summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-27 12:55:20 -0800
committerIgor Murashkin <iam@google.com>2013-02-28 15:55:15 -0800
commit8fdfbe27acd157d58fa35a849ec50c82464062f0 (patch)
tree19a08d59c5e5cfd56cda29b01ef1ea1b4f00ed77 /services
parent721f17283e2493426c47bbaa267c337b2af5726e (diff)
downloadframeworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.zip
frameworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.tar.gz
frameworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.tar.bz2
Camera: Drop ProCamera connections when a Camera connection happens
* Also adds an ICameraServiceListener with available/not available statuses Bug: 8291653 Change-Id: I24680f1a2dc109510caf451cf7c7bd180b670d84
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/CameraService.cpp126
-rw-r--r--services/camera/libcameraservice/CameraService.h30
-rw-r--r--services/camera/libcameraservice/ProCamera2Client.cpp68
-rw-r--r--services/camera/libcameraservice/ProCamera2Client.h5
4 files changed, 225 insertions, 4 deletions
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d7c8807..8c4f619 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -77,6 +77,10 @@ CameraService::CameraService()
{
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
+
+ for (size_t i = 0; i < MAX_CAMERAS; ++i) {
+ mStatusList[i] = ICameraServiceListener::STATUS_AVAILABLE;
+ }
}
void CameraService::onFirstRef()
@@ -155,6 +159,23 @@ int CameraService::getDeviceVersion(int cameraId, int* facing) {
return deviceVersion;
}
+bool CameraService::isValidCameraId(int cameraId) {
+ int facing;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
sp<ICamera> CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
@@ -236,6 +257,10 @@ sp<ICamera> CameraService::connect(
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
+ if (isValidCameraId(cameraId)) {
+ updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE, cameraId);
+ }
+
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
client = new CameraClient(this, cameraClient,
@@ -259,6 +284,9 @@ sp<ICamera> CameraService::connect(
}
if (client->initialize(mModule) != OK) {
+ // this is probably not recoverable.. but maybe the client can try again
+ updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
+
return NULL;
}
@@ -266,6 +294,7 @@ sp<ICamera> CameraService::connect(
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
+
return client;
}
@@ -275,6 +304,7 @@ sp<IProCameraUser> CameraService::connect(
const String16& clientPackageName,
int clientUid)
{
+ String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
// TODO: use clientPackageName and clientUid with appOpsMangr
@@ -301,6 +331,15 @@ sp<IProCameraUser> CameraService::connect(
return NULL;
}
+ // TODO: allow concurrent connections with a ProCamera
+ if (mBusy[cameraId]) {
+
+ ALOGW("CameraService::connectPro X (pid %d, \"%s\") rejected"
+ " (camera %d is still busy).", callingPid,
+ clientName8.string(), cameraId);
+ return NULL;
+ }
+
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -333,9 +372,45 @@ sp<IProCameraUser> CameraService::connect(
LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId,
getpid());
return client;
+}
+status_t CameraService::addListener(
+ const sp<ICameraServiceListener>& listener) {
+ ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
- return NULL;
+ Mutex::Autolock lock(mServiceLock);
+
+ Vector<sp<ICameraServiceListener> >::iterator it, end;
+ for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+ if ((*it)->asBinder() == listener->asBinder()) {
+ ALOGW("%s: Tried to add listener %p which was already subscribed",
+ __FUNCTION__, listener.get());
+ return ALREADY_EXISTS;
+ }
+ }
+
+ mListenerList.push_back(listener);
+
+ return OK;
+}
+status_t CameraService::removeListener(
+ const sp<ICameraServiceListener>& listener) {
+ ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get());
+
+ Mutex::Autolock lock(mServiceLock);
+
+ Vector<sp<ICameraServiceListener> >::iterator it;
+ for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+ if ((*it)->asBinder() == listener->asBinder()) {
+ mListenerList.erase(it);
+ return OK;
+ }
+ }
+
+ ALOGW("%s: Tried to remove a listener %p which was not subscribed",
+ __FUNCTION__, listener.get());
+
+ return BAD_VALUE;
}
void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
@@ -699,6 +774,8 @@ void CameraService::Client::notifyError() {
void CameraService::Client::disconnect() {
BasicClient::disconnect();
mCameraService->setCameraFree(mCameraId);
+ mCameraService->updateStatus(ICameraServiceListener::STATUS_AVAILABLE,
+ mCameraId);
}
CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
@@ -774,6 +851,10 @@ bool CameraService::ProClient::hasExclusiveLock() {
return false;
}
+void CameraService::ProClient::onExclusiveLockStolen() {
+ ALOGE("%s: not implemented yet", __FUNCTION__);
+}
+
status_t CameraService::ProClient::submitRequest(camera_metadata_t* request, bool streaming) {
ALOGE("%s: not implemented yet", __FUNCTION__);
@@ -944,4 +1025,47 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
}
+void CameraService::updateStatus(ICameraServiceListener::Status status,
+ int32_t cameraId) {
+ // do not lock mServiceLock here or can get into a deadlock from
+ // connect() -> ProClient::disconnect -> updateStatus
+ Mutex::Autolock lock(mStatusMutex);
+ updateStatusUnsafe(status, cameraId);
+}
+
+void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
+ int32_t cameraId) {
+
+ ICameraServiceListener::Status oldStatus = mStatusList[cameraId];
+
+ mStatusList[cameraId] = status;
+
+ if (oldStatus != status) {
+ ALOGV("%s: Status has changed for camera ID %d from 0x%x to 0x%x",
+ __FUNCTION__, cameraId, (uint32_t)oldStatus, (uint32_t)status);
+
+ /**
+ * ProClients lose their exclusive lock.
+ * - Done before the CameraClient can initialize the HAL device,
+ * since we want to be able to close it before they get to initialize
+ */
+ if (status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ Vector<wp<ProClient> > proClients(mProClientList[cameraId]);
+ Vector<wp<ProClient> >::const_iterator it;
+
+ for (it = proClients.begin(); it != proClients.end(); ++it) {
+ sp<ProClient> proCl = it->promote();
+ if (proCl.get() != NULL) {
+ proCl->onExclusiveLockStolen();
+ }
+ }
+ }
+
+ Vector<sp<ICameraServiceListener> >::const_iterator it;
+ for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+ (*it)->onStatusChanged(status, cameraId);
+ }
+ }
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d93aa73..8acc63f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -30,6 +30,8 @@
#include <camera/IProCameraUser.h>
#include <camera/IProCameraCallbacks.h>
+#include <camera/ICameraServiceListener.h>
+
/* This needs to be increased if we can have more cameras */
#define MAX_CAMERAS 2
@@ -67,6 +69,10 @@ public:
virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
int cameraId, const String16& clientPackageName, int clientUid);
+ virtual status_t addListener(const sp<ICameraServiceListener>& listener);
+ virtual status_t removeListener(
+ const sp<ICameraServiceListener>& listener);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -263,6 +269,9 @@ public:
virtual status_t requestStream(int streamId);
virtual status_t cancelStream(int streamId);
+ // Callbacks from camera service
+ virtual void onExclusiveLockStolen();
+
protected:
virtual void notifyError();
@@ -303,11 +312,30 @@ private:
camera_module_t *mModule;
+ Vector<sp<ICameraServiceListener> >
+ mListenerList;
+
+ // guard only mStatusList and the broadcasting of ICameraServiceListener
+ Mutex mStatusMutex;
+ ICameraServiceListener::Status
+ mStatusList[MAX_CAMERAS];
+
+ // Broadcast the new status if it changed (locks the service mutex)
+ void updateStatus(
+ ICameraServiceListener::Status status,
+ int32_t cameraId);
+ // Call this one when the service mutex is already held (idempotent)
+ void updateStatusUnsafe(
+ ICameraServiceListener::Status status,
+ int32_t cameraId);
+
// IBinder::DeathRecipient implementation
- virtual void binderDied(const wp<IBinder> &who);
+ virtual void binderDied(const wp<IBinder> &who);
// Helpers
int getDeviceVersion(int cameraId, int* facing);
+
+ bool isValidCameraId(int cameraId);
};
} // namespace android
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index eda3012..6fed8b4 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -115,6 +115,8 @@ status_t ProCamera2Client::exclusiveTryLock() {
Mutex::Autolock icl(mIProCameraUserLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+ if (!mDevice.get()) return PERMISSION_DENIED;
+
if (!mExclusiveLock) {
mExclusiveLock = true;
@@ -144,6 +146,8 @@ status_t ProCamera2Client::exclusiveLock() {
Mutex::Autolock icl(mIProCameraUserLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+ if (!mDevice.get()) return PERMISSION_DENIED;
+
/**
* TODO: this should asynchronously 'wait' until the lock becomes available
* if another client already has an exclusive lock.
@@ -197,12 +201,33 @@ bool ProCamera2Client::hasExclusiveLock() {
return mExclusiveLock;
}
+void ProCamera2Client::onExclusiveLockStolen() {
+ ALOGV("%s: ProClient lost exclusivity (id %d)",
+ __FUNCTION__, mCameraId);
+
+ Mutex::Autolock icl(mIProCameraUserLock);
+ SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+ if (mExclusiveLock && mRemoteCallback.get() != NULL) {
+ mRemoteCallback->onLockStatusChanged(
+ IProCameraCallbacks::LOCK_STOLEN);
+ }
+
+ mExclusiveLock = false;
+
+ //TODO: we should not need to detach the device, merely reset it.
+ detachDevice();
+}
+
status_t ProCamera2Client::submitRequest(camera_metadata_t* request,
bool streaming) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mIProCameraUserLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
if (!mExclusiveLock) {
return PERMISSION_DENIED;
}
@@ -224,6 +249,9 @@ status_t ProCamera2Client::cancelRequest(int requestId) {
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mIProCameraUserLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
if (!mExclusiveLock) {
return PERMISSION_DENIED;
}
@@ -247,6 +275,7 @@ status_t ProCamera2Client::cancelStream(int streamId) {
Mutex::Autolock icl(mIProCameraUserLock);
+ if (!mDevice.get()) return DEAD_OBJECT;
mDevice->clearStreamingRequest();
status_t code;
@@ -274,6 +303,8 @@ status_t ProCamera2Client::createStream(int width, int height, int format,
Mutex::Autolock icl(mIProCameraUserLock);
+ if (!mDevice.get()) return DEAD_OBJECT;
+
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
@@ -303,6 +334,8 @@ status_t ProCamera2Client::createDefaultRequest(int templateId,
Mutex::Autolock icl(mIProCameraUserLock);
+ if (!mDevice.get()) return DEAD_OBJECT;
+
CameraMetadata metadata;
if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK) {
*request = metadata.release();
@@ -319,6 +352,10 @@ status_t ProCamera2Client::getCameraInfo(int cameraId,
return INVALID_OPERATION;
}
+ Mutex::Autolock icl(mIProCameraUserLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
CameraMetadata deviceInfo = mDevice->info();
*info = deviceInfo.release();
@@ -341,6 +378,12 @@ status_t ProCamera2Client::dump(int fd, const Vector<String16>& args) {
result = " Device dump:\n";
write(fd, result.string(), result.size());
+ if (!mDevice.get()) {
+ result = " *** Device is detached\n";
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+ }
+
status_t res = mDevice->dump(fd, args);
if (res != OK) {
result = String8::format(" Error dumping device: %s (%d)",
@@ -363,9 +406,19 @@ void ProCamera2Client::disconnect() {
int callingPid = getCallingPid();
if (callingPid != mClientPid && callingPid != mServicePid) return;
+ ALOGV("Camera %d: Shutting down", mCameraId);
+
+ detachDevice();
+ ProClient::disconnect();
+
+ ALOGV("Camera %d: Shut down complete complete", mCameraId);
+}
+
+void ProCamera2Client::detachDevice() {
if (mDevice == 0) return;
- ALOGV("Camera %d: Shutting down", mCameraId);
+ ALOGV("Camera %d: Stopping processors", mCameraId);
+
mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this);
@@ -374,11 +427,22 @@ void ProCamera2Client::disconnect() {
mFrameProcessor->join();
ALOGV("Camera %d: Disconnecting device", mCameraId);
+ // WORKAROUND: HAL refuses to disconnect while there's streams in flight
+ {
+ mDevice->clearStreamingRequest();
+
+ status_t code;
+ if ((code = mDevice->waitUntilDrained()) != OK) {
+ ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
+ code);
+ }
+ }
+
mDevice->disconnect();
mDevice.clear();
- ProClient::disconnect();
+ ALOGV("Camera %d: Detach complete", mCameraId);
}
status_t ProCamera2Client::connect(const sp<IProCameraCallbacks>& client) {
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index 9f514f4..ff6f4e2 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -104,6 +104,9 @@ public:
const sp<Camera2Device>& getCameraDevice();
const sp<CameraService>& getCameraService();
+ // Callbacks from camera service
+ virtual void onExclusiveLockStolen();
+
/**
* Interface used by independent components of ProCamera2Client.
*/
@@ -167,6 +170,8 @@ private:
// - if no we can't modify the request queue.
// note that creating/deleting streams we own is still OK
bool mExclusiveLock;
+
+ void detachDevice();
};
}; // namespace android