Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca1e0064 authored by Austin Borger's avatar Austin Borger
Browse files

CameraService: Watch for foreground changes from AppOps

AppOps now sends notifications when an app loses its camera capability.
We should watch for these notifications and block clients when they
happen, assuming they're untrusted. Otherwise, an app that should not
have camera access outside of the foreground may retain it.

Bug: 290086710
Test: Ran on physical device, tested Zoom + GCA
Change-Id: Ie69f96d91ec3898114a2c106afe3d42143cd8d33
parent ffff5ff5
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,13 @@ flag {
     bug: "309627704"
}

flag {
     namespace: "camera_platform"
     name: "watch_foreground_changes"
     description: "Request AppOps to notify changes in the foreground status of the client"
     bug: "290086710"
}

flag {
     namespace: "camera_platform"
     name: "log_ultrawide_usage"
+32 −11
Original line number Diff line number Diff line
@@ -4288,8 +4288,15 @@ status_t CameraService::BasicClient::startCameraOps() {
    if (mAppOpsManager != nullptr) {
        // Notify app ops that the camera is not available
        mOpsCallback = new OpsCallback(this);

        if (flags::watch_foreground_changes()) {
            mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
                toString16(mClientPackageName),
                AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
        } else {
            mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
                toString16(mClientPackageName), mOpsCallback);
        }

        // Just check for camera acccess here on open - delay startOp until
        // camera frames start streaming in startCameraStreamingOps
@@ -4450,6 +4457,11 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16&) {
    } else if (res == AppOpsManager::MODE_IGNORED) {
        bool isUidActive = sCameraService->mUidPolicy->isUidActive(mClientUid, mClientPackageName);

        // Uid may be active, but not visible to the user (e.g. PROCESS_STATE_FOREGROUND_SERVICE).
        // If not visible, but still active, then we want to block instead of muting the camera.
        int32_t procState = sCameraService->mUidPolicy->getProcState(mClientUid);
        bool isUidVisible = (procState <= ActivityManager::PROCESS_STATE_BOUND_TOP);

        bool isCameraPrivacyEnabled;
        if (flags::camera_privacy_allowlist()) {
            isCameraPrivacyEnabled = sCameraService->isCameraPrivacyEnabled(
@@ -4460,12 +4472,20 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16&) {
        }

        ALOGI("Camera %s: Access for \"%s\" has been restricted, isUidTrusted %d, isUidActive %d"
                " isCameraPrivacyEnabled %d", mCameraIdStr.c_str(), mClientPackageName.c_str(),
                mUidIsTrusted, isUidActive, isCameraPrivacyEnabled);
        // If the calling Uid is trusted (a native service), or the client Uid is active (WAR for
        // b/175320666), the AppOpsManager could return MODE_IGNORED. Do not treat such cases as
        // error.
                " isUidVisible %d, isCameraPrivacyEnabled %d", mCameraIdStr.c_str(),
                mClientPackageName.c_str(), mUidIsTrusted, isUidActive, isUidVisible,
                isCameraPrivacyEnabled);
        // If the calling Uid is trusted (a native service), or the client Uid is active / visible
        // (WAR for b/175320666)the AppOpsManager could return MODE_IGNORED. Do not treat such
        // cases as error.
        if (!mUidIsTrusted) {
            if (flags::watch_foreground_changes()) {
                if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
                    setCameraMute(true);
                } else {
                    block();
                }
            } else {
                if (isUidActive && isCameraPrivacyEnabled && supportsCameraMute()) {
                    setCameraMute(true);
                } else if (!isUidActive
@@ -4473,6 +4493,7 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16&) {
                    block();
                }
            }
        }
    } else if (res == AppOpsManager::MODE_ALLOWED) {
        setCameraMute(sCameraService->mOverrideCameraMuteMode);
    }