summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-20 17:15:11 -0800
committerIgor Murashkin <iam@google.com>2013-02-22 10:50:14 -0800
commit634a51509ee50475f3e9f8ccf897e90fc72ded31 (patch)
tree5d9fc437299a8b5adc391eb721d55c9df00afc87 /services/camera/libcameraservice
parent1d88023e1de6b9f370eb4be944dd9c4480d01f11 (diff)
downloadframeworks_av-634a51509ee50475f3e9f8ccf897e90fc72ded31.zip
frameworks_av-634a51509ee50475f3e9f8ccf897e90fc72ded31.tar.gz
frameworks_av-634a51509ee50475f3e9f8ccf897e90fc72ded31.tar.bz2
Camera: Add ProCamera private binder interface for an API2-light functionality
Change-Id: I2af7a807c99df75ea659e6e6acc9c4fca6a56274
Diffstat (limited to 'services/camera/libcameraservice')
-rw-r--r--services/camera/libcameraservice/CameraService.cpp296
-rw-r--r--services/camera/libcameraservice/CameraService.h147
2 files changed, 390 insertions, 53 deletions
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b1c594a..4941965 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -79,6 +79,8 @@ CameraService::CameraService()
void CameraService::onFirstRef()
{
+ LOG1("CameraService::onFirstRef");
+
BnCameraService::onFirstRef();
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
@@ -131,6 +133,26 @@ status_t CameraService::getCameraInfo(int cameraId,
return rc;
}
+int CameraService::getDeviceVersion(int cameraId, int* facing) {
+ struct camera_info info;
+ if (mModule->get_camera_info(cameraId, &info) != OK) {
+ return -1;
+ }
+
+ int deviceVersion;
+ if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_0) {
+ deviceVersion = info.device_version;
+ } else {
+ deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+ }
+
+ if (facing) {
+ *facing = info.facing;
+ }
+
+ return deviceVersion;
+}
+
sp<ICamera> CameraService::connect(
const sp<ICameraClient>& cameraClient, int cameraId) {
int callingPid = getCallingPid();
@@ -175,34 +197,96 @@ sp<ICamera> CameraService::connect(
mClient[cameraId].clear();
}
+ /*
+ mBusy is set to false as the last step of the Client destructor,
+ after which it is guaranteed that the Client destructor has finished (
+ including any inherited destructors)
+
+ We only need this for a Client subclasses since we don't allow
+ multiple Clents to be opened concurrently, but multiple BasicClient
+ would be fine
+ */
if (mBusy[cameraId]) {
ALOGW("CameraService::connect X (pid %d) rejected"
" (camera %d is still busy).", callingPid, cameraId);
return NULL;
}
- struct camera_info info;
- if (mModule->get_camera_info(cameraId, &info) != OK) {
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ client = new CameraClient(this, cameraClient, cameraId,
+ facing, callingPid, 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());
+ break;
+ case -1:
ALOGE("Invalid camera id %d", cameraId);
return NULL;
+ default:
+ ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+ return NULL;
}
- int deviceVersion;
- if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {
- deviceVersion = info.device_version;
- } else {
- deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+ if (client->initialize(mModule) != OK) {
+ return NULL;
+ }
+
+ cameraClient->asBinder()->linkToDeath(this);
+
+ mClient[cameraId] = client;
+ LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
+ return client;
+}
+
+sp<IProCameraUser> CameraService::connect(
+ const sp<IProCameraCallbacks>& cameraCb,
+ int cameraId)
+{
+ int callingPid = getCallingPid();
+
+ LOG1("CameraService::connectPro E (pid %d, id %d)", callingPid, cameraId);
+
+ if (!mModule) {
+ ALOGE("Camera HAL module not loaded");
+ return NULL;
+ }
+
+ sp<ProClient> client;
+ if (cameraId < 0 || cameraId >= mNumberOfCameras) {
+ ALOGE("CameraService::connectPro X (pid %d) rejected (invalid cameraId %d).",
+ callingPid, cameraId);
+ return NULL;
}
+ char value[PROPERTY_VALUE_MAX];
+ property_get("sys.secpolicy.camera.disabled", value, "0");
+ if (strcmp(value, "1") == 0) {
+ // Camera is disabled by DevicePolicyManager.
+ ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
+ return NULL;
+ }
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
- client = new CameraClient(this, cameraClient, cameraId,
- info.facing, callingPid, getpid());
+ ALOGE("Camera id %d uses HALv1, doesn't support ProCamera", cameraId);
+ return NULL;
break;
case CAMERA_DEVICE_API_VERSION_2_0:
- client = new Camera2Client(this, cameraClient, cameraId,
- info.facing, callingPid, getpid());
+ client = new ProClient(this, cameraCb, cameraId,
+ facing, callingPid, getpid());
break;
+ case -1:
+ ALOGE("Invalid camera id %d", cameraId);
+ return NULL;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return NULL;
@@ -212,23 +296,27 @@ sp<ICamera> CameraService::connect(
return NULL;
}
- cameraClient->asBinder()->linkToDeath(this);
+ mProClientList[cameraId].push(client);
+
+ cameraCb->asBinder()->linkToDeath(this);
- mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
return client;
+
+
+ return NULL;
}
-void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {
+void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
int callingPid = getCallingPid();
- LOG1("CameraService::removeClient E (pid %d)", callingPid);
+ LOG1("CameraService::removeClientByRemote E (pid %d)", callingPid);
// Declare this before the lock to make absolutely sure the
// destructor won't be called with the lock held.
Mutex::Autolock lock(mServiceLock);
int outIndex;
- sp<Client> client = findClientUnsafe(cameraClient->asBinder(), outIndex);
+ sp<Client> client = findClientUnsafe(remoteBinder, outIndex);
if (client != 0) {
// Found our camera, clear and leave.
@@ -236,9 +324,50 @@ void CameraService::removeClient(const sp<ICameraClient>& cameraClient) {
mClient[outIndex].clear();
client->unlinkToDeath(this);
+ } else {
+
+ sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
+
+ if (clientPro != NULL) {
+ // Found our camera, clear and leave.
+ LOG1("removeClient: clear pro %p", clientPro.get());
+
+ clientPro->getRemoteCallback()->asBinder()->unlinkToDeath(this);
+ }
+ }
+
+ LOG1("CameraService::removeClientByRemote X (pid %d)", callingPid);
+}
+
+sp<CameraService::ProClient> CameraService::findProClientUnsafe(
+ const wp<IBinder>& cameraCallbacksRemote)
+{
+ sp<ProClient> clientPro;
+
+ for (int i = 0; i < mNumberOfCameras; ++i) {
+ Vector<size_t> removeIdx;
+
+ for (size_t j = 0; j < mProClientList[i].size(); ++j) {
+ wp<ProClient> cl = mProClientList[i][j];
+
+ sp<ProClient> clStrong = cl.promote();
+ if (clStrong != NULL && clStrong->getRemote() == cameraCallbacksRemote) {
+ clientPro = clStrong;
+ break;
+ } else if (clStrong == NULL) {
+ // mark to clean up dead ptr
+ removeIdx.push(j);
+ }
+ }
+
+ // remove stale ptrs (in reverse so the indices dont change)
+ for (ssize_t j = (ssize_t)removeIdx.size() - 1; j >= 0; --j) {
+ mProClientList[i].removeAt(removeIdx[j]);
+ }
+
}
- LOG1("CameraService::removeClient X (pid %d)", callingPid);
+ return clientPro;
}
sp<CameraService::Client> CameraService::findClientUnsafe(
@@ -252,7 +381,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe(
if (mClient[i] == 0) continue;
// Promote mClient. It can fail if we are called from this path:
- // Client::~Client() -> disconnect() -> removeClient().
+ // Client::~Client() -> disconnect() -> removeClientByRemote().
client = mClient[i].promote();
// Clean up stale client entry
@@ -282,12 +411,12 @@ Mutex* CameraService::getClientLockById(int cameraId) {
return &mClientLock[cameraId];
}
-sp<CameraService::Client> CameraService::getClientByRemote(
+sp<CameraService::BasicClient> CameraService::getClientByRemote(
const wp<IBinder>& cameraClient) {
// Declare this before the lock to make absolutely sure the
// destructor won't be called with the lock held.
- sp<Client> client;
+ sp<BasicClient> client;
Mutex::Autolock lock(mServiceLock);
@@ -302,6 +431,7 @@ status_t CameraService::onTransact(
// Permission checks
switch (code) {
case BnCameraService::CONNECT:
+ case BnCameraService::CONNECT_PRO:
const int pid = getCallingPid();
const int self_pid = getpid();
if (pid != self_pid) {
@@ -390,17 +520,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) {
+ int cameraId, int cameraFacing, int clientPid, int servicePid) :
+ CameraService::BasicClient(cameraService, cameraClient->asBinder(),
+ cameraId, cameraFacing,
+ clientPid, servicePid)
+{
int callingPid = getCallingPid();
LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
- mCameraService = cameraService;
mCameraClient = cameraClient;
- mCameraId = cameraId;
- mCameraFacing = cameraFacing;
- mClientPid = clientPid;
- mServicePid = servicePid;
- mDestructionStarted = false;
cameraService->setCameraBusy(cameraId);
cameraService->loadSound();
@@ -409,12 +537,37 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
// tear down the client
CameraService::Client::~Client() {
+ mDestructionStarted = true;
+
mCameraService->releaseSound();
// 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)
+{
+ mCameraService = cameraService;
+ mRemoteCallback = remoteCallback;
+ mCameraId = cameraId;
+ mCameraFacing = cameraFacing;
+ mClientPid = clientPid;
+ mServicePid = servicePid;
+
+ mDestructionStarted = false;
+}
+
+CameraService::BasicClient::~BasicClient() {
+ mDestructionStarted = true;
+}
+
+void CameraService::BasicClient::disconnect() {
+ mCameraService->removeClientByRemote(mRemoteCallback);
+}
+
// ----------------------------------------------------------------------------
Mutex* CameraService::Client::getClientLockFromCookie(void* user) {
@@ -439,11 +592,96 @@ CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
// NOTE: function is idempotent
void CameraService::Client::disconnect() {
- mCameraService->removeClient(mCameraClient);
+ BasicClient::disconnect();
mCameraService->setCameraFree(mCameraId);
}
// ----------------------------------------------------------------------------
+// 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)
+{
+ mRemoteCallback = remoteCallback;
+}
+
+CameraService::ProClient::~ProClient() {
+ mDestructionStarted = true;
+
+ ProClient::disconnect();
+}
+
+status_t CameraService::ProClient::connect(const sp<IProCameraCallbacks>& callbacks) {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+
+ return INVALID_OPERATION;
+}
+
+void CameraService::ProClient::disconnect() {
+ BasicClient::disconnect();
+}
+
+status_t CameraService::ProClient::initialize(camera_module_t* module)
+{
+ ALOGW("%s: not implemented yet", __FUNCTION__);
+ return OK;
+}
+
+status_t CameraService::ProClient::exclusiveTryLock() {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
+status_t CameraService::ProClient::exclusiveLock() {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
+status_t CameraService::ProClient::exclusiveUnlock() {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
+bool CameraService::ProClient::hasExclusiveLock() {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+ return false;
+}
+
+status_t CameraService::ProClient::submitRequest(camera_metadata_t* request, bool streaming) {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+
+ free_camera_metadata(request);
+
+ return INVALID_OPERATION;
+}
+
+status_t CameraService::ProClient::cancelRequest(int requestId) {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+
+ return INVALID_OPERATION;
+}
+
+status_t CameraService::ProClient::requestStream(int streamId) {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+
+ return INVALID_OPERATION;
+}
+
+status_t CameraService::ProClient::cancelStream(int streamId) {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+
+ return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 60000;
@@ -569,7 +807,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
ALOGV("java clients' binder died");
- sp<Client> cameraClient = getClientByRemote(who);
+ sp<BasicClient> cameraClient = getClientByRemote(who);
if (cameraClient == 0) {
ALOGV("java clients' binder death already cleaned up (normal case)");
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 41365a0..9e0f62a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -18,6 +18,7 @@
#ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
+#include <utils/Vector.h>
#include <binder/BinderService.h>
#include <camera/ICameraService.h>
#include <hardware/camera.h>
@@ -40,27 +41,32 @@ class CameraService :
friend class BinderService<CameraService>;
public:
class Client;
+ class BasicClient;
+
+ // Implementation of BinderService<T>
static char const* getServiceName() { return "media.camera"; }
CameraService();
virtual ~CameraService();
+ /////////////////////////////////////////////////////////////////////
+ // ICameraService
virtual int32_t getNumberOfCameras();
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
- virtual void removeClient(const sp<ICameraClient>& cameraClient);
- // returns plain pointer of client. Note that mClientLock should be acquired to
- // prevent the client from destruction. The result can be NULL.
- virtual Client* getClientByIdUnsafe(int cameraId);
- virtual Mutex* getClientLockById(int cameraId);
-
- virtual sp<Client> getClientByRemote(const wp<IBinder>& cameraClient);
+ virtual sp<IProCameraUser>
+ connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId);
- virtual status_t dump(int fd, const Vector<String16>& args);
+ // Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
- virtual void onFirstRef();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ /////////////////////////////////////////////////////////////////////
+ // Client functionality
+ virtual void removeClientByRemote(const wp<IBinder>& remoteBinder);
enum sound_kind {
SOUND_SHUTTER = 0,
@@ -72,7 +78,53 @@ public:
void playSound(sound_kind kind);
void releaseSound();
- class Client : public BnCamera
+
+ /////////////////////////////////////////////////////////////////////
+ // CameraClient functionality
+
+ // returns plain pointer of client. Note that mClientLock should be acquired to
+ // prevent the client from destruction. The result can be NULL.
+ virtual Client* getClientByIdUnsafe(int cameraId);
+ virtual Mutex* getClientLockById(int cameraId);
+
+ class BasicClient : public virtual RefBase {
+ public:
+ virtual status_t initialize(camera_module_t *module) = 0;
+
+ virtual void disconnect() = 0;
+
+ wp<IBinder> getRemote() {
+ return mRemoteCallback;
+ }
+
+ protected:
+ BasicClient(const sp<CameraService>& cameraService,
+ const sp<IBinder>& remoteCallback,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ int servicePid);
+
+ virtual ~BasicClient();
+
+ // the instance is in the middle of destruction. When this is set,
+ // the instance should not be accessed from callback.
+ // CameraService's mClientLock should be acquired to access this.
+ // - subclasses should set this to true in their destructors.
+ bool mDestructionStarted;
+
+ // these are initialized in the constructor.
+ sp<CameraService> mCameraService; // immutable after constructor
+ int mCameraId; // immutable after constructor
+ int mCameraFacing; // immutable after constructor
+ pid_t mClientPid;
+ pid_t mServicePid; // immutable after constructor
+
+ // - The app-side Binder interface to receive callbacks from us
+ wp<IBinder> mRemoteCallback; // immutable after constructor
+ };
+
+ class Client : public BnCamera, public BasicClient
{
public:
// ICamera interface (see ICamera for details)
@@ -112,38 +164,82 @@ public:
return mCameraClient;
}
- virtual status_t initialize(camera_module_t *module) = 0;
-
- virtual status_t dump(int fd, const Vector<String16>& args) = 0;
-
protected:
static Mutex* getClientLockFromCookie(void* user);
// convert client from cookie. Client lock should be acquired before getting Client.
static Client* getClientFromCookie(void* user);
- // the instance is in the middle of destruction. When this is set,
- // the instance should not be accessed from callback.
- // CameraService's mClientLock should be acquired to access this.
- bool mDestructionStarted;
+ // Initialized in constructor
- // these are initialized in the constructor.
- sp<CameraService> mCameraService; // immutable after constructor
+ // - The app-side Binder interface to receive callbacks from us
sp<ICameraClient> mCameraClient;
- int mCameraId; // immutable after constructor
- int mCameraFacing; // immutable after constructor
- pid_t mClientPid;
- pid_t mServicePid; // immutable after constructor
+ };
+
+ class ProClient : public BnProCameraUser, public BasicClient {
+ public:
+ ProClient(const sp<CameraService>& cameraService,
+ const sp<IProCameraCallbacks>& remoteCallback,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ int servicePid);
+
+ virtual ~ProClient();
+
+ const sp<IProCameraCallbacks>& getRemoteCallback() {
+ return mRemoteCallback;
+ }
+
+ // BasicClient implementation
+ virtual status_t initialize(camera_module_t *module);
+
+ /***
+ IProCamera implementation
+ ***/
+
+
+ virtual status_t connect(
+ const sp<IProCameraCallbacks>& callbacks);
+ virtual void disconnect();
+
+ virtual status_t exclusiveTryLock();
+ virtual status_t exclusiveLock();
+ virtual status_t exclusiveUnlock();
+
+ virtual bool hasExclusiveLock();
+
+ // Note that the callee gets a copy of the metadata.
+ virtual int submitRequest(camera_metadata_t* metadata,
+ bool streaming = false);
+ virtual status_t cancelRequest(int requestId);
+
+ virtual status_t requestStream(int streamId);
+ virtual status_t cancelStream(int streamId);
+
+ protected:
+ sp<IProCameraCallbacks> mRemoteCallback;
};
private:
+
+ // Delay-load the Camera HAL module
+ virtual void onFirstRef();
+
+ virtual sp<BasicClient> getClientByRemote(const wp<IBinder>& cameraClient);
+
Mutex mServiceLock;
wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock
Mutex mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks
int mNumberOfCameras;
+ typedef wp<ProClient> weak_pro_client_ptr;
+ Vector<weak_pro_client_ptr> mProClientList[MAX_CAMERAS];
+
// needs to be called with mServiceLock held
sp<Client> findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
+ sp<ProClient> findProClientUnsafe(
+ const wp<IBinder>& cameraCallbacksRemote);
// atomics to record whether the hardware is allocated to some client.
volatile int32_t mBusy[MAX_CAMERAS];
@@ -161,6 +257,9 @@ private:
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
+
+ // Helpers
+ int getDeviceVersion(int cameraId, int* facing);
};
} // namespace android