From 48af7e8dd40883d6154e7029d9500072b551b5fa Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 19 Feb 2013 10:40:14 -0800 Subject: [PATCH] CameraService and Stagefright: Support AppOps Camera: - Signal to AppOpsService when camera usage starts and stops - Listen to permissions revocations and act on them - Currently just kill camera connection when permissions lost Stagefright: - Pass on client name, UID to camera as needed Bug: 8181262 Change-Id: I9e33c9d05e9daa77dbb2d795045d08eb887ec8f0 --- camera/Camera.cpp | 6 +- camera/ICameraService.cpp | 14 +- cmds/stagefright/record.cpp | 3 +- include/camera/Camera.h | 10 +- include/camera/ICameraService.h | 20 ++- include/media/IMediaRecorder.h | 1 + include/media/MediaRecorderBase.h | 1 + include/media/mediarecorder.h | 1 + include/media/stagefright/CameraSource.h | 28 +++- include/media/stagefright/CameraSourceTimeLapse.h | 5 + media/libmedia/IMediaRecorder.cpp | 19 ++- media/libmedia/mediarecorder.cpp | 21 +++ .../libmediaplayerservice/MediaRecorderClient.cpp | 12 +- media/libmediaplayerservice/MediaRecorderClient.h | 1 + .../libmediaplayerservice/StagefrightRecorder.cpp | 13 +- media/libmediaplayerservice/StagefrightRecorder.h | 3 + media/libstagefright/CameraSource.cpp | 27 +++- media/libstagefright/CameraSourceTimeLapse.cpp | 8 +- services/camera/libcameraservice/Camera2Client.cpp | 15 +- services/camera/libcameraservice/Camera2Client.h | 2 + services/camera/libcameraservice/CameraClient.cpp | 18 ++- services/camera/libcameraservice/CameraClient.h | 2 + services/camera/libcameraservice/CameraService.cpp | 171 +++++++++++++++++---- services/camera/libcameraservice/CameraService.h | 57 ++++++- .../camera/libcameraservice/ProCamera2Client.cpp | 6 +- .../camera/libcameraservice/ProCamera2Client.h | 2 + 26 files changed, 388 insertions(+), 78 deletions(-) diff --git a/camera/Camera.cpp b/camera/Camera.cpp index be395ba0b1..d8dc2a5c30 100644 --- a/camera/Camera.cpp +++ b/camera/Camera.cpp @@ -19,6 +19,7 @@ #define LOG_TAG "Camera" #include #include +#include #include #include #include @@ -116,14 +117,15 @@ status_t Camera::getCameraInfo(int cameraId, return cs->getCameraInfo(cameraId, cameraInfo); } -sp Camera::connect(int cameraId) +sp Camera::connect(int cameraId, const String16& clientPackageName, + int clientUid) { ALOGV("connect"); sp c = new Camera(); sp cl = c; const sp& cs = getCameraService(); if (cs != 0) { - c->mCamera = cs->connect(cl, cameraId); + c->mCamera = cs->connect(cl, cameraId, clientPackageName, clientUid); } if (c->mCamera != 0) { c->mCamera->asBinder()->linkToDeath(c); diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 8237c66b0e..fdf20ffac0 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -56,12 +56,15 @@ public: } // connect to camera service - virtual sp connect(const sp& cameraClient, int cameraId) + virtual sp connect(const sp& cameraClient, int cameraId, + const String16 &clientPackageName, int clientUid) { Parcel data, reply; data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeStrongBinder(cameraClient->asBinder()); data.writeInt32(cameraId); + data.writeString16(clientPackageName); + data.writeInt32(clientUid); remote()->transact(BnCameraService::CONNECT, data, &reply); return interface_cast(reply.readStrongBinder()); } @@ -103,8 +106,13 @@ status_t BnCameraService::onTransact( } break; case CONNECT: { CHECK_INTERFACE(ICameraService, data, reply); - sp cameraClient = interface_cast(data.readStrongBinder()); - sp camera = connect(cameraClient, data.readInt32()); + sp cameraClient = + interface_cast(data.readStrongBinder()); + int32_t cameraId = data.readInt32(); + const String16 clientName = data.readString16(); + int32_t clientUid = data.readInt32(); + sp camera = connect(cameraClient, cameraId, + clientName, clientUid); reply->writeStrongBinder(camera->asBinder()); return NO_ERROR; } break; diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index 45c3f7b7aa..b7a40c2b1f 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -264,7 +264,8 @@ int main(int argc, char **argv) { #endif #if 0 - CameraSource *source = CameraSource::Create(); + CameraSource *source = CameraSource::Create( + String16(argv[0], strlen(argv[0]))); source->start(); printf("source = %p\n", source); diff --git a/include/camera/Camera.h b/include/camera/Camera.h index 8b87de606f..be2b7f43b8 100644 --- a/include/camera/Camera.h +++ b/include/camera/Camera.h @@ -53,6 +53,7 @@ class ICamera; class Surface; class Mutex; class String8; +class String16; // ref-counted object for callbacks class CameraListener: virtual public RefBase @@ -67,12 +68,19 @@ public: class Camera : public BnCameraClient, public IBinder::DeathRecipient { public: + enum { + USE_CALLING_UID = -1 + }; + // construct a camera client from an existing remote static sp create(const sp& camera); static int32_t getNumberOfCameras(); static status_t getCameraInfo(int cameraId, struct CameraInfo* cameraInfo); - static sp connect(int cameraId); + static sp connect(int cameraId, + const String16& clientPackageName, + int clientUid); + virtual ~Camera(); void init(); diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index 11d7b6567a..aa64243246 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -37,18 +37,28 @@ public: CONNECT_PRO }; + enum { + USE_CALLING_UID = -1 + }; + public: DECLARE_META_INTERFACE(CameraService); virtual int32_t getNumberOfCameras() = 0; virtual status_t getCameraInfo(int cameraId, struct CameraInfo* cameraInfo) = 0; - virtual sp connect(const sp& cameraClient, - int cameraId) = 0; + /** + * clientPackageName and clientUid are used for permissions checking. if + * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only + * trusted callers can set a clientUid other than USE_CALLING_UID. + */ + virtual sp connect(const sp& cameraClient, + int cameraId, + const String16& clientPackageName, + int clientUid) = 0; - virtual sp - connect(const sp& cameraCb, - int cameraId) = 0; + virtual sp connect(const sp& cameraCb, + int cameraId) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h index 54af0d37c5..8d7f11de6c 100644 --- a/include/media/IMediaRecorder.h +++ b/include/media/IMediaRecorder.h @@ -47,6 +47,7 @@ public: virtual status_t setVideoFrameRate(int frames_per_second) = 0; virtual status_t setParameters(const String8& params) = 0; virtual status_t setListener(const sp& listener) = 0; + virtual status_t setClientName(const String16& clientName) = 0; virtual status_t prepare() = 0; virtual status_t getMaxAmplitude(int* max) = 0; virtual status_t start() = 0; diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h index 803bc6436d..8dd40d2a3f 100644 --- a/include/media/MediaRecorderBase.h +++ b/include/media/MediaRecorderBase.h @@ -48,6 +48,7 @@ struct MediaRecorderBase { virtual status_t setOutputFileAuxiliary(int fd) {return INVALID_OPERATION;} virtual status_t setParameters(const String8& params) = 0; virtual status_t setListener(const sp& listener) = 0; + virtual status_t setClientName(const String16& clientName) = 0; virtual status_t prepare() = 0; virtual status_t start() = 0; virtual status_t stop() = 0; diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h index da6b50773f..3b33479a64 100644 --- a/include/media/mediarecorder.h +++ b/include/media/mediarecorder.h @@ -219,6 +219,7 @@ public: status_t setVideoFrameRate(int frames_per_second); status_t setParameters(const String8& params); status_t setListener(const sp& listener); + status_t setClientName(const String16& clientName); status_t prepare(); status_t getMaxAmplitude(int* max); status_t start(); diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index 6d6b8a9669..cf38b14702 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace android { @@ -39,9 +40,11 @@ public: * settings (such as video size, frame rate, color format, etc) * from the default camera. * + * @param clientName The package/process name of the client application. + * This is used for permissions checking. * @return NULL on error. */ - static CameraSource *Create(); + static CameraSource *Create(const String16 &clientName); /** * Factory method to create a new CameraSource. @@ -52,7 +55,11 @@ public: * * @param cameraId the id of the camera that the source will connect * to if camera is NULL; otherwise ignored. - * + * @param clientName the package/process name of the camera-using + * application if camera is NULL; otherwise ignored. Used for + * permissions checking. + * @param clientUid the UID of the camera-using application if camera is + * NULL; otherwise ignored. Used for permissions checking. * @param videoSize the dimension (in pixels) of the video frame * @param frameRate the target frames per second * @param surface the preview surface for display where preview @@ -71,6 +78,8 @@ public: static CameraSource *CreateFromCamera(const sp &camera, const sp &proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t frameRate, const sp& surface, @@ -158,7 +167,7 @@ protected: int64_t mTimeBetweenFrameCaptureUs; CameraSource(const sp& camera, const sp& proxy, - int32_t cameraId, + int32_t cameraId, const String16& clientName, uid_t clientUid, Size videoSize, int32_t frameRate, const sp& surface, bool storeMetaDataInVideoBuffers); @@ -198,17 +207,20 @@ private: status_t init(const sp& camera, const sp& proxy, - int32_t cameraId, Size videoSize, int32_t frameRate, - bool storeMetaDataInVideoBuffers); + int32_t cameraId, const String16& clientName, uid_t clientUid, + Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers); status_t initWithCameraAccess( const sp& camera, const sp& proxy, - int32_t cameraId, Size videoSize, int32_t frameRate, - bool storeMetaDataInVideoBuffers); + int32_t cameraId, const String16& clientName, uid_t clientUid, + Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers); status_t isCameraAvailable(const sp& camera, const sp& proxy, - int32_t cameraId); + int32_t cameraId, + const String16& clientName, + uid_t clientUid); + status_t isCameraColorFormatSupported(const CameraParameters& params); status_t configureCamera(CameraParameters* params, int32_t width, int32_t height, diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h index 0936da2f3e..774772bb59 100644 --- a/include/media/stagefright/CameraSourceTimeLapse.h +++ b/include/media/stagefright/CameraSourceTimeLapse.h @@ -22,6 +22,7 @@ #include #include +#include namespace android { @@ -35,6 +36,8 @@ public: const sp &camera, const sp &proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t videoFrameRate, const sp& surface, @@ -108,6 +111,8 @@ private: const sp &camera, const sp &proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t videoFrameRate, const sp& surface, diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index fdbc747ace..c935d971e3 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -51,7 +51,8 @@ enum { SET_PARAMETERS, SET_PREVIEW_SURFACE, SET_CAMERA, - SET_LISTENER + SET_LISTENER, + SET_CLIENT_NAME }; class BpMediaRecorder: public BpInterface @@ -217,6 +218,16 @@ public: return reply.readInt32(); } + status_t setClientName(const String16& clientName) + { + ALOGV("setClientName(%s)", String8(clientName).string()); + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); + data.writeString16(clientName); + remote()->transact(SET_CLIENT_NAME, data, &reply); + return reply.readInt32(); + } + status_t prepare() { ALOGV("prepare"); @@ -423,6 +434,12 @@ status_t BnMediaRecorder::onTransact( reply->writeInt32(setListener(listener)); return NO_ERROR; } break; + case SET_CLIENT_NAME: { + ALOGV("SET_CLIENT_NAME"); + CHECK_INTERFACE(IMediaRecorder, data, reply); + reply->writeInt32(setClientName(data.readString16())); + return NO_ERROR; + } case SET_PREVIEW_SURFACE: { ALOGV("SET_PREVIEW_SURFACE"); CHECK_INTERFACE(IMediaRecorder, data, reply); diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 660b1b2d32..3ac98cc2ae 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -656,6 +656,27 @@ status_t MediaRecorder::setListener(const sp& listener) return NO_ERROR; } +status_t MediaRecorder::setClientName(const String16& clientName) +{ + ALOGV("setClientName"); + if (mMediaRecorder == NULL) { + ALOGE("media recorder is not initialized yet"); + return INVALID_OPERATION; + } + bool isInvalidState = (mCurrentState & + (MEDIA_RECORDER_PREPARED | + MEDIA_RECORDER_RECORDING | + MEDIA_RECORDER_ERROR)); + if (isInvalidState) { + ALOGE("setClientName is called in an invalid state: %d", mCurrentState); + return INVALID_OPERATION; + } + + mMediaRecorder->setClientName(clientName); + + return NO_ERROR; +} + void MediaRecorder::notify(int msg, int ext1, int ext2) { ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index c6d8b7668c..a52b23894a 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -99,7 +99,7 @@ status_t MediaRecorderClient::setVideoSource(int vs) return PERMISSION_DENIED; } Mutex::Autolock lock(mLock); - if (mRecorder == NULL) { + if (mRecorder == NULL) { ALOGE("recorder is not initialized"); return NO_INIT; } @@ -325,6 +325,16 @@ status_t MediaRecorderClient::setListener(const sp& listen return mRecorder->setListener(listener); } +status_t MediaRecorderClient::setClientName(const String16& clientName) { + ALOGV("setClientName(%s)", String8(clientName).string()); + Mutex::Autolock lock(mLock); + if (mRecorder == NULL) { + ALOGE("recorder is not initialized"); + return NO_INIT; + } + return mRecorder->setClientName(clientName); +} + status_t MediaRecorderClient::dump(int fd, const Vector& args) const { if (mRecorder != NULL) { return mRecorder->dump(fd, args); diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h index 56239177c1..bd0eaf1459 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.h +++ b/media/libmediaplayerservice/MediaRecorderClient.h @@ -46,6 +46,7 @@ public: virtual status_t setParameters(const String8& params); virtual status_t setListener( const sp& listener); + virtual status_t setClientName(const String16& clientName); virtual status_t prepare(); virtual status_t getMaxAmplitude(int* max); virtual status_t start(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 497dda65e9..f5708566b1 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -730,6 +730,12 @@ status_t StagefrightRecorder::setListener(const sp &listen return OK; } +status_t StagefrightRecorder::setClientName(const String16& clientName) { + mClientName = clientName; + + return OK; +} + status_t StagefrightRecorder::prepare() { return OK; } @@ -737,6 +743,8 @@ status_t StagefrightRecorder::prepare() { status_t StagefrightRecorder::start() { CHECK_GE(mOutputFd, 0); + // Get UID here for permission checking + mClientUid = IPCThreadState::self()->getCallingUid(); if (mWriter != NULL) { ALOGE("File writer is not avaialble"); return UNKNOWN_ERROR; @@ -1312,13 +1320,14 @@ status_t StagefrightRecorder::setupCameraSource( } mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera( - mCamera, mCameraProxy, mCameraId, + mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, videoSize, mFrameRate, mPreviewSurface, mTimeBetweenTimeLapseFrameCaptureUs); *cameraSource = mCameraSourceTimeLapse; } else { *cameraSource = CameraSource::CreateFromCamera( - mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate, + mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, + videoSize, mFrameRate, mPreviewSurface, true /*storeMetaDataInVideoBuffers*/); } mCamera.clear(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 351efd4571..fbe6fa6de4 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -56,6 +56,7 @@ struct StagefrightRecorder : public MediaRecorderBase { virtual status_t setOutputFile(int fd, int64_t offset, int64_t length); virtual status_t setParameters(const String8& params); virtual status_t setListener(const sp& listener); + virtual status_t setClientName(const String16& clientName); virtual status_t prepare(); virtual status_t start(); virtual status_t pause(); @@ -72,6 +73,8 @@ private: sp mCameraProxy; sp mPreviewSurface; sp mListener; + String16 mClientName; + uid_t mClientUid; sp mWriter; int mOutputFd; sp mAudioSourceNode; diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index efd7af7e8a..f8557d0204 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -121,13 +121,14 @@ static int32_t getColorFormat(const char* colorFormat) { CHECK(!"Unknown color format"); } -CameraSource *CameraSource::Create() { +CameraSource *CameraSource::Create(const String16 &clientName) { Size size; size.width = -1; size.height = -1; sp camera; - return new CameraSource(camera, NULL, 0, size, -1, NULL, false); + return new CameraSource(camera, NULL, 0, clientName, -1, + size, -1, NULL, false); } // static @@ -135,14 +136,16 @@ CameraSource *CameraSource::CreateFromCamera( const sp& camera, const sp& proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t frameRate, const sp& surface, bool storeMetaDataInVideoBuffers) { CameraSource *source = new CameraSource(camera, proxy, cameraId, - videoSize, frameRate, surface, - storeMetaDataInVideoBuffers); + clientName, clientUid, videoSize, frameRate, surface, + storeMetaDataInVideoBuffers); return source; } @@ -150,6 +153,8 @@ CameraSource::CameraSource( const sp& camera, const sp& proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t frameRate, const sp& surface, @@ -173,6 +178,7 @@ CameraSource::CameraSource( mVideoSize.height = -1; mInitCheck = init(camera, proxy, cameraId, + clientName, clientUid, videoSize, frameRate, storeMetaDataInVideoBuffers); if (mInitCheck != OK) releaseCamera(); @@ -184,10 +190,10 @@ status_t CameraSource::initCheck() const { status_t CameraSource::isCameraAvailable( const sp& camera, const sp& proxy, - int32_t cameraId) { + int32_t cameraId, const String16& clientName, uid_t clientUid) { if (camera == 0) { - mCamera = Camera::connect(cameraId); + mCamera = Camera::connect(cameraId, clientName, clientUid); if (mCamera == 0) return -EBUSY; mCameraFlags &= ~FLAGS_HOT_CAMERA; } else { @@ -469,6 +475,8 @@ status_t CameraSource::init( const sp& camera, const sp& proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers) { @@ -476,7 +484,7 @@ status_t CameraSource::init( ALOGV("init"); status_t err = OK; int64_t token = IPCThreadState::self()->clearCallingIdentity(); - err = initWithCameraAccess(camera, proxy, cameraId, + err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid, videoSize, frameRate, storeMetaDataInVideoBuffers); IPCThreadState::self()->restoreCallingIdentity(token); @@ -487,13 +495,16 @@ status_t CameraSource::initWithCameraAccess( const sp& camera, const sp& proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers) { ALOGV("initWithCameraAccess"); status_t err = OK; - if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) { + if ((err = isCameraAvailable(camera, proxy, cameraId, + clientName, clientUid)) != OK) { ALOGE("Camera connection could not be established."); return err; } diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 26ce7ae9a8..2ed2223110 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -36,6 +36,8 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera( const sp &camera, const sp &proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t videoFrameRate, const sp& surface, @@ -43,6 +45,7 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera( CameraSourceTimeLapse *source = new CameraSourceTimeLapse(camera, proxy, cameraId, + clientName, clientUid, videoSize, videoFrameRate, surface, timeBetweenFrameCaptureUs); @@ -59,11 +62,14 @@ CameraSourceTimeLapse::CameraSourceTimeLapse( const sp& camera, const sp& proxy, int32_t cameraId, + const String16& clientName, + uid_t clientUid, Size videoSize, int32_t videoFrameRate, const sp& surface, int64_t timeBetweenFrameCaptureUs) - : CameraSource(camera, proxy, cameraId, videoSize, videoFrameRate, surface, true), + : CameraSource(camera, proxy, cameraId, clientName, clientUid, + videoSize, videoFrameRate, surface, true), mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), mLastTimeLapseFrameRealTimestampUs(0), mSkipCurrentFrame(false) { diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index e8b3b7f673..38d6949eee 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -40,12 +40,14 @@ static int getCallingPid() { Camera2Client::Camera2Client(const sp& cameraService, const sp& cameraClient, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid): - Client(cameraService, cameraClient, - cameraId, cameraFacing, clientPid, servicePid), + Client(cameraService, cameraClient, clientPackageName, + cameraId, cameraFacing, clientPid, clientUid, servicePid), mSharedCameraClient(cameraClient), mParameters(cameraId, cameraFacing) { @@ -73,6 +75,12 @@ status_t Camera2Client::initialize(camera_module_t *module) ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId); status_t res; + // Verify ops permissions + res = startCameraOps(); + if (res != OK) { + return res; + } + res = mDevice->initialize(module); if (res != OK) { ALOGE("%s: Camera %d: unable to initialize device: %s (%d)", @@ -741,8 +749,7 @@ void Camera2Client::stopPreviewL() { switch (state) { case Parameters::DISCONNECTED: - ALOGE("%s: Camera %d: Call before initialized", - __FUNCTION__, mCameraId); + // Nothing to do. break; case Parameters::STOPPED: case Parameters::VIDEO_SNAPSHOT: diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index a4d4478356..173b65e395 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -72,9 +72,11 @@ public: Camera2Client(const sp& cameraService, const sp& cameraClient, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid); virtual ~Camera2Client(); diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp index f67c9f4cae..90f8f40bdd 100644 --- a/services/camera/libcameraservice/CameraClient.cpp +++ b/services/camera/libcameraservice/CameraClient.cpp @@ -35,9 +35,12 @@ static int getCallingPid() { CameraClient::CameraClient(const sp& cameraService, const sp& cameraClient, - int cameraId, int cameraFacing, int clientPid, int servicePid): - Client(cameraService, cameraClient, - cameraId, cameraFacing, clientPid, servicePid) + const String16& clientPackageName, + int cameraId, int cameraFacing, + int clientPid, int clientUid, + int servicePid): + Client(cameraService, cameraClient, clientPackageName, + cameraId, cameraFacing, clientPid, clientUid, servicePid) { int callingPid = getCallingPid(); LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId); @@ -57,10 +60,17 @@ CameraClient::CameraClient(const sp& cameraService, status_t CameraClient::initialize(camera_module_t *module) { int callingPid = getCallingPid(); + status_t res; + LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId); + // Verify ops permissions + res = startCameraOps(); + if (res != OK) { + return res; + } + char camera_device_name[10]; - status_t res; snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId); mHardware = new CameraHardwareInterface(camera_device_name); diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h index 74829ce1e4..00dc90c270 100644 --- a/services/camera/libcameraservice/CameraClient.h +++ b/services/camera/libcameraservice/CameraClient.h @@ -53,9 +53,11 @@ public: // Interface used by CameraService CameraClient(const sp& cameraService, const sp& cameraClient, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + int clientUid, int servicePid); ~CameraClient(); diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index eb8bc05f58..ec1c3f04a3 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -72,7 +73,7 @@ static int getCallingUid() { static CameraService *gCameraService; CameraService::CameraService() -:mSoundRef(0), mModule(0) + :mSoundRef(0), mModule(0) { ALOGI("CameraService started (pid=%d)", getpid()); gCameraService = this; @@ -155,10 +156,27 @@ int CameraService::getDeviceVersion(int cameraId, int* facing) { } sp CameraService::connect( - const sp& cameraClient, int cameraId) { + const sp& cameraClient, + int cameraId, + const String16& clientPackageName, + int clientUid) { + + String8 clientName8(clientPackageName); int callingPid = getCallingPid(); - LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId); + LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid, + clientName8.string(), cameraId); + + if (clientUid == USE_CALLING_UID) { + clientUid = getCallingUid(); + } else { + // We only trust our own process to forward client UIDs + if (callingPid != getpid()) { + ALOGE("CameraService::connect X (pid %d) rejected (don't trust clientUid)", + callingPid); + return NULL; + } + } if (!mModule) { ALOGE("Camera HAL module not loaded"); @@ -208,8 +226,10 @@ sp CameraService::connect( would be fine */ if (mBusy[cameraId]) { - ALOGW("CameraService::connect X (pid %d) rejected" - " (camera %d is still busy).", callingPid, cameraId); + + ALOGW("CameraService::connect X (pid %d, \"%s\") rejected" + " (camera %d is still busy).", callingPid, + clientName8.string(), cameraId); return NULL; } @@ -218,13 +238,15 @@ sp CameraService::connect( switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: - client = new CameraClient(this, cameraClient, cameraId, - facing, callingPid, getpid()); + client = new CameraClient(this, cameraClient, + clientPackageName, cameraId, + facing, callingPid, clientUid, getpid()); break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: - client = new Camera2Client(this, cameraClient, cameraId, - facing, callingPid, getpid()); + client = new Camera2Client(this, cameraClient, + clientPackageName, cameraId, + facing, callingPid, clientUid, getpid()); break; case -1: ALOGE("Invalid camera id %d", cameraId); @@ -283,8 +305,8 @@ sp CameraService::connect( break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: - client = new ProCamera2Client(this, cameraCb, cameraId, - facing, callingPid, getpid()); + client = new ProCamera2Client(this, cameraCb, String16(), + cameraId, facing, callingPid, USE_CALLING_UID, getpid()); break; case -1: ALOGE("Invalid camera id %d", cameraId); @@ -302,7 +324,8 @@ sp CameraService::connect( cameraCb->asBinder()->linkToDeath(this); - LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid()); + LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId, + getpid()); return client; @@ -522,10 +545,15 @@ void CameraService::playSound(sound_kind kind) { CameraService::Client::Client(const sp& cameraService, const sp& cameraClient, - int cameraId, int cameraFacing, int clientPid, int servicePid) : + const String16& clientPackageName, + int cameraId, int cameraFacing, + int clientPid, uid_t clientUid, + int servicePid) : CameraService::BasicClient(cameraService, cameraClient->asBinder(), - cameraId, cameraFacing, - clientPid, servicePid) + clientPackageName, + cameraId, cameraFacing, + clientPid, clientUid, + servicePid) { int callingPid = getCallingPid(); LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId); @@ -534,6 +562,7 @@ CameraService::Client::Client(const sp& cameraService, cameraService->setCameraBusy(cameraId); cameraService->loadSound(); + LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId); } @@ -542,23 +571,27 @@ CameraService::Client::~Client() { mDestructionStarted = true; mCameraService->releaseSound(); - + finishCameraOps(); // unconditionally disconnect. function is idempotent Client::disconnect(); } CameraService::BasicClient::BasicClient(const sp& cameraService, - const sp& remoteCallback, - int cameraId, int cameraFacing, - int clientPid, int servicePid) + const sp& remoteCallback, + const String16& clientPackageName, + int cameraId, int cameraFacing, + int clientPid, uid_t clientUid, + int servicePid): + mClientPackageName(clientPackageName) { mCameraService = cameraService; mRemoteCallback = remoteCallback; mCameraId = cameraId; mCameraFacing = cameraFacing; mClientPid = clientPid; + mClientUid = clientUid; mServicePid = servicePid; - + mOpsActive = false; mDestructionStarted = false; } @@ -570,6 +603,66 @@ void CameraService::BasicClient::disconnect() { mCameraService->removeClientByRemote(mRemoteCallback); } +status_t CameraService::BasicClient::startCameraOps() { + int32_t res; + + mOpsCallback = new OpsCallback(this); + + mAppOpsManager.startWatchingMode(AppOpsManager::OP_CAMERA, + mClientPackageName, mOpsCallback); + res = mAppOpsManager.startOp(AppOpsManager::OP_CAMERA, + mClientUid, mClientPackageName); + + if (res != AppOpsManager::MODE_ALLOWED) { + ALOGI("Camera %d: Access for \"%s\" has been revoked", + mCameraId, String8(mClientPackageName).string()); + return PERMISSION_DENIED; + } + mOpsActive = true; + return OK; +} + +status_t CameraService::BasicClient::finishCameraOps() { + if (mOpsActive) { + mAppOpsManager.finishOp(AppOpsManager::OP_CAMERA, mClientUid, + mClientPackageName); + mOpsActive = false; + } + mAppOpsManager.stopWatchingMode(mOpsCallback); + mOpsCallback.clear(); + + return OK; +} + +void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) { + String8 name(packageName); + String8 myName(mClientPackageName); + + if (op != AppOpsManager::OP_CAMERA) { + ALOGW("Unexpected app ops notification received: %d", op); + return; + } + + int32_t res; + res = mAppOpsManager.checkOp(AppOpsManager::OP_CAMERA, + mClientUid, mClientPackageName); + ALOGV("checkOp returns: %d, %s ", res, + res == AppOpsManager::MODE_ALLOWED ? "ALLOWED" : + res == AppOpsManager::MODE_IGNORED ? "IGNORED" : + res == AppOpsManager::MODE_ERRORED ? "ERRORED" : + "UNKNOWN"); + + if (res != AppOpsManager::MODE_ALLOWED) { + ALOGI("Camera %d: Access for \"%s\" revoked", mCameraId, + myName.string()); + // Reset the client PID to allow server-initiated disconnect, + // and to prevent further calls by client. + mClientPid = getCallingPid(); + notifyError(); + disconnect(); + } +} + // ---------------------------------------------------------------------------- Mutex* CameraService::Client::getClientLockFromCookie(void* user) { @@ -592,25 +685,43 @@ CameraService::Client* CameraService::Client::getClientFromCookie(void* user) { return client; } +void CameraService::Client::notifyError() { + mCameraClient->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0); +} + // NOTE: function is idempotent void CameraService::Client::disconnect() { BasicClient::disconnect(); mCameraService->setCameraFree(mCameraId); } +CameraService::Client::OpsCallback::OpsCallback(wp client): + mClient(client) { +} + +void CameraService::Client::OpsCallback::opChanged(int32_t op, + const String16& packageName) { + sp client = mClient.promote(); + if (client != NULL) { + client->opChanged(op, packageName); + } +} + // ---------------------------------------------------------------------------- // IProCamera // ---------------------------------------------------------------------------- CameraService::ProClient::ProClient(const sp& cameraService, - const sp& remoteCallback, - int cameraId, - int cameraFacing, - int clientPid, - int servicePid) - : CameraService::BasicClient(cameraService, remoteCallback->asBinder(), - cameraId, cameraFacing, - clientPid, servicePid) + const sp& remoteCallback, + const String16& clientPackageName, + int cameraId, + int cameraFacing, + int clientPid, + uid_t clientUid, + int servicePid) + : CameraService::BasicClient(cameraService, remoteCallback->asBinder(), + clientPackageName, cameraId, cameraFacing, + clientPid, clientUid, servicePid) { mRemoteCallback = remoteCallback; } @@ -683,6 +794,10 @@ status_t CameraService::ProClient::cancelStream(int streamId) { return INVALID_OPERATION; } +void CameraService::ProClient::notifyError() { + ALOGE("%s: not implemented yet", __FUNCTION__); +} + // ---------------------------------------------------------------------------- static const int kDumpLockRetries = 50; diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 9e0f62a53f..b017505591 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -19,7 +19,9 @@ #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H #include +#include #include +#include #include #include @@ -54,9 +56,11 @@ public: virtual int32_t getNumberOfCameras(); virtual status_t getCameraInfo(int cameraId, struct CameraInfo* cameraInfo); - virtual sp connect(const sp& cameraClient, int cameraId); - virtual sp - connect(const sp& cameraCb, int cameraId); + + virtual sp connect(const sp& cameraClient, int cameraId, + const String16& clientPackageName, int clientUid); + virtual sp connect(const sp& cameraCb, + int cameraId); // Extra permissions checks virtual status_t onTransact(uint32_t code, const Parcel& data, @@ -100,9 +104,11 @@ public: protected: BasicClient(const sp& cameraService, const sp& remoteCallback, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid); virtual ~BasicClient(); @@ -117,12 +123,41 @@ public: sp mCameraService; // immutable after constructor int mCameraId; // immutable after constructor int mCameraFacing; // immutable after constructor + const String16 mClientPackageName; pid_t mClientPid; + uid_t mClientUid; // immutable after constructor pid_t mServicePid; // immutable after constructor // - The app-side Binder interface to receive callbacks from us wp mRemoteCallback; // immutable after constructor - }; + + // permissions management + status_t startCameraOps(); + status_t finishCameraOps(); + + // Notify client about a fatal error + virtual void notifyError() = 0; + private: + AppOpsManager mAppOpsManager; + + class OpsCallback : public BnAppOpsCallback { + public: + OpsCallback(wp client); + virtual void opChanged(int32_t op, const String16& packageName); + + private: + wp mClient; + + }; // class OpsCallback + + sp mOpsCallback; + // Track whether startCameraOps was called successfully, to avoid + // finishing what we didn't start. + bool mOpsActive; + + // IAppOpsCallback interface, indirected through opListener + virtual void opChanged(int32_t op, const String16& packageName); + }; // class BasicClient class Client : public BnCamera, public BasicClient { @@ -153,9 +188,11 @@ public: // Interface used by CameraService Client(const sp& cameraService, const sp& cameraClient, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid); ~Client(); @@ -169,19 +206,24 @@ public: // convert client from cookie. Client lock should be acquired before getting Client. static Client* getClientFromCookie(void* user); + virtual void notifyError(); + // Initialized in constructor // - The app-side Binder interface to receive callbacks from us sp mCameraClient; - }; + + }; // class Client class ProClient : public BnProCameraUser, public BasicClient { public: ProClient(const sp& cameraService, const sp& remoteCallback, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid); virtual ~ProClient(); @@ -217,9 +259,10 @@ public: virtual status_t cancelStream(int streamId); protected: - sp mRemoteCallback; + virtual void notifyError(); - }; + sp mRemoteCallback; + }; // class ProClient private: diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp index c264e2adbb..eda301240a 100644 --- a/services/camera/libcameraservice/ProCamera2Client.cpp +++ b/services/camera/libcameraservice/ProCamera2Client.cpp @@ -43,12 +43,14 @@ static int getCallingUid() { ProCamera2Client::ProCamera2Client(const sp& cameraService, const sp& remoteCallback, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid): - ProClient(cameraService, remoteCallback, - cameraId, cameraFacing, clientPid, servicePid), + ProClient(cameraService, remoteCallback, clientPackageName, + cameraId, cameraFacing, clientPid, clientUid, servicePid), mSharedCameraCallbacks(remoteCallback) { ATRACE_CALL(); diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h index cd0a2aef76..9f514f4132 100644 --- a/services/camera/libcameraservice/ProCamera2Client.h +++ b/services/camera/libcameraservice/ProCamera2Client.h @@ -77,9 +77,11 @@ public: ProCamera2Client(const sp& cameraService, const sp& remoteCallback, + const String16& clientPackageName, int cameraId, int cameraFacing, int clientPid, + uid_t clientUid, int servicePid); virtual ~ProCamera2Client(); -- 2.11.0