diff options
author | Igor Murashkin <iam@google.com> | 2013-02-27 12:55:20 -0800 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2013-02-28 15:55:15 -0800 |
commit | bfc9915f482520eb9676c6d2dbf7f1ac078d937d (patch) | |
tree | 1353c3f2f63777397770edfd1f146c691e5684e2 /services | |
parent | 3fa4891f54bbfdbe8ee652930d22c96639964eff (diff) | |
download | frameworks_av-bfc9915f482520eb9676c6d2dbf7f1ac078d937d.zip frameworks_av-bfc9915f482520eb9676c6d2dbf7f1ac078d937d.tar.gz frameworks_av-bfc9915f482520eb9676c6d2dbf7f1ac078d937d.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.cpp | 126 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 30 | ||||
-rw-r--r-- | services/camera/libcameraservice/ProCamera2Client.cpp | 68 | ||||
-rw-r--r-- | services/camera/libcameraservice/ProCamera2Client.h | 5 |
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 |