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