Prevent camera deadlocks when taking pictures

The camera in the emulator would sometimes end up in a deadlock when
taking pictuers. This happened because the request to take a picture
could be blocked on waiting for the frame delivery thread to end. But
the frame delivery thread was waiting to acquire a lock in the image
delivery callback, a lock that was held by the take picture call in the
camera client. This change changes the synchronous take picture call
into an asynchronous request. The take picture functionality is moved to
the same thread that delivers frames which ensures that all callbacks to
the camera client happen from the same thread.

BUG: 31599348
Test: ran camera CTS tests
Change-Id: Ib8d3a6c04e7e9bf7f297e1aafcd73d7f2e629132
(cherry picked from commit 31466a4d2304d5097e70d6437c7bd7c8b08d961b)
diff --git a/camera/EmulatedCamera.cpp b/camera/EmulatedCamera.cpp
index 474a2b6..dd055e1 100755
--- a/camera/EmulatedCamera.cpp
+++ b/camera/EmulatedCamera.cpp
@@ -234,6 +234,9 @@
     mCallbackNotifier.onCameraDeviceError(err);
 }
 
+void EmulatedCamera::setTakingPicture(bool takingPicture) {
+    mCallbackNotifier.setTakingPicture(takingPicture);
+}
 /****************************************************************************
  * Camera API implementation.
  ***************************************************************************/
@@ -445,47 +448,40 @@
      * picture.
      */
 
-    const bool preview_on = mPreviewWindow.isPreviewEnabled();
-    if (preview_on) {
-        doStopPreview();
-    }
-
-    /* Camera device should have been stopped when the shutter message has been
-     * enabled. */
     EmulatedCameraDevice* const camera_dev = getCameraDevice();
-    if (camera_dev->isStarted()) {
-        ALOGW("%s: Camera device is started", __FUNCTION__);
-        camera_dev->stopDeliveringFrames();
-        camera_dev->stopDevice();
-    }
+    mCallbackNotifier.setJpegQuality(jpeg_quality);
+    mCallbackNotifier.setCameraParameters(mParameters);
 
-    /*
-     * Take the picture now.
-     */
-
-    /* Start camera device for the picture frame. */
     ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
-         reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
-    res = camera_dev->startDevice(width, height, org_fmt);
-    if (res != NO_ERROR) {
-        if (preview_on) {
-            doStartPreview();
+          reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
+    if (mPreviewWindow.isPreviewEnabled()) {
+        mPreviewWindow.stopPreview();
+        /* If the camera preview is enabled we need to perform an asynchronous
+         * restart. A blocking restart could deadlock this thread as it's
+         * currently holding the camera client lock and the frame delivery could
+         * be stuck on waiting for that lock. If this was synchronous then this
+         * thread would in turn get stuck on waiting for the delivery thread. */
+        if (!camera_dev->requestRestart(width, height, org_fmt,
+                                        true /* takingPicture */,
+                                        true /* oneBurst */)) {
+            return UNKNOWN_ERROR;
+        }
+        return NO_ERROR;
+    } else {
+        /* Start camera device for the picture frame. */
+        res = camera_dev->startDevice(width, height, org_fmt);
+        if (res != NO_ERROR) {
+            return res;
+        }
+
+        /* Deliver one frame only. */
+        mCallbackNotifier.setTakingPicture(true);
+        res = camera_dev->startDeliveringFrames(true);
+        if (res != NO_ERROR) {
+            mCallbackNotifier.setTakingPicture(false);
         }
         return res;
     }
-
-    /* Deliver one frame only. */
-    mCallbackNotifier.setJpegQuality(jpeg_quality);
-    mCallbackNotifier.setCameraParameters(mParameters);
-    mCallbackNotifier.setTakingPicture(true);
-    res = camera_dev->startDeliveringFrames(true);
-    if (res != NO_ERROR) {
-        mCallbackNotifier.setTakingPicture(false);
-        if (preview_on) {
-            doStartPreview();
-        }
-    }
-    return res;
 }
 
 status_t EmulatedCamera::cancelPicture()
diff --git a/camera/EmulatedCamera.h b/camera/EmulatedCamera.h
index 4c215ed..8b1b47d 100755
--- a/camera/EmulatedCamera.h
+++ b/camera/EmulatedCamera.h
@@ -95,6 +95,9 @@
      */
     virtual void onCameraDeviceError(int err);
 
+    /* Signal to the callback notifier that a pictuer is being taken. */
+    void setTakingPicture(bool takingPicture);
+
     /****************************************************************************
      * Camera API implementation
      ***************************************************************************/
diff --git a/camera/EmulatedCameraDevice.cpp b/camera/EmulatedCameraDevice.cpp
index 352716d..bda3223 100755
--- a/camera/EmulatedCameraDevice.cpp
+++ b/camera/EmulatedCameraDevice.cpp
@@ -87,8 +87,8 @@
     }
 
     /* Frames will be delivered from the thread routine. */
-    const status_t res = startWorkerThreads(one_burst);
-    ALOGE_IF(res != NO_ERROR, "%s: startWorkerThreads failed", __FUNCTION__);
+    const status_t res = startWorkerThread(one_burst);
+    ALOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
     return res;
 }
 
@@ -101,8 +101,8 @@
         return NO_ERROR;
     }
 
-    const status_t res = stopWorkerThreads();
-    ALOGE_IF(res != NO_ERROR, "%s: stopWorkerThreads failed", __FUNCTION__);
+    const status_t res = stopWorkerThread();
+    ALOGE_IF(res != NO_ERROR, "%s: stopWorkerThread failed", __FUNCTION__);
     return res;
 }
 
