diff options
author | Wu-cheng Li <wuchengli@google.com> | 2012-03-15 21:23:24 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-03-15 21:23:24 -0700 |
commit | 49f306f863b14f8bfc3b405ebfd3a2fb2b403c15 (patch) | |
tree | d7c29856e1529b3337e5a2093fa1553c8818a3df /services | |
parent | 2f70d9f89a0461cafdbd84a3d8d65062f420d77a (diff) | |
parent | 2fd2440d0175ca3e196b01b7541a9e0d4ed9a694 (diff) | |
download | frameworks_av-49f306f863b14f8bfc3b405ebfd3a2fb2b403c15.zip frameworks_av-49f306f863b14f8bfc3b405ebfd3a2fb2b403c15.tar.gz frameworks_av-49f306f863b14f8bfc3b405ebfd3a2fb2b403c15.tar.bz2 |
Merge "Add a new camera open API that allows taking the ownership."
Diffstat (limited to 'services')
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 149 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 15 |
2 files changed, 130 insertions, 34 deletions
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index adf1d49..22836e3 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -21,6 +21,7 @@ #include <stdio.h> #include <sys/types.h> #include <pthread.h> +#include <time.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -33,6 +34,7 @@ #include <hardware/hardware.h> #include <media/AudioSystem.h> #include <media/mediaplayer.h> +#include <utils/Condition.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/String16.h> @@ -42,6 +44,8 @@ namespace android { +#define WAIT_RELEASE_TIMEOUT 250 // 250ms + // ---------------------------------------------------------------------------- // Logging support -- this is for debugging only // Use "adb shell dumpsys media.camera -v 1" to change it. @@ -64,6 +68,13 @@ static int getCallingUid() { return IPCThreadState::self()->getCallingUid(); } +static long long getTimeInMs() { + struct timeval t; + t.tv_sec = t.tv_usec = 0; + gettimeofday(&t, NULL); + return t.tv_sec * 1000LL + t.tv_usec / 1000; +} + // ---------------------------------------------------------------------------- // This is ugly and only safe if we never re-create the CameraService, but @@ -131,7 +142,7 @@ status_t CameraService::getCameraInfo(int cameraId, } sp<ICamera> CameraService::connect( - const sp<ICameraClient>& cameraClient, int cameraId) { + const sp<ICameraClient>& cameraClient, int cameraId, bool force, bool keep) { int callingPid = getCallingPid(); sp<CameraHardwareInterface> hardware = NULL; @@ -157,27 +168,73 @@ sp<ICamera> CameraService::connect( return NULL; } + if (keep && !checkCallingPermission(String16("android.permission.KEEP_CAMERA"))) { + ALOGE("connect X (pid %d) rejected (no KEEP_CAMERA permission).", callingPid); + return NULL; + } + Mutex::Autolock lock(mServiceLock); - if (mClient[cameraId] != 0) { - client = mClient[cameraId].promote(); - if (client != 0) { - if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) { - LOG1("CameraService::connect X (pid %d) (the same client)", - callingPid); - return client; - } else { - ALOGW("CameraService::connect X (pid %d) rejected (existing client).", - callingPid); - return NULL; - } + // Check if there is an existing client. + client = mClient[cameraId].promote(); + if (client != 0 && + cameraClient->asBinder() == client->getCameraClient()->asBinder()) { + LOG1("connect X (pid %d) (the same client)", callingPid); + return client; + } + + if (!force) { + if (mClient[cameraId].promote() != 0) { + ALOGW("connect X (pid %d) rejected (existing client).", callingPid); + return NULL; } mClient[cameraId].clear(); - } + if (mBusy[cameraId]) { + ALOGW("connect X (pid %d) rejected (camera %d is still busy).", + callingPid, cameraId); + return NULL; + } + } else { // force == true + int i = 0; + long long start_time = getTimeInMs(); + while (i < mNumberOfCameras) { + if (getTimeInMs() - start_time >= 3000LL) { + ALOGE("connect X (pid %d) rejected (timeout 3s)", callingPid); + return NULL; + } - if (mBusy[cameraId]) { - ALOGW("CameraService::connect X (pid %d) rejected" - " (camera %d is still busy).", callingPid, cameraId); - return NULL; + client = mClient[i].promote(); + if (client != 0) { + if (client->keep()) { + ALOGW("connect X (pid %d) rejected (existing client wants to keeps the camera)", + callingPid); + return NULL; + } else { + ALOGW("New client (pid %d, id=%d). Disconnect the existing client (id=%d).", + callingPid, cameraId, i); + // Do not hold mServiceLock because disconnect will try to get it. + mServiceLock.unlock(); + client->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0, &i); + client->waitRelease(WAIT_RELEASE_TIMEOUT); + client->disconnectInternal(false); + mServiceLock.lock(); + // Restart from the first client because a new client may have connected + // when mServiceLock is unlocked. + i = 0; + continue; + } + } + + if (mBusy[i]) { + // Give the client a chance to release the hardware. + mServiceLock.unlock(); + usleep(10 * 1000); + mServiceLock.lock(); + i = 0; // Restart from the first client + continue; + } + + i++; + } } struct camera_info info; @@ -195,9 +252,15 @@ sp<ICamera> CameraService::connect( return NULL; } - client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid); + client = new Client(this, cameraClient, hardware, cameraId, info.facing, + callingPid, keep); + // We need to clear the hardware here. After the destructor of mServiceLock + // finishes, a new client may connect and disconnect this client. If this + // reference is not cleared, the destructor of CameraHardwareInterface + // cannot run. The new client will not be able to connect. + hardware.clear(); mClient[cameraId] = client; - LOG1("CameraService::connect X"); + LOG1("CameraService::connect X (id %d)", cameraId); return client; } @@ -331,9 +394,9 @@ void CameraService::playSound(sound_kind kind) { CameraService::Client::Client(const sp<CameraService>& cameraService, const sp<ICameraClient>& cameraClient, const sp<CameraHardwareInterface>& hardware, - int cameraId, int cameraFacing, int clientPid) { + int cameraId, int cameraFacing, int clientPid, bool keep) { int callingPid = getCallingPid(); - LOG1("Client::Client E (pid %d)", callingPid); + LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId); mCameraService = cameraService; mCameraClient = cameraClient; @@ -341,6 +404,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, mCameraId = cameraId; mCameraFacing = cameraFacing; mClientPid = clientPid; + mKeep = keep; mMsgEnabled = 0; mSurface = 0; mPreviewWindow = 0; @@ -359,7 +423,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, mPlayShutterSound = true; cameraService->setCameraBusy(cameraId); cameraService->loadSound(); - LOG1("Client::Client X (pid %d)", callingPid); + LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId); } // tear down the client @@ -468,18 +532,24 @@ static void disconnectWindow(const sp<ANativeWindow>& window) { } void CameraService::Client::disconnect() { + disconnectInternal(true); +} + +void CameraService::Client::disconnectInternal(bool needCheckPid) { int callingPid = getCallingPid(); - LOG1("disconnect E (pid %d)", callingPid); + LOG1("disconnectInternal E (pid %d)", callingPid); Mutex::Autolock lock(mLock); - if (checkPid() != NO_ERROR) { - ALOGW("different client - don't disconnect"); - return; - } + if (needCheckPid) { + if (checkPid() != NO_ERROR) { + ALOGW("different client - don't disconnect"); + return; + } - if (mClientPid <= 0) { - LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid); - return; + if (mClientPid <= 0) { + LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid); + return; + } } // Make sure disconnect() is done once and once only, whether it is called @@ -506,8 +576,16 @@ void CameraService::Client::disconnect() { mCameraService->removeClient(mCameraClient); mCameraService->setCameraFree(mCameraId); + mReleaseCondition.signal(); + + LOG1("disconnectInternal X (pid %d)", callingPid); +} - LOG1("disconnect X (pid %d)", callingPid); +void CameraService::Client::waitRelease(int ms) { + Mutex::Autolock lock(mLock); + if (mHardware != 0) { + mReleaseCondition.waitRelative(mLock, ms * 1000000); + } } // ---------------------------------------------------------------------------- @@ -874,6 +952,9 @@ status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t a return OK; } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) { mCameraService->playSound(SOUND_RECORDING); + } else if (cmd == CAMERA_CMD_PING) { + // If mHardware is 0, checkPidAndHardware will return error. + return OK; } return mHardware->sendCommand(cmd, arg1, arg2); @@ -1217,6 +1298,10 @@ int CameraService::Client::getOrientation(int degrees, bool mirror) { return -1; } +// Whether the client wants to keep the camera from taking +bool CameraService::Client::keep() const { + return mKeep; +} // ---------------------------------------------------------------------------- diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index bad41f5..457c79b 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -46,7 +46,8 @@ 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<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId, + bool force, bool keep); virtual void removeClient(const sp<ICameraClient>& cameraClient); virtual sp<Client> getClientById(int cameraId); @@ -114,7 +115,8 @@ private: const sp<CameraHardwareInterface>& hardware, int cameraId, int cameraFacing, - int clientPid); + int clientPid, + bool keep); ~Client(); // return our camera client @@ -172,12 +174,19 @@ private: const sp<IBinder>& binder, const sp<ANativeWindow>& window); + void disconnectInternal(bool needCheckPid); + bool keep() const; + void waitRelease(int ms); + + // these are initialized in the constructor. sp<CameraService> mCameraService; // immutable after constructor sp<ICameraClient> mCameraClient; int mCameraId; // immutable after constructor int mCameraFacing; // immutable after constructor pid_t mClientPid; + // Client wants to keep the camera from taking by other clients. + bool mKeep; sp<CameraHardwareInterface> mHardware; // cleared after disconnect() int mPreviewCallbackFlag; int mOrientation; // Current display orientation @@ -185,6 +194,8 @@ private: // Ensures atomicity among the public methods mutable Mutex mLock; + // This will get notified when the hardware is released. + Condition mReleaseCondition; // This is a binder of Surface or SurfaceTexture. sp<IBinder> mSurface; sp<ANativeWindow> mPreviewWindow; |