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

Commit 34bbfc44 authored by Jayant Chowdhary's avatar Jayant Chowdhary Committed by Android (Google) Code Review
Browse files

Merge "cameraserver: Add support for system only cameras"

parents 706f1052 5216b211
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -7758,6 +7758,13 @@ typedef enum acamera_metadata_enum_acamera_request_available_capabilities {
     */
    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA         = 13,

    /**
     * <p>The camera device is only accessible by Android's system components and privileged
     * applications. Processes need to have the android.permission.SYSTEM_CAMERA in
     * addition to android.permission.CAMERA in order to connect to this camera device.</p>
     */
    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA             = 14,

} acamera_metadata_enum_android_request_available_capabilities_t;


+103 −38
Original line number Diff line number Diff line
@@ -117,7 +117,12 @@ static void setLogLevel(int level) {

// ----------------------------------------------------------------------------

static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
static const String16 sCameraPermission("android.permission.CAMERA");
static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
static const String16
        sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");

// Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
static constexpr int32_t kVendorClientScore = 200;
@@ -239,7 +244,7 @@ void CameraService::broadcastTorchModeStatus(const String8& cameraId, TorchModeS
    Mutex::Autolock lock(mStatusListenerLock);

    for (auto& i : mListenerList) {
        i.second->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
        i->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
    }
}

@@ -514,6 +519,11 @@ Status CameraService::getCameraCharacteristics(const String16& cameraId,
                "Camera subsystem is not available");;
    }

    if (shouldRejectSystemCameraConnection(String8(cameraId))) {
        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
                "characteristics for system only device %s: ", String8(cameraId).string());
    }

    Status ret{};

    status_t res = mCameraProviderManager->getCameraCharacteristics(
@@ -527,9 +537,12 @@ Status CameraService::getCameraCharacteristics(const String16& cameraId,
    int callingPid = CameraThreadState::getCallingPid();
    int callingUid = CameraThreadState::getCallingUid();
    std::vector<int32_t> tagsRemoved;
    // If it's not calling from cameraserver, check the permission.
    // If it's not calling from cameraserver, check the permission only if
    // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
    // it would've already been checked in shouldRejectSystemCameraConnection.
    if ((callingPid != getpid()) &&
            !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
            (getSystemCameraKind(String8(cameraId)) != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
            !checkPermission(sCameraPermission, callingPid, callingUid)) {
        res = cameraInfo->removePermissionEntries(
                mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
                &tagsRemoved);
@@ -969,9 +982,18 @@ Status CameraService::validateClientPermissionsLocked(const String8& cameraId,
                clientName8.string(), clientUid, clientPid);
    }

    // If it's not calling from cameraserver, check the permission.
    if (shouldRejectSystemCameraConnection(cameraId)) {
        ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
                cameraId.c_str());
        return STATUS_ERROR_FMT(ERROR_DISCONNECTED, "No camera device with ID \"%s\" is"
                                "available", cameraId.string());
    }
    // If it's not calling from cameraserver, check the permission if the
    // device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
    // android.permission.SYSTEM_CAMERA for system only camera devices).
    if (callingPid != getpid() &&
            !checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
                (getSystemCameraKind(cameraId) != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
                !checkPermission(sCameraPermission, clientPid, clientUid)) {
        ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
@@ -1324,15 +1346,63 @@ Status CameraService::connectLegacy(
    return ret;
}

bool CameraService::shouldRejectHiddenCameraConnection(const String8 & cameraId) {
    // If the thread serving this call is not a hwbinder thread and the caller
    // isn't the cameraserver itself, and the camera id being requested is to be
    // publically hidden, we should reject the connection.
static bool hasPermissionsForSystemCamera(int callingPid, int callingUid) {
    return checkPermission(sSystemCameraPermission, callingPid, callingUid) &&
            checkPermission(sCameraPermission, callingPid, callingUid);
}

bool CameraService::shouldSkipStatusUpdates(const String8& cameraId, bool isVendorListener,
        int clientPid, int clientUid) const {
    SystemCameraKind systemCameraKind = getSystemCameraKind(cameraId);
    // If the client is not a vendor client, don't add listener if
    //   a) the camera is a publicly hidden secure camera OR
    //   b) the camera is a system only camera and the client doesn't
    //      have android.permission.SYSTEM_CAMERA permissions.
    if (!isVendorListener && (systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA ||
            (systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
            !hasPermissionsForSystemCamera(clientPid, clientUid)))) {
        return true;
    }
    return false;
}

bool CameraService::shouldRejectSystemCameraConnection(const String8& cameraId) const {
    // Rules for rejection:
    // 1) If cameraserver tries to access this camera device, accept the
    //    connection.
    // 2) The camera device is a publicly hidden secure camera device AND some
    //    component is trying to access it on a non-hwbinder thread (generally a non HAL client),
    //    reject it.
    // 3) if the camera device is advertised by the camera HAL as SYSTEM_ONLY
    //    and the serving thread is a non hwbinder thread, the client must have
    //    android.permission.SYSTEM_CAMERA permissions to connect.

    int cPid = CameraThreadState::getCallingPid();
    int cUid = CameraThreadState::getCallingUid();
    SystemCameraKind systemCameraKind = getSystemCameraKind(cameraId);

    // (1) Cameraserver trying to connect, accept.
    if (CameraThreadState::getCallingPid() == getpid()) {
        return false;
    }
    // (2)
    if (!hardware::IPCThreadState::self()->isServingCall() &&
            systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
        ALOGW("Rejecting access to secure hidden camera %s", cameraId.c_str());
        return true;
    }
    // (3) Here we only check for permissions if it is a system only camera device. This is since
    //     getCameraCharacteristics() allows for calls to succeed (albeit after hiding some
    //     characteristics) even if clients don't have android.permission.CAMERA. We do not want the
    //     same behavior for system camera devices.
    if (!hardware::IPCThreadState::self()->isServingCall() &&
            CameraThreadState::getCallingPid() != getpid() &&
            mCameraProviderManager->isPublicallyHiddenSecureCamera(cameraId.c_str())) {
            systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
            !hasPermissionsForSystemCamera(cPid, cUid)) {
        ALOGW("Rejecting access to system only camera %s, inadequete permissions",
                cameraId.c_str());
        return true;
    }

    return false;
}

@@ -1385,14 +1455,6 @@ Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8&
            (halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
            static_cast<int>(effectiveApiLevel));

    if (shouldRejectHiddenCameraConnection(cameraId)) {
        ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
              cameraId.c_str());
        return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
                                "No camera device with ID \"%s\" currently available",
                                cameraId.string());

    }
    sp<CLIENT> client = nullptr;
    {
        // Acquire mServiceLock and prevent other clients from connecting
@@ -1668,8 +1730,7 @@ Status CameraService::notifySystemEvent(int32_t eventId,
    if (pid != selfPid) {
        // Ensure we're being called by system_server, or similar process with
        // permissions to notify the camera service about system events
        if (!checkCallingPermission(
                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
        if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
            const int uid = CameraThreadState::getCallingUid();
            ALOGE("Permission Denial: cannot send updates to camera service about system"
                    " events from pid=%d, uid=%d", pid, uid);
@@ -1704,7 +1765,7 @@ void CameraService::notifyMonitoredUids() {
    Mutex::Autolock lock(mStatusListenerLock);

    for (const auto& it : mListenerList) {
        auto ret = it.second->getListener()->onCameraAccessPrioritiesChanged();
        auto ret = it->getListener()->onCameraAccessPrioritiesChanged();
        if (!ret.isOk()) {
            ALOGE("%s: Failed to trigger permission callback: %d", __FUNCTION__,
                    ret.exceptionCode());
@@ -1720,8 +1781,7 @@ Status CameraService::notifyDeviceStateChange(int64_t newState) {
    if (pid != selfPid) {
        // Ensure we're being called by system_server, or similar process with
        // permissions to notify the camera service about system events
        if (!checkCallingPermission(
                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
        if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
            const int uid = CameraThreadState::getCallingUid();
            ALOGE("Permission Denial: cannot send updates to camera service about device"
                    " state changes from pid=%d, uid=%d", pid, uid);
@@ -1775,20 +1835,23 @@ Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listen
        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addListener");
    }

    auto clientUid = CameraThreadState::getCallingUid();
    auto clientPid = CameraThreadState::getCallingPid();

    Mutex::Autolock lock(mServiceLock);

    {
        Mutex::Autolock lock(mStatusListenerLock);
        for (const auto &it : mListenerList) {
            if (IInterface::asBinder(it.second->getListener()) == IInterface::asBinder(listener)) {
            if (IInterface::asBinder(it->getListener()) == IInterface::asBinder(listener)) {
                ALOGW("%s: Tried to add listener %p which was already subscribed",
                      __FUNCTION__, listener.get());
                return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered");
            }
        }

        auto clientUid = CameraThreadState::getCallingUid();
        sp<ServiceListener> serviceListener = new ServiceListener(this, listener, clientUid);
        sp<ServiceListener> serviceListener =
                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener);
        auto ret = serviceListener->initialize();
        if (ret != NO_ERROR) {
            String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -1796,7 +1859,10 @@ Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listen
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
        }
        mListenerList.emplace_back(isVendorListener, serviceListener);
        // The listener still needs to be added to the list of listeners, regardless of what
        // permissions the listener process has / whether it is a vendor listener. Since it might be
        // eligible to listen to other camera ids.
        mListenerList.emplace_back(serviceListener);
        mUidPolicy->registerMonitorUid(clientUid);
    }

@@ -1804,8 +1870,7 @@ Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listen
    {
        Mutex::Autolock lock(mCameraStatesLock);
        for (auto& i : mCameraStates) {
            if (!isVendorListener &&
                mCameraProviderManager->isPublicallyHiddenSecureCamera(i.first.c_str())) {
            if (shouldSkipStatusUpdates(i.first, isVendorListener, clientPid, clientUid)) {
                ALOGV("Cannot add public listener for hidden system-only %s for pid %d",
                      i.first.c_str(), CameraThreadState::getCallingPid());
                continue;
@@ -1844,9 +1909,9 @@ Status CameraService::removeListener(const sp<ICameraServiceListener>& listener)
    {
        Mutex::Autolock lock(mStatusListenerLock);
        for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
            if (IInterface::asBinder(it->second->getListener()) == IInterface::asBinder(listener)) {
                mUidPolicy->unregisterMonitorUid(it->second->getListenerUid());
                IInterface::asBinder(listener)->unlinkToDeath(it->second);
            if (IInterface::asBinder((*it)->getListener()) == IInterface::asBinder(listener)) {
                mUidPolicy->unregisterMonitorUid((*it)->getListenerUid());
                IInterface::asBinder(listener)->unlinkToDeath(*it);
                mListenerList.erase(it);
                return Status::ok();
            }
@@ -3029,7 +3094,7 @@ static bool tryLock(Mutex& mutex)
status_t CameraService::dump(int fd, const Vector<String16>& args) {
    ATRACE_CALL();

    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
    if (checkCallingPermission(sDumpPermission) == false) {
        dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
                CameraThreadState::getCallingPid(),
                CameraThreadState::getCallingUid());
@@ -3261,13 +3326,13 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId,
            Mutex::Autolock lock(mStatusListenerLock);

            for (auto& listener : mListenerList) {
                if (!listener.first &&
                    mCameraProviderManager->isPublicallyHiddenSecureCamera(cameraId.c_str())) {
                if (shouldSkipStatusUpdates(cameraId, listener->isVendorListener(),
                        listener->getListenerPid(), listener->getListenerUid())) {
                    ALOGV("Skipping camera discovery callback for system-only camera %s",
                            cameraId.c_str());
                    continue;
                }
                listener.second->getListener()->onStatusChanged(mapToInterface(status),
                listener->getListener()->onStatusChanged(mapToInterface(status),
                        String16(cameraId));
            }
        });
+23 −6
Original line number Diff line number Diff line
@@ -633,9 +633,20 @@ private:
        sp<BasicClient>* client,
        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial);

    // Should an operation attempt on a cameraId be rejected, if the camera id is
    // advertised as a publically hidden secure camera, by the camera HAL ?
    bool shouldRejectHiddenCameraConnection(const String8 & cameraId);
    // Should an operation attempt on a cameraId be rejected ? (this can happen
    // under various conditions. For example if a camera device is advertised as
    // system only or hidden secure camera, amongst possible others.
    bool shouldRejectSystemCameraConnection(const String8 & cameraId) const;

    // Should a device status update be skipped for a particular camera device ? (this can happen
    // under various conditions. For example if a camera device is advertised as
    // system only or hidden secure camera, amongst possible others.
    bool shouldSkipStatusUpdates(const String8& cameraId, bool isVendorListener, int clientPid,
            int clientUid) const;

    inline SystemCameraKind getSystemCameraKind(const String8& cameraId) const {
        return mCameraProviderManager->getSystemCameraKind(cameraId.c_str());
    }

    // Single implementation shared between the various connect calls
    template<class CALLBACK, class CLIENT>
@@ -810,7 +821,9 @@ private:
    class ServiceListener : public virtual IBinder::DeathRecipient {
        public:
            ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
                    int uid) : mParent(parent), mListener(listener), mListenerUid(uid) {}
                    int uid, int pid, bool isVendorClient)
                    : mParent(parent), mListener(listener), mListenerUid(uid), mListenerPid(pid),
                      mIsVendorListener(isVendorClient) { }

            status_t initialize() {
                return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -824,16 +837,20 @@ private:
            }

            int getListenerUid() { return mListenerUid; }
            int getListenerPid() { return mListenerPid; }
            sp<hardware::ICameraServiceListener> getListener() { return mListener; }
            bool isVendorListener() { return mIsVendorListener; }

        private:
            wp<CameraService> mParent;
            sp<hardware::ICameraServiceListener> mListener;
            int mListenerUid;
            int mListenerUid = -1;
            int mListenerPid = -1;
            bool mIsVendorListener = false;
    };

    // Guarded by mStatusListenerMutex
    std::vector<std::pair<bool, sp<ServiceListener>>> mListenerList;
    std::vector<sp<ServiceListener>> mListenerList;

    Mutex       mStatusListenerLock;

+18 −10
Original line number Diff line number Diff line
@@ -534,15 +534,23 @@ void CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds()
    }
}

bool CameraProviderManager::ProviderInfo::DeviceInfo3::isPublicallyHiddenSecureCamera() {
SystemCameraKind CameraProviderManager::ProviderInfo::DeviceInfo3::getSystemCameraKind() {
    camera_metadata_entry_t entryCap;
    entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
    if (entryCap.count != 1) {
        // Do NOT hide this camera device if the capabilities specify anything more
        // than ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA.
        return false;
    if (entryCap.count == 1 &&
            entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
        return SystemCameraKind::HIDDEN_SECURE_CAMERA;
    }
    return entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;

    // Go through the capabilities and check if it has
    // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
    for (size_t i = 0; i < entryCap.count; ++i) {
        uint8_t capability = entryCap.data.u8[i];
        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
            return SystemCameraKind::SYSTEM_ONLY_CAMERA;
        }
    }
    return SystemCameraKind::PUBLIC;
}

void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedSizes(
@@ -1046,14 +1054,14 @@ bool CameraProviderManager::isLogicalCamera(const std::string& id,
    return deviceInfo->mIsLogicalCamera;
}

bool CameraProviderManager::isPublicallyHiddenSecureCamera(const std::string& id) {
SystemCameraKind CameraProviderManager::getSystemCameraKind(const std::string& id) {
    std::lock_guard<std::mutex> lock(mInterfaceMutex);

    auto deviceInfo = findDeviceInfoLocked(id);
    if (deviceInfo == nullptr) {
        return false;
        return SystemCameraKind::PUBLIC;
    }
    return deviceInfo->mIsPublicallyHiddenSecureCamera;
    return deviceInfo->mSystemCameraKind;
}

bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) {
@@ -1937,7 +1945,7 @@ CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string&
        return;
    }

    mIsPublicallyHiddenSecureCamera = isPublicallyHiddenSecureCamera();
    mSystemCameraKind = getSystemCameraKind();

    status_t res = fixupMonochromeTags();
    if (OK != res) {
+23 −3
Original line number Diff line number Diff line
@@ -54,6 +54,26 @@ public:
            sp<VendorTagDescriptor>& descriptor);
};

enum SystemCameraKind {
   /**
    * These camera devices are visible to all apps and system components alike
    */
   PUBLIC = 0,

   /**
    * These camera devices are visible only to processes having the
    * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
    * apps.
    */
   SYSTEM_ONLY_CAMERA,

   /**
    * These camera devices are visible only to HAL clients (that try to connect
    * on a hwbinder thread).
    */
   HIDDEN_SECURE_CAMERA
};

/**
 * A manager for all camera providers available on an Android device.
 *
@@ -272,7 +292,7 @@ public:
     */
    bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);

    bool isPublicallyHiddenSecureCamera(const std::string& id);
    SystemCameraKind getSystemCameraKind(const std::string& id);
    bool isHiddenPhysicalCamera(const std::string& cameraId);

    static const float kDepthARTolerance;
@@ -379,7 +399,7 @@ private:
            std::vector<std::string> mPhysicalIds;
            hardware::CameraInfo mInfo;
            sp<IBase> mSavedInterface;
            bool mIsPublicallyHiddenSecureCamera = false;
            SystemCameraKind mSystemCameraKind = SystemCameraKind::PUBLIC;

            const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;

@@ -497,7 +517,7 @@ private:
            CameraMetadata mCameraCharacteristics;
            std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
            void queryPhysicalCameraIds();
            bool isPublicallyHiddenSecureCamera();
            SystemCameraKind getSystemCameraKind();
            status_t fixupMonochromeTags();
            status_t addDynamicDepthTags();
            static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,