@@ -182,7 +182,7 @@
     }
 
     FrameLock lock(*this);
-    const void* source = mFrameProducer->getPrimaryBuffer();
+    const void* source = mCameraThread->getPrimaryBuffer();
     if (source == nullptr) {
         ALOGE("%s: No framebuffer", __FUNCTION__);
         return EINVAL;
@@ -203,7 +203,7 @@
     }
 
     FrameLock lock(*this);
-    const void* currentFrame = mFrameProducer->getPrimaryBuffer();
+    const void* currentFrame = mCameraThread->getPrimaryBuffer();
     if (currentFrame == nullptr) {
         ALOGE("%s: No framebuffer", __FUNCTION__);
         return EINVAL;
@@ -232,8 +232,8 @@
 }
 
 const void* EmulatedCameraDevice::getCurrentFrame() {
-    if (mFrameProducer.get()) {
-        return mFrameProducer->getPrimaryBuffer();
+    if (mCameraThread.get()) {
+        return mCameraThread->getPrimaryBuffer();
     }
     return nullptr;
 }
@@ -257,6 +257,19 @@
     return NO_ERROR;
 }
 
+bool EmulatedCameraDevice::requestRestart(int width, int height,
+                                          uint32_t pixelFormat,
+                                          bool takingPicture, bool oneBurst) {
+    if (mCameraThread.get() == nullptr) {
+        ALOGE("%s: No thread alive to perform the restart, is preview on?",
+              __FUNCTION__);
+        return false;
+    }
+    mCameraThread->requestRestart(width, height, pixelFormat,
+                                  takingPicture, oneBurst);
+    return true;
+}
+
 /****************************************************************************
  * Emulated camera device private API
  ***************************************************************************/
@@ -324,7 +337,7 @@
  * Worker thread management.
  ***************************************************************************/
 
-status_t EmulatedCameraDevice::startWorkerThreads(bool one_burst)
+status_t EmulatedCameraDevice::startWorkerThread(bool one_burst)
 {
     ALOGV("%s", __FUNCTION__);
 
@@ -333,46 +346,22 @@
         return EINVAL;
     }
 
-    // First create and start a frame producer, without a producer there are no
-    // frames to deliver and the deliverer will not deliver frames until one has
-    // been produced.
-    void* primaryBuffer = getPrimaryBuffer();
-    void* secondaryBuffer = getSecondaryBuffer();
-    mFrameProducer = new FrameProducer(this, mObjectLock,
-                                       staticProduceFrame, this,
-                                       primaryBuffer, secondaryBuffer);
-    if (mFrameProducer == NULL) {
-        ALOGE("%s: Unable to instantiate FrameProducer object", __FUNCTION__);
+    mCameraThread = new CameraThread(this, staticProduceFrame, this);
+    if (mCameraThread == NULL) {
+        ALOGE("%s: Unable to instantiate CameraThread object", __FUNCTION__);
         return ENOMEM;
     }
-    status_t res = mFrameProducer->startThread(one_burst);
+    status_t res = mCameraThread->startThread(one_burst);
     if (res != NO_ERROR) {
-        ALOGE("%s: Unable to start frame producer thread: %s",
+        ALOGE("%s: Unable to start CameraThread: %s",
               __FUNCTION__, strerror(res));
         return res;
     }
 
-    // Then create a frame deliverer, this takes the producer as a reference to
-    // be able to check if a frame has been produced yet.
-    mFrameDeliverer = new FrameDeliverer(this, mObjectLock,
-                                         mFrameProducer.get());
-    if (mFrameDeliverer == NULL) {
-        ALOGE("%s: Unable to instantiate FrameDeliverer object", __FUNCTION__);
-        mFrameProducer->stopThread();
-        return ENOMEM;
-    }
-    res = mFrameDeliverer->startThread(one_burst);
-    if (res != NO_ERROR) {
-        ALOGE("%s: Unable to start frame deliverer: %s",
-              __FUNCTION__, strerror(res));
-        mFrameProducer->stopThread();
-        return res;
-    }
-
     return res;
 }
 
-status_t EmulatedCameraDevice::stopWorkerThreads()
+status_t EmulatedCameraDevice::stopWorkerThread()
 {
     ALOGV("%s", __FUNCTION__);
 
@@ -381,48 +370,65 @@
         return EINVAL;
     }
 
-    // Since the deliverer holds a reference to the producer make sure we shut
-    // down the deliverer first so that it won't use an invalid reference.
-    status_t res = mFrameDeliverer->stopThread();
-    ALOGE_IF(res != NO_ERROR, "%s: Unable to stop FrameDeliverer", __FUNCTION__);
+    status_t res = mCameraThread->stopThread();
+    if (res != NO_ERROR) {
+        ALOGE("%s: Unable to stop CameraThread", __FUNCTION__);
+        return res;
+    }
+    res = mCameraThread->joinThread();
+    if (res != NO_ERROR) {
+        ALOGE("%s: Unable to join CameraThread", __FUNCTION__);
+        return res;
+    }
 
-    res = mFrameProducer->stopThread();
-    ALOGE_IF(res != NO_ERROR, "%s: Unable to stop FrameProducer", __FUNCTION__);
-
-    // Destroy the threads as well
-    mFrameDeliverer.clear();
-    mFrameProducer.clear();
+    // Destroy the thread as well
+    mCameraThread.clear();
     return res;
 }
 
