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;
     }