Camera: Add onCameraOpened/onCameraClosed callbacks

The onCameraOpened/onCameraClosed callbacks are used to notify camera
service client with CAMERA_OPEN_CLOSE_LISTENER permission that a certain
camera device has been opened/closed.

Test: Manually check callbacks are received in SystemUI app
Bug: 150540299
Change-Id: If6f3624c43927c30afef7df0a780eafe3ae4c527
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 453984e..e0884f4 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -126,6 +126,8 @@
 static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
 static const String16
         sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
+static const String16 sCameraOpenCloseListenerPermission(
+        "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
 
 // Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
 static constexpr int32_t kVendorClientScore = 200;
@@ -2146,6 +2148,8 @@
 
     auto clientUid = CameraThreadState::getCallingUid();
     auto clientPid = CameraThreadState::getCallingPid();
+    bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
+            clientPid, clientUid);
 
     Mutex::Autolock lock(mServiceLock);
 
@@ -2160,7 +2164,8 @@
         }
 
         sp<ServiceListener> serviceListener =
-                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener);
+                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
+                        openCloseCallbackAllowed);
         auto ret = serviceListener->initialize();
         if (ret != NO_ERROR) {
             String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -2923,6 +2928,9 @@
 
     sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
 
+    // Notify listeners of camera open/close status
+    sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName);
+
     return OK;
 }
 
@@ -2963,6 +2971,9 @@
 
     sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
 
+    // Notify listeners of camera open/close status
+    sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName);
+
     return OK;
 }
 
@@ -3759,6 +3770,29 @@
         });
 }
 
+void CameraService::updateOpenCloseStatus(const String8& cameraId, bool open,
+        const String16& clientPackageName) {
+    Mutex::Autolock lock(mStatusListenerLock);
+
+    for (const auto& it : mListenerList) {
+        if (!it->isOpenCloseCallbackAllowed()) {
+            continue;
+        }
+
+        binder::Status ret;
+        String16 cameraId64(cameraId);
+        if (open) {
+            ret = it->getListener()->onCameraOpened(cameraId64, clientPackageName);
+        } else {
+            ret = it->getListener()->onCameraClosed(cameraId64);
+        }
+        if (!ret.isOk()) {
+            ALOGE("%s: Failed to trigger onCameraOpened/onCameraClosed callback: %d", __FUNCTION__,
+                    ret.exceptionCode());
+        }
+    }
+}
+
 template<class Func>
 void CameraService::CameraState::updateStatus(StatusInternal status,
         const String8& cameraId,