-EmulatedCameraDevice::FrameDeliverer::FrameDeliverer(EmulatedCameraDevice* dev,
-                                                     Mutex& cameraMutex,
-                                                     FrameProducer* producer)
-    : WorkerThread("Camera_FrameDeliverer", dev, cameraMutex),
+EmulatedCameraDevice::CameraThread::CameraThread(EmulatedCameraDevice* dev,
+                                                 ProduceFrameFunc producer,
+                                                 void* producerOpaque)
+    : WorkerThread("Camera_CameraThread", dev, dev->mCameraHAL),
       mCurFrameTimestamp(0),
-      mFrameProducer(producer) {
+      mProducerFunc(producer),
+      mProducerOpaque(producerOpaque),
+      mRestartWidth(0),
+      mRestartHeight(0),
+      mRestartPixelFormat(0),
+      mRestartOneBurst(false),
+      mRestartTakingPicture(false),
+      mRestartRequested(false) {
 
 }
 
-bool EmulatedCameraDevice::FrameDeliverer::inWorkerThread() {
-    /* Wait till FPS timeout expires, or thread exit message is received. */
-    nsecs_t wakeAt =
-        mCurFrameTimestamp + 1000000000.0 / mCameraDevice->mFramesPerSecond;
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    nsecs_t timeout = std::max<nsecs_t>(0, wakeAt - now);
+const void* EmulatedCameraDevice::CameraThread::getPrimaryBuffer() const {
+    if (mFrameProducer.get()) {
+        return mFrameProducer->getPrimaryBuffer();
+    }
+    return nullptr;
+}
 
+void EmulatedCameraDevice::CameraThread::lockPrimaryBuffer() {
+    mFrameProducer->lockPrimaryBuffer();
+}
+
+void EmulatedCameraDevice::CameraThread::unlockPrimaryBuffer() {
+    mFrameProducer->unlockPrimaryBuffer();
+}
+
+bool
+EmulatedCameraDevice::CameraThread::waitForFrameOrTimeout(nsecs_t timeout) {
     // Keep waiting until the frame producer indicates that a frame is available
     // This does introduce some unnecessary latency to the first frame delivery
     // but avoids a lot of thread synchronization.
     do {
         // We don't have any specific fd we want to select so we pass in -1
         // timeout is in nanoseconds but Select expects microseconds
-        SelectRes res = Select(-1, timeout / 1000);
-        if (res == EXIT_THREAD) {
-            ALOGV("%s: FrameDeliverer thread has been terminated.",
-                  __FUNCTION__);
-            // Reset this to true, the next time the thread is started it will
-            // be considred as the first loop
+        Mutex::Autolock lock(mRunningMutex);
+        mRunningCondition.waitRelative(mRunningMutex, timeout);
+        if (!mRunning) {
+            ALOGV("%s: CameraThread has been terminated.", __FUNCTION__);
             return false;
         }
         // Set a short timeout in case there is no frame available and we are
@@ -430,23 +436,63 @@
         timeout = milliseconds(5);
     } while (!mFrameProducer->hasFrame());
 
+    return true;
+}
+
+bool EmulatedCameraDevice::CameraThread::inWorkerThread() {
+    /* Wait till FPS timeout expires, or thread exit message is received. */
+    nsecs_t wakeAt =
+        mCurFrameTimestamp + 1000000000.0 / mCameraDevice->mFramesPerSecond;
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t timeout = std::max<nsecs_t>(0, wakeAt - now);
+
+    if (!waitForFrameOrTimeout(timeout)) {
+        return false;
+    }
+
+    /* Check if a restart and potentially apply the requested changes */
+    if (!checkRestartRequest()) {
+        return false;
+    }
+
     /* Check if an auto-focus event needs to be triggered */
     mCameraDevice->checkAutoFocusTrigger();
 
     mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    mCameraDevice->mCameraHAL->onNextFrameAvailable(mCurFrameTimestamp,
-                                                    mCameraDevice);
+    mCameraHAL->onNextFrameAvailable(mCurFrameTimestamp, mCameraDevice);
 
     return true;
 }
 
-EmulatedCameraDevice::FrameProducer::FrameProducer(EmulatedCameraDevice* dev,
-                                                   Mutex& cameraMutex,
-                                                   ProduceFrameFunc producer,
-                                                   void* opaque,
-                                                   void* primaryBuffer,
-                                                   void* secondaryBuffer)
-    : WorkerThread("Camera_FrameProducer", dev, cameraMutex),
+status_t EmulatedCameraDevice::CameraThread::onThreadStart() {
+    void* primaryBuffer = mCameraDevice->getPrimaryBuffer();
+    void* secondaryBuffer = mCameraDevice->getSecondaryBuffer();
+    mFrameProducer = new FrameProducer(mCameraDevice,
+                                       mProducerFunc, mProducerOpaque,
+                                       primaryBuffer, secondaryBuffer);
+    if (mFrameProducer.get() == nullptr) {
+        ALOGE("%s: Could not instantiate FrameProducer object", __FUNCTION__);
+        return ENOMEM;
+    }
+    return mFrameProducer->startThread(mOneBurst);
+}
+
+void EmulatedCameraDevice::CameraThread::onThreadExit() {
+    if (mFrameProducer.get()) {
+        if (mFrameProducer->stopThread() == NO_ERROR) {
+            mFrameProducer->joinThread();
+            mFrameProducer.clear();
+        }
+    }
+}
+
+EmulatedCameraDevice::CameraThread::FrameProducer::FrameProducer(
+        EmulatedCameraDevice* dev,
+        ProduceFrameFunc producer,
+        void* opaque,
+        void* primaryBuffer,
+        void* secondaryBuffer)
+    : WorkerThread("Camera_FrameProducer", dev, dev->mCameraHAL),
       mProducer(producer),
       mOpaque(opaque),
       mPrimaryBuffer(primaryBuffer),
@@ -456,37 +502,105 @@
 
 }
 
-const void* EmulatedCameraDevice::FrameProducer::getPrimaryBuffer() const {
+const void*
+EmulatedCameraDevice::CameraThread::FrameProducer::getPrimaryBuffer() const {
     return mPrimaryBuffer;
 }
 
-void EmulatedCameraDevice::FrameProducer::lockPrimaryBuffer() {
+void EmulatedCameraDevice::CameraThread::FrameProducer::lockPrimaryBuffer() {
     mBufferMutex.lock();
 }
-void EmulatedCameraDevice::FrameProducer::unlockPrimaryBuffer() {
+void EmulatedCameraDevice::CameraThread::FrameProducer::unlockPrimaryBuffer() {
     mBufferMutex.unlock();
 }
 
-bool EmulatedCameraDevice::FrameProducer::hasFrame() const {
+void EmulatedCameraDevice::CameraThread::requestRestart(int width,
+                                                        int height,
+                                                        uint32_t pixelFormat,
+                                                        bool takingPicture,
+                                                        bool oneBurst) {
+    Mutex::Autolock lock(mRequestMutex);
+    mRestartWidth = width;
+    mRestartHeight = height;
+    mRestartPixelFormat = pixelFormat;
+    mRestartTakingPicture = takingPicture;
+    mRestartOneBurst = oneBurst;
+    mRestartRequested = true;
+}
+
+bool EmulatedCameraDevice::CameraThread::FrameProducer::hasFrame() const {
     return mHasFrame;
 }
 
-bool EmulatedCameraDevice::FrameProducer::inWorkerThread() {
+bool EmulatedCameraDevice::CameraThread::checkRestartRequest() {
+    Mutex::Autolock lock(mRequestMutex);
+    if (mRestartRequested) {
+        mRestartRequested = false;
+        status_t res = mFrameProducer->stopThread();
+        if (res != NO_ERROR) {
+            ALOGE("%s: Could not stop frame producer thread", __FUNCTION__);
+            mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+            return false;
+        }
+        res = mFrameProducer->joinThread();
+        if (res != NO_ERROR) {
+            ALOGE("%s: Could not join frame producer thread", __FUNCTION__);
+            mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+            return false;
+        }
+        mFrameProducer.clear();
+        res = mCameraDevice->stopDevice();
+        if (res != NO_ERROR) {
+            ALOGE("%s: Could not stop device", __FUNCTION__);
+            mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+            return false;
+        }
+        res = mCameraDevice->startDevice(mRestartWidth,
+                                         mRestartHeight,
+                                         mRestartPixelFormat);
+        if (res != NO_ERROR) {
+            ALOGE("%s: Could not start device", __FUNCTION__);
+            mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+            return false;
+        }
+        if (mRestartTakingPicture) {
+            mCameraHAL->setTakingPicture(true);
+        }
+        mOneBurst = mRestartOneBurst;
+
+        // Pretend like this a thread start, performs the remaining setup
+        if (onThreadStart() != NO_ERROR) {
+            mCameraDevice->stopDevice();
+            mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+            return false;
+        }
+
+        // Now wait for the frame producer to start producing before we proceed
+        return waitForFrameOrTimeout(0);
+    }
+    return true;
+}
+
+bool EmulatedCameraDevice::CameraThread::FrameProducer::inWorkerThread() {
     nsecs_t nextFrame =
         mLastFrame + 1000000000 / mCameraDevice->mFramesPerSecond;
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     nsecs_t timeout = std::max<nsecs_t>(0, nextFrame - now);
 
-    SelectRes res = Select(-1, timeout / 1000);
-    if (res == EXIT_THREAD) {
-        ALOGV("%s: FrameProducer thread has been terminated.", __FUNCTION__);
-        return false;
+    {
+        Mutex::Autolock lock(mRunningMutex);
+        mRunningCondition.waitRelative(mRunningMutex, timeout);
+        if (!mRunning) {
+            ALOGV("%s: FrameProducer has been terminated.", __FUNCTION__);
+            return false;
+        }
     }
 
     // Produce one frame and place it in the secondary buffer
     mLastFrame = systemTime(SYSTEM_TIME_MONOTONIC);
     if (!mProducer(mOpaque, mSecondaryBuffer)) {
         ALOGE("FrameProducer could not produce frame, exiting thread");
+        mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
         return false;
     }
 
@@ -500,15 +614,11 @@
 }
 
 void EmulatedCameraDevice::lockCurrentFrame() {
-    if (mFrameProducer.get()) {
-        mFrameProducer->lockPrimaryBuffer();
-    }
+    mCameraThread->lockPrimaryBuffer();
 }
 
 void EmulatedCameraDevice::unlockCurrentFrame() {
-    if (mFrameProducer.get()) {
-        mFrameProducer->unlockPrimaryBuffer();
-    }
+    mCameraThread->unlockPrimaryBuffer();
 }
 
 };  /* namespace android */
diff --git a/camera/EmulatedCameraDevice.h b/camera/EmulatedCameraDevice.h
index 2c3756e..ec2bdb3 100755
--- a/camera/EmulatedCameraDevice.h
+++ b/camera/EmulatedCameraDevice.h
@@ -329,6 +329,16 @@
      */
     virtual status_t cancelAutoFocus();
 
+    /* Request an asynchronous camera restart with new image parameters. The
+     * restart will be performed on the same thread that delivers frames,
+     * ensuring that all callbacks are done from the same thread.
+     * Return
+     *  false if the thread request cannot be honored because no thread is
+     *        running or some other error occured.
+     */
+    bool requestRestart(int width, int height, uint32_t pixelFormat,
+                        bool takingPicture, bool oneBurst);
+
     /****************************************************************************
      * Emulated camera device private API
      ***************************************************************************/
@@ -381,8 +391,8 @@
      ***************************************************************************/
 
 protected:
-    /* Starts the worker threads.
-     * Typically, worker threads are started from the startDeliveringFrames
+    /* Starts the worker thread.
+     * Typically, the worker thread is started from the startDeliveringFrames
      * method of this class.
      * Param:
      *  one_burst - Controls how many times thread loop should run. If this
@@ -393,16 +403,16 @@
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    virtual status_t startWorkerThreads(bool one_burst);
+    virtual status_t startWorkerThread(bool one_burst);
 
-    /* Stops the worker threads.
-     * Note that this method will always wait for the worker threads to
-     * terminate. Typically, worker threads are stopped from the
+    /* Stop the worker thread.
+     * Note that this method will always wait for the worker thread to
+     * terminate. Typically, the worker thread is stopped from the
      * stopDeliveringFrames method of this class.
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    virtual status_t stopWorkerThreads();
+    virtual status_t stopWorkerThread();
 
     /* Produce a camera frame and place it in buffer. The buffer is one of
      * the two buffers provided to mFrameProducer during construction along with
@@ -421,22 +431,16 @@
         return mFrameBuffers[1].data();
     }
 
-    /* A class with a thread that will call a function at a specified interval
-     * to produce frames. This is done in a double-buffered fashion to make sure
-     * that one of the frames can be delivered without risk of overwriting its
-     * contents. Access to the primary buffer, the one NOT being drawn to,
-     * should be protected with the lock methods provided or the guarantee of
-     * not overwriting the contents does not hold.
-     */
-    class FrameProducer : public WorkerThread {
+    /* A class that encaspulates the asynchronous behavior of a camera. This
+     * includes asynchronous production (through another thread), frame delivery
+     * as well as asynchronous state changes that have to be synchronized with
+     * frame production and delivery but can't be blocking the camera HAL. */
+    class CameraThread : public WorkerThread {
     public:
         typedef bool (*ProduceFrameFunc)(void* opaque, void* destinationBuffer);
-        FrameProducer(EmulatedCameraDevice* cameraDevice, Mutex& cameraMutex,
-                      ProduceFrameFunc producer, void* opaque,
-                      void* primaryBuffer, void* secondaryBuffer);
-
-        /* Indicates if the producer has produced at least one frame or not. */
-        bool hasFrame() const;
+        CameraThread(EmulatedCameraDevice* cameraDevice,
+                     ProduceFrameFunc producer,
+                     void* producerOpaque);
 
         /* Access the primary buffer of the frame producer, this is the frame
          * that is currently not being written to. The buffer will only have
@@ -449,32 +453,62 @@
         void lockPrimaryBuffer();
         void unlockPrimaryBuffer();
 
-    protected:
+        void requestRestart(int width, int height, uint32_t pixelFormat,
+                            bool takingPicture, bool oneBurst);
+
+    private:
+        bool checkRestartRequest();
+        bool waitForFrameOrTimeout(nsecs_t timeout);
         bool inWorkerThread() override;
 
-        ProduceFrameFunc mProducer;
-        void* mOpaque;
-        void* mPrimaryBuffer;
-        void* mSecondaryBuffer;
-        nsecs_t mLastFrame;
-        mutable Mutex mBufferMutex;
-        std::atomic<bool> mHasFrame;
-    };
+        status_t onThreadStart() override;
+        void onThreadExit() override;
 
-    /* A class encapsulating a thread that will deliver frame available
-     * notifications at a fixed interval. The first notification will NOT be
-     * delivered until the provided FrameProducer has produced at least one
-     * frame. The deliver takes place through the provided camera device. */
-    class FrameDeliverer : public WorkerThread {
-    public:
-        FrameDeliverer(EmulatedCameraDevice* cameraDevice,
-                       Mutex& cameraMutex,
-                       FrameProducer* frameProducer);
-    protected:
-        bool inWorkerThread() override;
+        /* A class with a thread that will call a function at a specified
+         * interval to produce frames. This is done in a double-buffered fashion
+         * to make sure that one of the frames can be delivered without risk of
+         * overwriting its contents. Access to the primary buffer, the one NOT
+         * being drawn to, should be protected with the lock methods provided or
+         * the guarantee of not overwriting the contents does not hold.
+         */
+        class FrameProducer : public WorkerThread {
+        public:
+            FrameProducer(EmulatedCameraDevice* cameraDevice,
+                          ProduceFrameFunc producer, void* opaque,
+                          void* primaryBuffer, void* secondaryBuffer);
+
+            /* Indicates if the producer has produced at least one frame. */
+            bool hasFrame() const;
+
+            const void* getPrimaryBuffer() const;
+
+            void lockPrimaryBuffer();
+            void unlockPrimaryBuffer();
+
+        protected:
+            bool inWorkerThread() override;
+
+            ProduceFrameFunc mProducer;
+            void* mOpaque;
+            void* mPrimaryBuffer;
+            void* mSecondaryBuffer;
+            nsecs_t mLastFrame;
+            mutable Mutex mBufferMutex;
+            std::atomic<bool> mHasFrame;
+        };
 
         nsecs_t mCurFrameTimestamp;
-        FrameProducer* mFrameProducer;
+        /* Worker thread that will produce frames for the camera thread */
+        sp<FrameProducer> mFrameProducer;
+        ProduceFrameFunc mProducerFunc;
+        void* mProducerOpaque;
+        Mutex mRequestMutex;
+        int mRestartWidth;
+        int mRestartHeight;
+        uint32_t mRestartPixelFormat;
+        bool mRestartOneBurst;
+        bool mRestartTakingPicture;
+        bool mRestartRequested;
     };
 
     /****************************************************************************
@@ -485,16 +519,14 @@
     /* Locks this instance for parameters, state, etc. change. */
     Mutex                       mObjectLock;
 
-    /* Worker thread that is used in frame delivery. The process of generating
-     * and delivering frames is split up into two threads. This way frames can
+    /* A camera thread that is used in frame production, delivery and handling
+     * of asynchronous restarts. Internally the process of generating and
+     * delivering frames is split up into two threads. This way frames can
      * always be delivered on time even if they cannot be produced fast enough
      * to keep up with the expected frame rate. It also increases performance on
      * multi-core systems. If the producer cannot keep up the last frame will
      * simply be delivered again. */
-    sp<FrameDeliverer>          mFrameDeliverer;
-
-    /* Worker thread that will produce frames for the frame deliverer */
-    sp<FrameProducer>           mFrameProducer;
+    sp<CameraThread>          mCameraThread;
 
     /* Emulated camera object containing this instance. */
     EmulatedCamera*             mCameraHAL;
diff --git a/camera/EmulatedQemuCameraDevice.cpp b/camera/EmulatedQemuCameraDevice.cpp
index df68999..20d9424 100755
--- a/camera/EmulatedQemuCameraDevice.cpp
+++ b/camera/EmulatedQemuCameraDevice.cpp
@@ -227,7 +227,7 @@
     }
 
     FrameLock lock(*this);
-    const void* primary = mFrameProducer->getPrimaryBuffer();
+    const void* primary = mCameraThread->getPrimaryBuffer();
     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
     uint8_t* frame = frameBufferPair->first;
 
@@ -250,7 +250,7 @@
     }
 
     FrameLock lock(*this);
-    const void* primary = mFrameProducer->getPrimaryBuffer();
+    const void* primary = mCameraThread->getPrimaryBuffer();
     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
     uint32_t* previewFrame = frameBufferPair->second;
 
@@ -263,11 +263,11 @@
 }
 
 const void* EmulatedQemuCameraDevice::getCurrentFrame() {
-    if (mFrameProducer.get() == nullptr) {
+    if (mCameraThread.get() == nullptr) {
         return nullptr;
     }
 
-    const void* primary = mFrameProducer->getPrimaryBuffer();
+    const void* primary = mCameraThread->getPrimaryBuffer();
     auto frameBufferPair = reinterpret_cast<const FrameBufferPair*>(primary);
     uint8_t* frame = frameBufferPair->first;
 
@@ -294,7 +294,6 @@
     if (query_res != NO_ERROR) {
         ALOGE("%s: Unable to get current video frame: %s",
              __FUNCTION__, strerror(query_res));
-        mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
         return false;
     }
     return true;
diff --git a/camera/WorkerThread.cpp b/camera/WorkerThread.cpp
index 4b73ff0..2b5fe92 100644
--- a/camera/WorkerThread.cpp
+++ b/camera/WorkerThread.cpp
@@ -25,196 +25,67 @@
 namespace android {
 
 WorkerThread::WorkerThread(const char* threadName,
-                           EmulatedCameraDevice* camera_dev,
-                           Mutex& cameraMutex)
+                           EmulatedCameraDevice* cameraDevice,
+                           EmulatedCamera* cameraHAL)
     : Thread(true),   // Callbacks may involve Java calls.
-      mCameraDevice(camera_dev),
-      mThreadName(threadName),
-      mThreadControl(-1),
-      mControlFD(-1),
-      mCameraMutex(cameraMutex) {
+      mCameraDevice(cameraDevice),
+      mCameraHAL(cameraHAL),
+      mRunning(false),
+      mThreadName(threadName) {
 }
 
-WorkerThread::~WorkerThread() {
-    ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
-            "%s: Control FDs are opened in the destructor",
-            __FUNCTION__);
-    if (mThreadControl >= 0) {
-        close(mThreadControl);
+status_t WorkerThread::startThread(bool oneBurst) {
+    ALOGV("Starting worker thread, oneBurst=%s", oneBurst ? "true" : "false");
+    mOneBurst = oneBurst;
+    {
+        Mutex::Autolock lock(mRunningMutex);
+        mRunning = true;
     }
-    if (mControlFD >= 0) {
-        close(mControlFD);
-    }
-}
-
-status_t WorkerThread::startThread(bool one_burst) {
-    ALOGV("Starting worker thread, one_burst=%s", one_burst ? "true" : "false");
-    mOneBurst = one_burst;
     return run(mThreadName, ANDROID_PRIORITY_URGENT_DISPLAY, 0);
 }
 
+status_t WorkerThread::stopThread() {
+    ALOGV("%s: Stopping worker thread...", __FUNCTION__);
+
+    Mutex::Autolock lock(mRunningMutex);
+    mRunning = false;
+    mRunningCondition.signal();
+    return NO_ERROR;
+}
+
+status_t WorkerThread::wakeThread() {
+    ALOGV("%s: Waking emulated camera device's worker thread...", __FUNCTION__);
+
+    mRunningCondition.signal();
+    return NO_ERROR;
+}
+
+status_t WorkerThread::joinThread() {
+    return join();
+}
+
 status_t WorkerThread::readyToRun()
 {
-    ALOGV("Starting emulated camera device worker thread...");
-
-    ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
-            "%s: Thread control FDs are opened", __FUNCTION__);
-    /* Create a pair of FDs that would be used to control the thread. */
-    int thread_fds[2];
-    status_t ret;
-    Mutex::Autolock lock(mCameraMutex);
-    if (pipe(thread_fds) == 0) {
-        mThreadControl = thread_fds[1];
-        mControlFD = thread_fds[0];
-        ALOGV("Emulated device's worker thread has been started.");
-        ret = NO_ERROR;
-    } else {
-        ALOGE("%s: Unable to create thread control FDs: %d -> %s",
-             __FUNCTION__, errno, strerror(errno));
-        ret = errno;
-    }
-
-    mSetup.broadcast();
-    return ret;
-}
-
-status_t WorkerThread::sendControlMessage(ControlMessage msg) {
-    status_t res = EINVAL;
-
-    // Limit the scope of the Autolock
-    {
-      // If thread is running and readyToRun() has not finished running,
-      //    then wait until it is done.
-      Mutex::Autolock lock(mCameraMutex);
-      ALOGV("%s: Acquired camera mutex lock", __FUNCTION__);
-      if (isRunning() && (mThreadControl < 0 || mControlFD < 0)) {
-          ALOGV("%s: Waiting for setup condition", __FUNCTION__);
-          mSetup.wait(mCameraMutex);
-      }
-    }
-    ALOGV("%s: Waited for setup complete", __FUNCTION__);
-
-    if (mThreadControl >= 0) {
-        /* Send "stop" message to the thread loop. */
-        const int wres =
-            TEMP_FAILURE_RETRY(write(mThreadControl, &msg, sizeof(msg)));
-        if (wres == sizeof(msg)) {
-            res = NO_ERROR;
-        } else {
-            res = errno ? errno : EINVAL;
-        }
-        ALOGV("%s: Sent control message, result: %d", __FUNCTION__, (int)res);
-        return res;
-    } else {
-        ALOGE("%s: Thread control FDs are not opened", __FUNCTION__);
-    }
-
-    return res;
-}
-
-status_t WorkerThread::stopThread() {
-    ALOGV("%s: Stopping worker thread...",
-          __FUNCTION__);
-
-    status_t res = sendControlMessage(THREAD_STOP);
-    if (res == NO_ERROR) {
-        /* Stop the thread, and wait till it's terminated. */
-        ALOGV("%s: Requesting exit and waiting", __FUNCTION__);
-        res = requestExitAndWait();
-        ALOGV("%s: requestExitAndWait returned", __FUNCTION__);
-        if (res == NO_ERROR) {
-            /* Close control FDs. */
-            if (mThreadControl >= 0) {
-                close(mThreadControl);
-                mThreadControl = -1;
-            }
-            if (mControlFD >= 0) {
-                close(mControlFD);
-                mControlFD = -1;
-            }
-            ALOGV("%s: Worker thread has been stopped.", __FUNCTION__);
-        } else {
-            ALOGE("%s: requestExitAndWait failed: %d -> %s",
-                 __FUNCTION__, res, strerror(-res));
-        }
-    } else {
-        ALOGE("%s: Unable to send THREAD_STOP message: %d -> %s",
-             __FUNCTION__, errno, strerror(errno));
-    }
-    return res;
-}
-
-status_t WorkerThread::wakeThread() {
-    ALOGV("%s: Waking emulated camera device's worker thread...",
-          __FUNCTION__);
-
-    status_t res = sendControlMessage(THREAD_WAKE);
+    status_t res = onThreadStart();
     if (res != NO_ERROR) {
-        ALOGE("%s: Unable to send THREAD_WAKE message: %d -> %s",
-             __FUNCTION__, errno, strerror(errno));
+        return res;
     }
-    return res;
-}
-
-WorkerThread::SelectRes WorkerThread::Select(int fd, int timeoutMicroSec)
-{
-    fd_set fds[1];
-    struct timeval tv, *tvp = NULL;
-
-    const int fd_num = std::max(fd, mControlFD) + 1;
-    FD_ZERO(fds);
-    FD_SET(mControlFD, fds);
-    if (fd >= 0) {
-        FD_SET(fd, fds);
-    }
-    if (timeoutMicroSec >= 0) {
-        tv.tv_sec = timeoutMicroSec / 1000000;
-        tv.tv_usec = timeoutMicroSec % 1000000;
-        tvp = &tv;
-    }
-    int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp));
-    if (res < 0) {
-        ALOGE("%s: select returned %d and failed: %d -> %s",
-             __FUNCTION__, res, errno, strerror(errno));
-        return ERROR;
-    } else if (res == 0) {
-        /* Timeout. */
-        return TIMEOUT;
-    } else if (FD_ISSET(mControlFD, fds)) {
-        /* A control event. Lets read the message. */
-        ControlMessage msg;
-        res = TEMP_FAILURE_RETRY(read(mControlFD, &msg, sizeof(msg)));
-        if (res != sizeof(msg)) {
-            ALOGE("%s: Unexpected message size %d, or an error %d -> %s",
-                 __FUNCTION__, res, errno, strerror(errno));
-            return ERROR;
-        }
-        if (msg == THREAD_STOP) {
-            ALOGV("%s: THREAD_STOP message is received", __FUNCTION__);
-            return EXIT_THREAD;
-        } else if (msg == THREAD_WAKE) {
-            ALOGV("%s: THREAD_WAKE message is received", __FUNCTION__);
-            return WAKE_THREAD;
-        } else {
-            ALOGE("Unknown worker thread message %d", msg);
-            return ERROR;
-        }
-    } else {
-        /* Must be an FD. */
-        ALOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result",
-                __FUNCTION__);
-        return READY;
-    }
+    return NO_ERROR;
 }
 
 bool WorkerThread::threadLoop() {
-    /* Simply dispatch the call to the containing camera device. */
-    if (inWorkerThread()) {
-        /* Respect "one burst" parameter (see startThread). */
-        return !mOneBurst;
-    } else {
-        return false;
+    if (inWorkerThread() && !mOneBurst) {
+        /* Only return true if we're running. If mRunning has been set to false
+         * we fall through to ensure that onThreadExit is called. */
+        Mutex::Autolock lock(mRunningMutex);
+        if (mRunning) {
+            return true;
+        }
     }
+    onThreadExit();
+    ALOGV("%s: Exiting thread, mOneBurst=%s",
+          __FUNCTION__, mOneBurst ? "true" : "false");
+    return false;
 }
 
 }  // namespace android
diff --git a/camera/WorkerThread.h b/camera/WorkerThread.h
index f52d15f..fc40e67 100644
--- a/camera/WorkerThread.h
+++ b/camera/WorkerThread.h
@@ -21,18 +21,19 @@
 
 namespace android {
 
+class EmulatedCamera;
 class EmulatedCameraDevice;
 
 class WorkerThread : public Thread {
 public:
     WorkerThread(const char* threadName,
                  EmulatedCameraDevice* camera_dev,
-                 Mutex& cameraMutex);
-    virtual ~WorkerThread();
+                 EmulatedCamera* cameraHAL);
+    virtual ~WorkerThread() {}
 
     /* Starts the thread
      * Param:
-     *  one_burst - Controls how many times thread loop should run. If
+     *  oneBurst - Controls how many times thread loop should run. If
      *      this parameter is 'true', thread routine will run only once
      *      If this parameter is 'false', thread routine will run until
      *      stopThread method is called. See startWorkerThread for more
@@ -40,43 +41,18 @@
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    status_t startThread(bool one_burst);
+    status_t startThread(bool oneBurst);
 
-    /* Overriden base class method.
-     * It is overriden in order to provide one-time initialization just
-     * prior to starting the thread routine.
-     */
-    status_t readyToRun() override;
-
-    /* Stops the thread. */
+    /* Stops the thread, this only requests that the thread exits. The method
+     * will return right after the request has been made. Use joinThread to
+     * wait for the thread to exit. */
     status_t stopThread();
 
     /* Wake a thread that's currently waiting to timeout or to be awoken */
     status_t wakeThread();
 
-    /* Values returned from the Select method of this class. */
-    enum SelectRes {
-        TIMEOUT,      /* A timeout has occurred. */
-        READY,        /* Data are available for read on the provided FD. */
-        EXIT_THREAD,  /* Thread exit request has been received. */
-        WAKE_THREAD,  /* Thread wake request has been received */
-        ERROR         /* An error has occurred. */
-    };
-
-    /* Select on an FD event, keeping in mind thread exit message.
-     * Param:
-     *  fd - File descriptor on which to wait for an event. This
-     *      parameter may be negative. If it is negative this method will
-     *      only wait on a control message to the thread.
-     *  timeoutMicroSec - Timeout in microseconds. A negative value indicates
-     *            no timeout (wait forever). A timeout of zero indicates
-     *            an immediate return after polling the FD's; this can
-     *            be used to check if a thread exit has been requested
-     *            without having to wait for a timeout.
-     * Return:
-     *  See SelectRes enum comments.
-     */
-    SelectRes Select(int fd, int timeoutMicroSec);
+    /* Join the thread, waits until the thread exits before returning. */
+    status_t joinThread();
 
 protected:
     /* Perform whatever work should be done in the worker thread. A subclass
@@ -87,36 +63,44 @@
      */
     virtual bool inWorkerThread() = 0;
 
+    /* This provides an opportunity for a subclass to perform some operation
+     * when the thread starts. This is run on the newly started thread. If this
+     * returns an error the thread will exit and inWorkerThread will never be
+     * called.
+     */
+    virtual status_t onThreadStart() { return NO_ERROR; }
+
+    /* This provides an opportunity for a subclass to perform some operation
+     * when the thread exits. This is run on the worker thread. By default this
+     * does nothing.
+     */
+    virtual void onThreadExit() { }
+
     /* Containing camera device object. */
     EmulatedCameraDevice* mCameraDevice;
+    /* The camera HAL from the camera device object */
+    EmulatedCamera* mCameraHAL;
 
     /* Controls number of times the thread loop runs.
      * See startThread for more information. */
     bool mOneBurst;
 
+    /* Running Condition and mutex, use these to sleep the thread, the
+     * supporting functions will use these to signal wakes and exits. */
+    Condition mRunningCondition;
+    Mutex mRunningMutex;
+    bool mRunning;
 private:
-    /* Enumerates control messages that can be sent into the thread. */
-    enum ControlMessage {
-        THREAD_STOP,  /* Stop the thread. */
-        THREAD_WAKE   /* Wake the thread if it's waiting for something */
-    };
+    /* Overriden base class method.
+     * It is overriden in order to provide one-time initialization just
+     * prior to starting the thread routine.
+     */
+    status_t readyToRun() final;
 
     /* Implements abstract method of the base Thread class. */
-    bool threadLoop() override;
-
-    /* Send a control message to the thread */
-    status_t sendControlMessage(ControlMessage message);
+    bool threadLoop() final;
 
     const char* mThreadName;
-
-    /* FD that is used to send control messages into the thread. */
-    int mThreadControl;
-
-    /* FD that thread uses to receive control messages. */
-    int mControlFD;
-
-    Mutex& mCameraMutex;
-    Condition mSetup;
 };
 
 }  // namespace android