OSDN Git Service

Camera: Hotplug - conditionally transition to PRESENT when clients disconnect
authorIgor Murashkin <iam@google.com>
Wed, 1 May 2013 22:42:20 +0000 (15:42 -0700)
committerIgor Murashkin <iam@google.com>
Fri, 3 May 2013 01:04:38 +0000 (18:04 -0700)
Fixes an issue where a client could unconditionally transition to PRESENT
after a client disconnects, even though the underlying HAL status was actually
NOT_PRESENT or ENUMERATING.

Bug: 8780114
Change-Id: I68adb5fc819eec3b046ddcb2507b84bedc999a0f

services/camera/libcameraservice/CameraService.cpp
services/camera/libcameraservice/CameraService.h

index cdeb92e..757a781 100644 (file)
@@ -928,8 +928,15 @@ void CameraService::Client::disconnect() {
     ALOGV("Client::disconnect");
     BasicClient::disconnect();
     mCameraService->setCameraFree(mCameraId);
+
+    StatusVector rejectSourceStates;
+    rejectSourceStates.push_back(ICameraServiceListener::STATUS_NOT_PRESENT);
+    rejectSourceStates.push_back(ICameraServiceListener::STATUS_ENUMERATING);
+
+    // Transition to PRESENT if the camera is not in either of above 2 states
     mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
-                                 mCameraId);
+                                 mCameraId,
+                                 &rejectSourceStates);
 }
 
 CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
@@ -1111,15 +1118,11 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
 }
 
 void CameraService::updateStatus(ICameraServiceListener::Status status,
-                                 int32_t cameraId) {
+                                 int32_t cameraId,
+                                 const StatusVector *rejectSourceStates) {
     // 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];
 
@@ -1139,6 +1142,26 @@ void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
             return;
         }
 
+        if (rejectSourceStates != NULL) {
+            const StatusVector &rejectList = *rejectSourceStates;
+            StatusVector::const_iterator it = rejectList.begin();
+
+            /**
+             * Sometimes we want to conditionally do a transition.
+             * For example if a client disconnects, we want to go to PRESENT
+             * only if we weren't already in NOT_PRESENT or ENUMERATING.
+             */
+            for (; it != rejectList.end(); ++it) {
+                if (oldStatus == *it) {
+                    ALOGV("%s: Rejecting status transition for Camera ID %d, "
+                          " since the source state was was in one of the bad "
+                          " states.", __FUNCTION__, cameraId);
+                    mStatusList[cameraId] = oldStatus;
+                    return;
+                }
+            }
+        }
+
         /**
           * ProClients lose their exclusive lock.
           * - Done before the CameraClient can initialize the HAL device,
index 8cb1691..710f164 100644 (file)
@@ -341,14 +341,12 @@ private:
     ICameraServiceListener::Status
                         getStatus(int cameraId) const;
 
+    typedef Vector<ICameraServiceListener::Status> StatusVector;
     // 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);
+                            int32_t cameraId,
+                            const StatusVector *rejectSourceStates = NULL);
 
     // IBinder::DeathRecipient implementation
     virtual void        binderDied(const wp<IBinder> &who);