Camera: Drop ProCamera connections when a Camera connection happens

* Also adds an ICameraServiceListener with available/not available statuses

Bug: 8291653
Change-Id: I24680f1a2dc109510caf451cf7c7bd180b670d84
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index eda3012..6fed8b4 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -115,6 +115,8 @@
     Mutex::Autolock icl(mIProCameraUserLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
+    if (!mDevice.get()) return PERMISSION_DENIED;
+
     if (!mExclusiveLock) {
         mExclusiveLock = true;
 
@@ -144,6 +146,8 @@
     Mutex::Autolock icl(mIProCameraUserLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
+    if (!mDevice.get()) return PERMISSION_DENIED;
+
     /**
      * TODO: this should asynchronously 'wait' until the lock becomes available
      * if another client already has an exclusive lock.
@@ -197,12 +201,33 @@
     return mExclusiveLock;
 }
 
+void ProCamera2Client::onExclusiveLockStolen() {
+    ALOGV("%s: ProClient lost exclusivity (id %d)",
+          __FUNCTION__, mCameraId);
+
+    Mutex::Autolock icl(mIProCameraUserLock);
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+    if (mExclusiveLock && mRemoteCallback.get() != NULL) {
+        mRemoteCallback->onLockStatusChanged(
+                                       IProCameraCallbacks::LOCK_STOLEN);
+    }
+
+    mExclusiveLock = false;
+
+    //TODO: we should not need to detach the device, merely reset it.
+    detachDevice();
+}
+
 status_t ProCamera2Client::submitRequest(camera_metadata_t* request,
                                          bool streaming) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
     Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     if (!mExclusiveLock) {
         return PERMISSION_DENIED;
     }
@@ -224,6 +249,9 @@
     ALOGV("%s", __FUNCTION__);
 
     Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     if (!mExclusiveLock) {
         return PERMISSION_DENIED;
     }
@@ -247,6 +275,7 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
     mDevice->clearStreamingRequest();
 
     status_t code;
@@ -274,6 +303,8 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     sp<IBinder> binder;
     sp<ANativeWindow> window;
     if (bufferProducer != 0) {
@@ -303,6 +334,8 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     CameraMetadata metadata;
     if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK) {
         *request = metadata.release();
@@ -319,6 +352,10 @@
         return INVALID_OPERATION;
     }
 
+    Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     CameraMetadata deviceInfo = mDevice->info();
     *info = deviceInfo.release();
 
@@ -341,6 +378,12 @@
     result = "  Device dump:\n";
     write(fd, result.string(), result.size());
 
+    if (!mDevice.get()) {
+        result = "  *** Device is detached\n";
+        write(fd, result.string(), result.size());
+        return NO_ERROR;
+    }
+
     status_t res = mDevice->dump(fd, args);
     if (res != OK) {
         result = String8::format("   Error dumping device: %s (%d)",
@@ -363,9 +406,19 @@
     int callingPid = getCallingPid();
     if (callingPid != mClientPid && callingPid != mServicePid) return;
 
+    ALOGV("Camera %d: Shutting down", mCameraId);
+
+    detachDevice();
+    ProClient::disconnect();
+
+    ALOGV("Camera %d: Shut down complete complete", mCameraId);
+}
+
+void ProCamera2Client::detachDevice() {
     if (mDevice == 0) return;
 
-    ALOGV("Camera %d: Shutting down", mCameraId);
+    ALOGV("Camera %d: Stopping processors", mCameraId);
+
     mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
                                     FRAME_PROCESSOR_LISTENER_MAX_ID,
                                     /*listener*/this);
@@ -374,11 +427,22 @@
     mFrameProcessor->join();
     ALOGV("Camera %d: Disconnecting device", mCameraId);
 
+    // WORKAROUND: HAL refuses to disconnect while there's streams in flight
+    {
+        mDevice->clearStreamingRequest();
+
+        status_t code;
+        if ((code = mDevice->waitUntilDrained()) != OK) {
+            ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
+                  code);
+        }
+    }
+
     mDevice->disconnect();
 
     mDevice.clear();
 
-    ProClient::disconnect();
+    ALOGV("Camera %d: Detach complete", mCameraId);
 }
 
 status_t ProCamera2Client::connect(const sp<IProCameraCallbacks>& client) {