Loading camera/ndk/include/camera/NdkCameraMetadataTags.h +7 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/camera/libcameraservice/CameraService.cpp +103 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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}); } } Loading Loading @@ -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( Loading @@ -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); Loading Loading @@ -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", Loading Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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()); Loading @@ -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); Loading Loading @@ -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)", Loading @@ -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); } Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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()); Loading Loading @@ -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)); } }); Loading services/camera/libcameraservice/CameraService.h +23 −6 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading @@ -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; Loading services/camera/libcameraservice/common/CameraProviderManager.cpp +18 −10 Original line number Diff line number Diff line Loading @@ -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( Loading Loading @@ -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) { Loading Loading @@ -1937,7 +1945,7 @@ CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string& return; } mIsPublicallyHiddenSecureCamera = isPublicallyHiddenSecureCamera(); mSystemCameraKind = getSystemCameraKind(); status_t res = fixupMonochromeTags(); if (OK != res) { Loading services/camera/libcameraservice/common/CameraProviderManager.h +23 −3 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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, Loading Loading
camera/ndk/include/camera/NdkCameraMetadataTags.h +7 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/camera/libcameraservice/CameraService.cpp +103 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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}); } } Loading Loading @@ -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( Loading @@ -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); Loading Loading @@ -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", Loading Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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()); Loading @@ -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); Loading Loading @@ -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)", Loading @@ -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); } Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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()); Loading Loading @@ -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)); } }); Loading
services/camera/libcameraservice/CameraService.h +23 −6 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading @@ -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; Loading
services/camera/libcameraservice/common/CameraProviderManager.cpp +18 −10 Original line number Diff line number Diff line Loading @@ -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( Loading Loading @@ -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) { Loading Loading @@ -1937,7 +1945,7 @@ CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string& return; } mIsPublicallyHiddenSecureCamera = isPublicallyHiddenSecureCamera(); mSystemCameraKind = getSystemCameraKind(); status_t res = fixupMonochromeTags(); if (OK != res) { Loading
services/camera/libcameraservice/common/CameraProviderManager.h +23 −3 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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, Loading