hwc : Set bw limit on mdss when camera is on.

-Expose qservice API to get notified when Camera is on or off.
-Set bandwidth hint to mdss based on camera launch status by
  writing into fb0/mdp/bw_mode_bitmap.
-Implement camera service death notifier to recover display bw.

Change-Id: I532f44281b5d7de1d638f1cef250114a3cc952ae
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index f18ad36..5a1b047 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -40,6 +40,8 @@
 #include <hwc_qdcm.h>
 
 #define QCLIENT_DEBUG 0
+#define FILE_MAX_MDSSBW_FLAG \
+    "/sys/devices/virtual/graphics/fb0/mdp/bw_mode_bitmap"
 
 using namespace android;
 using namespace qService;
@@ -52,7 +54,8 @@
 
 // ----------------------------------------------------------------------------
 QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
-        mMPDeathNotifier(new MPDeathNotifier(ctx))
+        mMPDeathNotifier(new MPDeathNotifier(ctx)),
+        mCamDeathNotifier(new CamDeathNotifier())
 {
     ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
 }
@@ -481,6 +484,84 @@
     return NO_ERROR;
 }
 
+/*  register/unregister camera service */
+static bool  setCameraDeathNotifier(
+        android::sp<QClient::CamDeathNotifier> camDeathNotifier, bool on) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.camera"));
+    if (binder == 0) {
+        ALOGW("%s: CameraService not published or dead...", __FUNCTION__);
+        return false;
+    }
+    if(on) {
+        binder->linkToDeath(camDeathNotifier);
+    } else {
+        binder->unlinkToDeath(camDeathNotifier);
+    }
+    return true;
+}
+
+static bool updateDisplayBWCapForCam(bool on) {
+    char sysfsPath[255];
+    char bw[64];
+    int bw_flag = 0; // to reset to default.
+
+    memset(sysfsPath, 0, sizeof(sysfsPath));
+    snprintf(sysfsPath , sizeof(sysfsPath), FILE_MAX_MDSSBW_FLAG);
+    int sysfsFd = open(sysfsPath, O_RDWR);
+    if(sysfsFd < 0 ) {
+        ALOGE("%s: Status: %d Error in opening %s: %s",
+                __FUNCTION__, on, sysfsPath, strerror(errno));
+        return false;
+    }
+
+    if(on) {
+        bw_flag = MDSS_MAX_BW_LIMIT_CAMERA;
+    }
+    snprintf(bw, sizeof(bw), "%d", bw_flag);
+    ssize_t bytes = pwrite(sysfsFd, bw, strlen(bw), 0);
+    if(bytes < 0) {
+        ALOGE ("%s: Unable to write into %s node %s",
+                __FUNCTION__, sysfsPath, strerror(errno));
+        close(sysfsFd);
+        return false;
+    }
+    close(sysfsFd);
+    return true;
+}
+
+static void setCameraStatus(hwc_context_t* ctx,
+        android::sp<QClient::CamDeathNotifier> camDeathNotifier, uint32_t on) {
+
+    //Currently we need this only for 8952.
+    if(!MDPVersion::getInstance().is8x52()) {
+        ALOGI("%s  Not 8952?? return", __FUNCTION__);
+        return;
+    }
+
+    if(!setCameraDeathNotifier(camDeathNotifier, on)) {
+        ALOGE("%s  failed in updateCameraStatus", __FUNCTION__);
+        return;
+    }
+
+    if(!updateDisplayBWCapForCam(on)) {
+        ALOGE("%s  failed in updateDisplayBWCap", __FUNCTION__);
+        return;
+    }
+
+    // Trigger a screen update so that our BW setting will reflect
+    // atleast by next vsync.
+    screenRefresh(ctx);
+}
+
+void QClient::CamDeathNotifier::binderDied(const wp<IBinder>& who) {
+    //If Cameraservice abruptly gone, reset mdss bw caps
+    //This new cap will be applicable from next frame onwards
+    if(!updateDisplayBWCapForCam(false)) {
+        ALOGE("%s  failed in updateDisplayBWCap", __FUNCTION__);
+    }
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -559,6 +640,10 @@
         case IQService::QDCM_SVC_CMDS:
             qdcmCmdsHandler(mHwcContext, inParcel, outParcel);
             break;
+        case IQService::SET_CAMERA_STATUS:
+            setCameraStatus(mHwcContext,
+                    mCamDeathNotifier, inParcel->readInt32());
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index d955377..c1371f5 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -33,6 +33,7 @@
 #include <utils/Errors.h>
 #include <sys/types.h>
 #include <cutils/log.h>
+#include <utils/RefBase.h>
 #include <binder/IServiceManager.h>
 #include <media/IMediaDeathNotifier.h>
 #include <IQClient.h>
@@ -51,6 +52,13 @@
             const android::Parcel* inParcel,
             android::Parcel* outParcel);
 
+    //Notifies camera service death
+    class CamDeathNotifier : public IBinder::DeathRecipient {
+    public:
+        CamDeathNotifier(){}
+        virtual void binderDied(const android::wp<IBinder>& who);
+    };
+
 private:
     //Notifies of Media Player death
     class MPDeathNotifier : public android::IMediaDeathNotifier {
@@ -62,6 +70,7 @@
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
+    const android::sp<QClient::CamDeathNotifier>  mCamDeathNotifier;
 };
 }; // namespace qClient
 #endif // ANDROID_QCLIENT_H
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 5054578..0f69d40 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -69,6 +69,7 @@
         GET_CONFIG_COUNT = 27, //Get the number of supported display configs
         GET_DISPLAY_ATTRIBUTES_FOR_CONFIG = 28, //Get attr for specified config
         SET_DISPLAY_MODE = 29, // Set display mode to command or video mode
+        SET_CAMERA_STATUS = 30, // To notify display when camera is on and off
         COMMAND_LIST_END = 400,
     };
 
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
index 71277e8..62ee0d1 100644
--- a/libqservice/QServiceUtils.h
+++ b/libqservice/QServiceUtils.h
@@ -91,4 +91,8 @@
     return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable);
 }
 
+inline android::status_t setCameraLaunchStatus(uint32_t on) {
+    return sendSingleParam(qService::IQService::SET_CAMERA_STATUS, on);
+}
+
 #endif /* end of include guard: QSERVICEUTILS_H */