Injection camera: Block camera access on devices that don't support injection camera

- For devices that do not support camera injection, the external camera
ID will not be registered in the camera service. In this case, when the
user uses the camera on the virtual display of the second device (such
as a Chromebook, tablet) connected by the device, the internal camera
will be projected onto the virtual display. In order not to display the
internal camera screen on the virtual display to protect personal
privacy on the device, onCameraUnavailable will be called.

Bug: 207481642
Test: Manual
Change-Id: Iea12915734373e9f3a5d0c03874cf49236acc3f5
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 1b8eb99..267a1f8 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1907,8 +1907,14 @@
             status_t res = NO_ERROR;
             auto clientDescriptor = mActiveClientManager.get(mInjectionInternalCamId);
             if (clientDescriptor != nullptr) {
-                BasicClient* baseClientPtr = clientDescriptor->getValue().get();
-                res = baseClientPtr->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
+                sp<BasicClient> clientSp = clientDescriptor->getValue();
+                res = checkIfInjectionCameraIsPresent(mInjectionExternalCamId, clientSp);
+                if(res != OK) {
+                    return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
+                            "No camera device with ID \"%s\" currently available",
+                            mInjectionExternalCamId.string());
+                }
+                res = clientSp->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
                 if (res != OK) {
                     mInjectionStatusListener->notifyInjectionError(mInjectionExternalCamId, res);
                 }
@@ -2605,6 +2611,8 @@
         Mutex::Autolock lock(mInjectionParametersLock);
         mInjectionInternalCamId = String8(internalCamId);
         mInjectionExternalCamId = String8(externalCamId);
+        mInjectionStatusListener->addListener(callback);
+        *cameraInjectionSession = new CameraInjectionSession(this);
         status_t res = NO_ERROR;
         auto clientDescriptor = mActiveClientManager.get(mInjectionInternalCamId);
         // If the client already exists, we can directly connect to the camera device through the
@@ -2612,8 +2620,14 @@
         // (execute connectHelper()) before injecting the camera to the camera device.
         if (clientDescriptor != nullptr) {
             mInjectionInitPending = false;
-            BasicClient* baseClientPtr = clientDescriptor->getValue().get();
-            res = baseClientPtr->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
+            sp<BasicClient> clientSp = clientDescriptor->getValue();
+            res = checkIfInjectionCameraIsPresent(mInjectionExternalCamId, clientSp);
+            if(res != OK) {
+                return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
+                        "No camera device with ID \"%s\" currently available",
+                        mInjectionExternalCamId.string());
+            }
+            res = clientSp->injectCamera(mInjectionExternalCamId, mCameraProviderManager);
             if(res != OK) {
                 mInjectionStatusListener->notifyInjectionError(mInjectionExternalCamId, res);
             }
@@ -2621,8 +2635,6 @@
             mInjectionInitPending = true;
         }
     }
-    mInjectionStatusListener->addListener(callback);
-    *cameraInjectionSession = new CameraInjectionSession(this);
 
     return binder::Status::ok();
 }
@@ -5012,10 +5024,39 @@
     return mode;
 }
 
+status_t CameraService::checkIfInjectionCameraIsPresent(const String8& externalCamId,
+        sp<BasicClient> clientSp) {
+    std::unique_ptr<AutoConditionLock> lock =
+            AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
+    status_t res = NO_ERROR;
+    if ((res = checkIfDeviceIsUsable(externalCamId)) != NO_ERROR) {
+        ALOGW("Device %s is not usable!", externalCamId.string());
+        mInjectionStatusListener->notifyInjectionError(
+                externalCamId, UNKNOWN_TRANSACTION);
+        clientSp->notifyError(
+                hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
+                CaptureResultExtras());
+
+        // Do not hold mServiceLock while disconnecting clients, but retain the condition blocking
+        // other clients from connecting in mServiceLockWrapper if held
+        mServiceLock.unlock();
+
+        // Clear caller identity temporarily so client disconnect PID checks work correctly
+        int64_t token = CameraThreadState::clearCallingIdentity();
+        clientSp->disconnect();
+        CameraThreadState::restoreCallingIdentity(token);
+
+        // Reacquire mServiceLock
+        mServiceLock.lock();
+    }
+
+    return res;
+}
+
 void CameraService::clearInjectionParameters() {
     {
         Mutex::Autolock lock(mInjectionParametersLock);
-        mInjectionInitPending = true;
+        mInjectionInitPending = false;
         mInjectionInternalCamId = "";
     }
     mInjectionExternalCamId = "";
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index cb26763..19e9bbb 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1300,13 +1300,18 @@
             wp<CameraService> mParent;
     };
 
+    // When injecting the camera, it will check whether the injecting camera status is unavailable.
+    // If it is, the disconnect function will be called to to prevent camera access on the device.
+    status_t checkIfInjectionCameraIsPresent(const String8& externalCamId,
+            sp<BasicClient> clientSp);
+
     void clearInjectionParameters();
 
     // This is the existing camera id being replaced.
     String8 mInjectionInternalCamId;
     // This is the external camera Id replacing the internalId.
     String8 mInjectionExternalCamId;
-    bool mInjectionInitPending = true;
+    bool mInjectionInitPending = false;
     // Guard mInjectionInternalCamId and mInjectionInitPending.
     Mutex mInjectionParametersLock;
 };