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

Commit 646bd616 authored by Cliff Wu's avatar Cliff Wu
Browse files

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
parent 8b7ba583
Loading
Loading
Loading
Loading
+48 −7
Original line number Diff line number Diff line
@@ -1907,8 +1907,14 @@ Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8&
            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 @@ Status CameraService::injectCamera(
        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 @@ Status CameraService::injectCamera(
        // (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 @@ Status CameraService::injectCamera(
            mInjectionInitPending = true;
        }
    }
    mInjectionStatusListener->addListener(callback);
    *cameraInjectionSession = new CameraInjectionSession(this);

    return binder::Status::ok();
}
@@ -5012,10 +5024,39 @@ int32_t CameraService::updateAudioRestrictionLocked() {
    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 = "";
+6 −1
Original line number Diff line number Diff line
@@ -1300,13 +1300,18 @@ private:
            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;
};