Camera2: Move frame processing to its own thread.

To avoid blocking the HAL on possibly long-running binder calls,
move frame receiption and processing to its own thread.

Bug: 6243944
Change-Id: I6385be4410b2f68e2331755027afc10c342187cf
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index c06f6ba..21a0547 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -61,6 +61,7 @@
         mRecordingHeapCount(kDefaultRecordingHeapCount)
 {
     ATRACE_CALL();
+    ALOGV("%s: Created client for camera %d", __FUNCTION__, cameraId);
 
     mDevice = new Camera2Device(cameraId);
 
@@ -80,9 +81,14 @@
 status_t Camera2Client::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
+    ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
+    mFrameProcessor = new FrameProcessor(this);
+    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
+            mCameraId);
+    mFrameProcessor->run(frameThreadName.string());
+
     res = mDevice->initialize(module);
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -91,7 +97,6 @@
     }
 
     res = mDevice->setNotifyCallback(this);
-    res = mDevice->setFrameListener(this);
 
     res = buildDeviceInfo();
     res = buildDefaultParameters();
@@ -113,13 +118,16 @@
 
 Camera2Client::~Camera2Client() {
     ATRACE_CALL();
-    ALOGV("%s: Camera %d: Shutting down", __FUNCTION__, mCameraId);
+    ALOGV("%s: Camera %d: Shutting down client.", __FUNCTION__, mCameraId);
 
     mDestructionStarted = true;
 
     // Rewrite mClientPid to allow shutdown by CameraService
     mClientPid = getCallingPid();
     disconnect();
+
+    mFrameProcessor->requestExit();
+    ALOGV("%s: Camera %d: Shutdown complete", __FUNCTION__, mCameraId);
 }
 
 status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
@@ -315,6 +323,8 @@
         write(fd, result.string(), result.size());
     }
 
+    mFrameProcessor->dump(fd, args);
+
     result = "  Device dump:\n";
     write(fd, result.string(), result.size());
 
@@ -1986,36 +1996,76 @@
             __FUNCTION__, newState, triggerId);
 }
 
-void Camera2Client::onNewFrameAvailable() {
+Camera2Client::FrameProcessor::FrameProcessor(wp<Camera2Client> client):
+        Thread(false), mClient(client) {
+}
+
+Camera2Client::FrameProcessor::~FrameProcessor() {
+    ALOGV("%s: Exit", __FUNCTION__);
+}
+
+void Camera2Client::FrameProcessor::dump(int fd, const Vector<String16>& args) {
+    String8 result("    Latest received frame:\n");
+    write(fd, result.string(), result.size());
+    mLastFrame.dump(fd, 2, 6);
+}
+
+bool Camera2Client::FrameProcessor::threadLoop() {
+    status_t res;
+
+    sp<Camera2Device> device;
+    {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        device = client->mDevice;
+    }
+
+    res = device->waitForNextFrame(kWaitDuration);
+    if (res == OK) {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        processNewFrames(client);
+    } else if (res != TIMED_OUT) {
+        ALOGE("Camera2Client::FrameProcessor: Error waiting for new "
+                "frames: %s (%d)", strerror(-res), res);
+    }
+
+    return true;
+}
+
+void Camera2Client::FrameProcessor::processNewFrames(sp<Camera2Client> &client) {
     status_t res;
     CameraMetadata frame;
-    while ( (res = mDevice->getNextFrame(&frame)) == OK) {
+    while ( (res = client->mDevice->getNextFrame(&frame)) == OK) {
         camera_metadata_entry_t entry;
         entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
         if (entry.count == 0) {
             ALOGE("%s: Camera %d: Error reading frame number: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
+                    __FUNCTION__, client->mCameraId, strerror(-res), res);
             break;
         }
 
-        res = processFrameFaceDetect(frame);
+        res = processFaceDetect(frame, client);
         if (res != OK) break;
+
+        mLastFrame.acquire(frame);
     }
     if (res != NOT_ENOUGH_DATA) {
         ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
-                __FUNCTION__, mCameraId, strerror(-res), res);
+                __FUNCTION__, client->mCameraId, strerror(-res), res);
         return;
     }
 
     return;
 }
 
