cameraserver: Add support for system only cameras

Bug: 133508924
Bug: 138135733

android.permission.CAMERA and android.permission.SYSTEM_CAMERA are both
required by a client process to access system only cameras.

Test: Advertise the back camera as system only;
        1) don't give Camera2 SYSTEM_CAMERA permissions,
           Camera2 can't connect to the back camera
        2) give Camera2 SYSTEM_CAMERA permissions, Camera2 successfully
           connects.
        3) 3P app can't connect to any camera if all cameras are
           advertised as SYSTEM_ONLY_CAMERAs.

Test: CTS CameraDeviceTest, CameraManagerTest

Change-Id: I0309462f962d9c8c92564ef6781b2aae1485a933
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
gugelfrei
Jayant Chowdhary 5 years ago
parent 676a5419d7
commit 5216b21181

@ -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;

@ -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());
cameraId.c_str());
continue;
}
listener.second->getListener()->onStatusChanged(mapToInterface(status),
listener->getListener()->onStatusChanged(mapToInterface(status),
String16(cameraId));
}
});

@ -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;

@ -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) {

@ -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,

Loading…
Cancel
Save