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

Commit c0b8d471 authored by Valentin Iftime's avatar Valentin Iftime
Browse files

Disconnect external cameras if sensor privacy enabled

 If the camera device does not support mute test patterns, then it
 will be disconnected when the camera sensor privacy is enabled.

Bug: 182204067
Test: Connect an USB camera.
 Enable camera privacy toggle.
 Apps using the camera should get a blank preview (camera disconnected)
Change-Id: I7298e16190d6416abbe981adcbb1f87637fcaf77
parent 050b31fb
Loading
Loading
Loading
Loading
+52 −7
Original line number Diff line number Diff line
@@ -1834,10 +1834,31 @@ Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8&
        }

        // Set camera muting behavior
        if (client->supportsCameraMute()) {
        bool isCameraPrivacyEnabled =
                mSensorPrivacyPolicy->isCameraPrivacyEnabled(multiuser_get_user_id(clientUid));
            client->setCameraMute(mOverrideCameraMuteMode || isCameraPrivacyEnabled);
        if (client->supportsCameraMute()) {
            client->setCameraMute(
                    mOverrideCameraMuteMode || isCameraPrivacyEnabled);
        } else if (isCameraPrivacyEnabled) {
            // no camera mute supported, but privacy is on! => disconnect
            ALOGI("Camera mute not supported for package: %s, camera id: %s",
                    String8(client->getPackageName()).string(), cameraId.string());
            // 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();
            // Note AppOp to trigger the "Unblock" dialog
            client->noteAppOp();
            client->disconnect();
            CameraThreadState::restoreCallingIdentity(token);
            // Reacquire mServiceLock
            mServiceLock.lock();

            return STATUS_ERROR_FMT(ERROR_DISABLED,
                    "Camera \"%s\" disabled due to camera mute", cameraId.string());
        }

        if (shimUpdateOnly) {
@@ -3195,6 +3216,27 @@ status_t CameraService::BasicClient::startCameraStreamingOps() {
    return OK;
}

status_t CameraService::BasicClient::noteAppOp() {
    ATRACE_CALL();

    ALOGV("%s: Start camera noteAppOp, package name = %s, client UID = %d",
            __FUNCTION__, String8(mClientPackageName).string(), mClientUid);

    // noteAppOp is only used for when camera mute is not supported, in order
    // to trigger the sensor privacy "Unblock" dialog
    if (mAppOpsManager != nullptr) {
        int32_t mode = mAppOpsManager->noteOp(AppOpsManager::OP_CAMERA, mClientUid,
                mClientPackageName, mClientFeatureId,
                String16("start camera ") + String16(mCameraIdStr));
        status_t res = handleAppOpMode(mode);
        if (res != OK) {
            return res;
        }
    }

    return OK;
}

status_t CameraService::BasicClient::finishCameraStreamingOps() {
    ATRACE_CALL();

@@ -3287,11 +3329,14 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16&) {
        // 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.
        if (!mUidIsTrusted && isUidActive && isCameraPrivacyEnabled) {
        if (!mUidIsTrusted) {
            if (isUidActive && isCameraPrivacyEnabled && supportsCameraMute()) {
                setCameraMute(true);
        } else if (!mUidIsTrusted && !isUidActive) {
            } else if (!isUidActive
                || (isCameraPrivacyEnabled && !supportsCameraMute())) {
                block();
            }
        }
    } else if (res == AppOpsManager::MODE_ALLOWED) {
        setCameraMute(sCameraService->mOverrideCameraMuteMode);
    }
+3 −0
Original line number Diff line number Diff line
@@ -371,6 +371,9 @@ public:
        virtual status_t                finishCameraOps();
        // Handle errors for start/checkOps
        virtual status_t                handleAppOpMode(int32_t mode);
        // Just notify camera appops to trigger unblocking dialog if sensor
        // privacy is enabled and camera mute is not supported
        virtual status_t                noteAppOp();

        std::unique_ptr<AppOpsManager>  mAppOpsManager = nullptr;