-status_t Camera2Client::processFrameFaceDetect(const CameraMetadata &frame) {
+status_t Camera2Client::FrameProcessor::processFaceDetect(
+    const CameraMetadata &frame, sp<Camera2Client> &client) {
     status_t res;
     camera_metadata_ro_entry_t entry;
     bool enableFaceDetect;
     {
-        LockedParameters::Key k(mParameters);
+        LockedParameters::Key k(client->mParameters);
         enableFaceDetect = k.mParameters.enableFaceDetect;
     }
     entry = frame.find(ANDROID_STATS_FACE_DETECT_MODE);
@@ -2031,16 +2081,16 @@
         entry = frame.find(ANDROID_STATS_FACE_RECTANGLES);
         if (entry.count == 0) {
             ALOGE("%s: Camera %d: Unable to read face rectangles",
-                    __FUNCTION__, mCameraId);
+                    __FUNCTION__, client->mCameraId);
             return res;
         }
         camera_frame_metadata metadata;
         metadata.number_of_faces = entry.count / 4;
         if (metadata.number_of_faces >
-                mDeviceInfo->maxFaces) {
+                client->mDeviceInfo->maxFaces) {
             ALOGE("%s: Camera %d: More faces than expected! (Got %d, max %d)",
-                    __FUNCTION__, mCameraId,
-                    metadata.number_of_faces, mDeviceInfo->maxFaces);
+                    __FUNCTION__, client->mCameraId,
+                    metadata.number_of_faces, client->mDeviceInfo->maxFaces);
             return res;
         }
         const int32_t *faceRects = entry.data.i32;
@@ -2048,7 +2098,7 @@
         entry = frame.find(ANDROID_STATS_FACE_SCORES);
         if (entry.count == 0) {
             ALOGE("%s: Camera %d: Unable to read face scores",
-                    __FUNCTION__, mCameraId);
+                    __FUNCTION__, client->mCameraId);
             return res;
         }
         const uint8_t *faceScores = entry.data.u8;
@@ -2060,7 +2110,7 @@
             entry = frame.find(ANDROID_STATS_FACE_LANDMARKS);
             if (entry.count == 0) {
                 ALOGE("%s: Camera %d: Unable to read face landmarks",
-                        __FUNCTION__, mCameraId);
+                        __FUNCTION__, client->mCameraId);
                 return res;
             }
             faceLandmarks = entry.data.i32;
@@ -2069,7 +2119,7 @@
 
             if (entry.count == 0) {
                 ALOGE("%s: Camera %d: Unable to read face IDs",
-                        __FUNCTION__, mCameraId);
+                        __FUNCTION__, client->mCameraId);
                 return res;
             }
             faceIds = entry.data.i32;
@@ -2081,20 +2131,26 @@
         for (int i = 0; i < metadata.number_of_faces; i++) {
             camera_face_t face;
 
-            face.rect[0] = arrayXToNormalized(faceRects[i*4 + 0]);
-            face.rect[1] = arrayYToNormalized(faceRects[i*4 + 1]);
-            face.rect[2] = arrayXToNormalized(faceRects[i*4 + 2]);
-            face.rect[3] = arrayYToNormalized(faceRects[i*4 + 3]);
+            face.rect[0] = client->arrayXToNormalized(faceRects[i*4 + 0]);
+            face.rect[1] = client->arrayYToNormalized(faceRects[i*4 + 1]);
+            face.rect[2] = client->arrayXToNormalized(faceRects[i*4 + 2]);
+            face.rect[3] = client->arrayYToNormalized(faceRects[i*4 + 3]);
 
             face.score = faceScores[i];
             if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
                 face.id = faceIds[i];
-                face.left_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 0]);
-                face.left_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 1]);
-                face.right_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 2]);
-                face.right_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 3]);
-                face.mouth[0] = arrayXToNormalized(faceLandmarks[i*6 + 4]);
-                face.mouth[1] = arrayYToNormalized(faceLandmarks[i*6 + 5]);
+                face.left_eye[0] =
+                        client->arrayXToNormalized(faceLandmarks[i*6 + 0]);
+                face.left_eye[1] =
+                        client->arrayYToNormalized(faceLandmarks[i*6 + 1]);
+                face.right_eye[0] =
+                        client->arrayXToNormalized(faceLandmarks[i*6 + 2]);
+                face.right_eye[1] =
+                        client->arrayYToNormalized(faceLandmarks[i*6 + 3]);
+                face.mouth[0] =
+                        client->arrayXToNormalized(faceLandmarks[i*6 + 4]);
+                face.mouth[1] =
+                        client->arrayYToNormalized(faceLandmarks[i*6 + 5]);
             } else {
                 face.id = 0;
                 face.left_eye[0] = face.left_eye[1] = -2000;
@@ -2106,9 +2162,9 @@
 
         metadata.faces = faces.editArray();
         {
-            Mutex::Autolock iccl(mICameraClientLock);
-            if (mCameraClient != NULL) {
-                mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
+            Mutex::Autolock iccl(client->mICameraClientLock);
+            if (client->mCameraClient != NULL) {
+                client->mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
                         NULL, &metadata);
             }
         }