summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2013-02-19 10:40:14 -0800
committerEino-Ville Talvala <etalvala@google.com>2013-02-25 16:11:41 -0800
commit48af7e8dd40883d6154e7029d9500072b551b5fa (patch)
treece8b71d67a3313dc19c0691bc1b26d1244a106b4 /services
parent68e6e24cb6cdd66c2209774c4871a2c47e8bbc8b (diff)
downloadframeworks_av-48af7e8dd40883d6154e7029d9500072b551b5fa.zip
frameworks_av-48af7e8dd40883d6154e7029d9500072b551b5fa.tar.gz
frameworks_av-48af7e8dd40883d6154e7029d9500072b551b5fa.tar.bz2
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
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/Camera2Client.cpp15
-rw-r--r--services/camera/libcameraservice/Camera2Client.h2
-rw-r--r--services/camera/libcameraservice/CameraClient.cpp18
-rw-r--r--services/camera/libcameraservice/CameraClient.h2
-rw-r--r--services/camera/libcameraservice/CameraService.cpp171
-rw-r--r--services/camera/libcameraservice/CameraService.h57
-rw-r--r--services/camera/libcameraservice/ProCamera2Client.cpp6
-rw-r--r--services/camera/libcameraservice/ProCamera2Client.h2
8 files changed, 228 insertions, 45 deletions
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index e8b3b7f..38d6949 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>& cameraService,
const sp<ICameraClient>& 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 a4d4478..173b65e 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -72,9 +72,11 @@ public:
Camera2Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& 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 f67c9f4..90f8f40 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>& cameraService,
const sp<ICameraClient>& 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>& 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 74829ce..00dc90c 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>& cameraService,
const sp<ICameraClient>& 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 eb8bc05..ec1c3f0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <pthread.h>
+#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
@@ -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<ICamera> CameraService::connect(
- const sp<ICameraClient>& cameraClient, int cameraId) {
+ const sp<ICameraClient>& 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<ICamera> 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<ICamera> 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<IProCameraUser> 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<IProCameraUser> 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>& cameraService,
const sp<ICameraClient>& 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,
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>& cameraService,
- const sp<IBinder>& remoteCallback,
- int cameraId, int cameraFacing,
- int clientPid, int servicePid)
+ const sp<IBinder>& 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<BasicClient> client):
+ mClient(client) {
+}
+
+void CameraService::Client::OpsCallback::opChanged(int32_t op,
+ const String16& packageName) {
+ sp<BasicClient> client = mClient.promote();
+ if (client != NULL) {
+ client->opChanged(op, packageName);
+ }
+}
+
// ----------------------------------------------------------------------------
// IProCamera
// ----------------------------------------------------------------------------
CameraService::ProClient::ProClient(const sp<CameraService>& cameraService,
- const sp<IProCameraCallbacks>& remoteCallback,
- int cameraId,
- int cameraFacing,
- int clientPid,
- int servicePid)
- : CameraService::BasicClient(cameraService, remoteCallback->asBinder(),
- cameraId, cameraFacing,
- clientPid, servicePid)
+ const sp<IProCameraCallbacks>& 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 9e0f62a..b017505 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,7 +19,9 @@
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#include <utils/Vector.h>
+#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
+#include <binder/IAppOpsCallback.h>
#include <camera/ICameraService.h>
#include <hardware/camera.h>
@@ -54,9 +56,11 @@ public:
virtual int32_t getNumberOfCameras();
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
- virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
- virtual sp<IProCameraUser>
- connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId);
+
+ virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
+ const String16& clientPackageName, int clientUid);
+ virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& 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>& cameraService,
const sp<IBinder>& remoteCallback,
+ const String16& clientPackageName,
int cameraId,
int cameraFacing,
int clientPid,
+ uid_t clientUid,
int servicePid);
virtual ~BasicClient();
@@ -117,12 +123,41 @@ public:
sp<CameraService> 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<IBinder> 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<BasicClient> client);
+ virtual void opChanged(int32_t op, const String16& packageName);
+
+ private:
+ wp<BasicClient> mClient;
+
+ }; // class OpsCallback
+
+ sp<OpsCallback> 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>& cameraService,
const sp<ICameraClient>& 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<ICameraClient> mCameraClient;
- };
+
+ }; // class Client
class ProClient : public BnProCameraUser, public BasicClient {
public:
ProClient(const sp<CameraService>& cameraService,
const sp<IProCameraCallbacks>& 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<IProCameraCallbacks> mRemoteCallback;
+ virtual void notifyError();
- };
+ sp<IProCameraCallbacks> mRemoteCallback;
+ }; // class ProClient
private:
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index c264e2a..eda3012 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>& cameraService,
const sp<IProCameraCallbacks>& 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 cd0a2ae..9f514f4 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -77,9 +77,11 @@ public:
ProCamera2Client(const sp<CameraService>& cameraService,
const sp<IProCameraCallbacks>& remoteCallback,
+ const String16& clientPackageName,
int cameraId,
int cameraFacing,
int clientPid,
+ uid_t clientUid,
int servicePid);
virtual ~ProCamera2Client();