summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice/CameraService.cpp
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/CameraService.cpp
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/CameraService.cpp')
-rw-r--r--services/camera/libcameraservice/CameraService.cpp296
1 files changed, 267 insertions, 29 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)");