Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ec46421 authored by Igor Murashkin's avatar Igor Murashkin Committed by Android Git Automerger
Browse files

am ad065d38: Merge "Camera: Add hotplug support (for fixed # of cameras)" into jb-mr2-dev

* commit 'ad065d38':
  Camera: Add hotplug support (for fixed # of cameras)
parents 5683ded7 ad065d38
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -587,14 +587,19 @@ TEST_F(ProCameraTest, DISABLED_StreamingImageSingle) {
    sp<ServiceListener> listener = new ServiceListener();
    EXPECT_OK(ProCamera::addServiceListener(listener));

    ServiceListener::Status currentStatus = ServiceListener::STATUS_AVAILABLE;
    ServiceListener::Status currentStatus;

    // when subscribing a new listener,
    // we immediately get a callback to the current status
    while (listener->waitForStatusChange(/*out*/currentStatus) != OK);
    EXPECT_EQ(ServiceListener::STATUS_PRESENT, currentStatus);

    dout << "Will now stream and resume infinitely..." << std::endl;
    while (true) {

        if (currentStatus == ServiceListener::STATUS_AVAILABLE) {
        if (currentStatus == ServiceListener::STATUS_PRESENT) {

            EXPECT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
            ASSERT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
                                            surface,
                                            &depthStreamId));
            EXPECT_NE(-1, depthStreamId);
@@ -613,12 +618,15 @@ TEST_F(ProCameraTest, DISABLED_StreamingImageSingle) {
        while (listener->waitForStatusChange(/*out*/stat) != OK);

        if (currentStatus != stat) {
            if (stat == ServiceListener::STATUS_AVAILABLE) {
            if (stat == ServiceListener::STATUS_PRESENT) {
                dout << "Reconnecting to camera" << std::endl;
                mCamera = ProCamera::connect(CAMERA_ID);
            } else if (stat == ServiceListener::STATUS_NOT_AVAILABLE) {
                dout << "Disconnecting from camera" << std::endl;
                mCamera->disconnect();
            } else if (stat == ServiceListener::STATUS_NOT_PRESENT) {
                dout << "Camera unplugged" << std::endl;
                mCamera = NULL;
            } else {
                dout << "Unknown status change "
                     << std::hex << stat << std::endl;
@@ -1219,7 +1227,7 @@ TEST_F(ProCameraTest, ServiceListenersFunctional) {
    }

    EXPECT_OK(listener->waitForStatusChange(/*out*/stat));
    EXPECT_EQ(ServiceListener::STATUS_AVAILABLE, stat);
    EXPECT_EQ(ServiceListener::STATUS_PRESENT, stat);

    EXPECT_OK(ProCamera::removeServiceListener(listener));
}
+6 −5
Original line number Diff line number Diff line
@@ -38,9 +38,8 @@ public:
     *     NOT_PRESENT         -> PRESENT
     *     NOT_PRESENT         -> ENUMERATING
     *     ENUMERATING         -> PRESENT
     *     PRESENT             -> AVAILABLE
     *     AVAILABLE           -> NOT_AVAILABLE
     *     NOT_AVAILABLE       -> AVAILABLE
     *     PRESENT             -> NOT_AVAILABLE
     *     NOT_AVAILABLE       -> PRESENT
     *
     * A state will never immediately transition back to itself.
     */
@@ -48,15 +47,17 @@ public:
        // Device physically unplugged
        STATUS_NOT_PRESENT      = CAMERA_DEVICE_STATUS_NOT_PRESENT,
        // Device physically has been plugged in
        //  and the camera can be used exlusively
        STATUS_PRESENT          = CAMERA_DEVICE_STATUS_PRESENT,
        // Device physically has been plugged in
        //   but it will not be connect-able until enumeration is complete
        STATUS_ENUMERATING      = CAMERA_DEVICE_STATUS_ENUMERATING,

        // Camera can be used exclusively
        STATUS_AVAILABLE        = 0x80000000,
        STATUS_AVAILABLE        = STATUS_PRESENT, // deprecated, will be removed

        // Camera is in use by another app and cannot be used exclusively
        STATUS_NOT_AVAILABLE,
        STATUS_NOT_AVAILABLE    = 0x80000000,

        // Use to initialize variables only
        STATUS_UNKNOWN          = 0xFFFFFFFF,
+131 −3
Original line number Diff line number Diff line
@@ -66,6 +66,20 @@ static int getCallingUid() {
    return IPCThreadState::self()->getCallingUid();
}

extern "C" {
static void camera_device_status_change(
        const struct camera_module_callbacks* callbacks,
        int camera_id,
        int new_status) {
    sp<CameraService> cs = const_cast<CameraService*>(
                                static_cast<const CameraService*>(callbacks));

    cs->onDeviceStatusChanged(
        camera_id,
        new_status);
}
} // extern "C"

// ----------------------------------------------------------------------------

// This is ugly and only safe if we never re-create the CameraService, but
@@ -79,8 +93,10 @@ CameraService::CameraService()
    gCameraService = this;

    for (size_t i = 0; i < MAX_CAMERAS; ++i) {
        mStatusList[i] = ICameraServiceListener::STATUS_AVAILABLE;
        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
    }

    this->camera_device_status_change = android::camera_device_status_change;
}

void CameraService::onFirstRef()
@@ -105,6 +121,11 @@ void CameraService::onFirstRef()
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }

        if (mModule->common.module_api_version >=
                CAMERA_MODULE_API_VERSION_2_1) {
            mModule->set_callbacks(this);
        }
    }
}

@@ -118,6 +139,67 @@ CameraService::~CameraService() {
    gCameraService = NULL;
}

void CameraService::onDeviceStatusChanged(int cameraId,
                                          int newStatus)
{
    ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
          cameraId, newStatus);

    if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
        ALOGE("%s: Bad camera ID %d", __FUNCTION__, cameraId);
        return;
    }

    if ((int)getStatus(cameraId) == newStatus) {
        ALOGE("%s: State transition to the same status 0x%x not allowed",
              __FUNCTION__, (uint32_t)newStatus);
        return;
    }

    /* don't do this in updateStatus
       since it is also called from connect and we could get into a deadlock */
    if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
        Vector<sp<BasicClient> > clientsToDisconnect;
        {
           Mutex::Autolock al(mServiceLock);

           /* Find all clients that we need to disconnect */
           sp<Client> client = mClient[cameraId].promote();
           if (client.get() != NULL) {
               clientsToDisconnect.push_back(client);
           }

           int i = cameraId;
           for (size_t j = 0; j < mProClientList[i].size(); ++j) {
               sp<ProClient> cl = mProClientList[i][j].promote();
               if (cl != NULL) {
                   clientsToDisconnect.push_back(cl);
               }
           }
        }

        /* now disconnect them. don't hold the lock
           or we can get into a deadlock */

        for (size_t i = 0; i < clientsToDisconnect.size(); ++i) {
            sp<BasicClient> client = clientsToDisconnect[i];

            client->disconnect();
            /**
             * The remote app will no longer be able to call methods on the
             * client since the client PID will be reset to 0
             */
        }

        ALOGV("%s: After unplug, disconnected %d clients",
              __FUNCTION__, clientsToDisconnect.size());
    }

    updateStatus(
            static_cast<ICameraServiceListener::Status>(newStatus), cameraId);

}

int32_t CameraService::getNumberOfCameras() {
    return mNumberOfCameras;
}
@@ -212,6 +294,19 @@ bool CameraService::validateConnect(int cameraId,
        return false;
    }

    ICameraServiceListener::Status currentStatus = getStatus(cameraId);
    if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
        ALOGI("Camera is not plugged in,"
               " connect X (pid %d) rejected", callingPid);
        return false;
    } else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
        ALOGI("Camera is enumerating,"
               " connect X (pid %d) rejected", callingPid);
        return false;
    }
    // Else don't check for STATUS_NOT_AVAILABLE.
    //  -- It's done implicitly in canConnectUnsafe /w the mBusy array

    return true;
}

@@ -293,6 +388,7 @@ sp<ICamera> CameraService::connect(
        // If there are other non-exclusive users of the camera,
        //  this will tear them down before we can reuse the camera
        if (isValidCameraId(cameraId)) {
            // transition from PRESENT -> NOT_AVAILABLE
            updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
                         cameraId);
        }
@@ -321,7 +417,8 @@ sp<ICamera> CameraService::connect(

        if (!connectFinishUnsafe(client, client->asBinder())) {
            // this is probably not recoverable.. maybe the client can try again
            updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
            // OK: we can only get here if we were originally in PRESENT state
            updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);

            return NULL;
        }
@@ -429,6 +526,15 @@ status_t CameraService::addListener(

    mListenerList.push_back(listener);

    /* Immediately signal current status to this listener only */
    {
        Mutex::Autolock m(mStatusMutex) ;
        int numCams = getNumberOfCameras();
        for (int i = 0; i < numCams; ++i) {
            listener->onStatusChanged(mStatusList[i], i);
        }
    }

    return OK;
}
status_t CameraService::removeListener(
@@ -719,6 +825,8 @@ CameraService::BasicClient::~BasicClient() {

void CameraService::BasicClient::disconnect() {
    mCameraService->removeClientByRemote(mRemoteBinder);
    // client shouldn't be able to call into us anymore
    mClientPid = 0;
}

status_t CameraService::BasicClient::startCameraOps() {
@@ -816,7 +924,7 @@ void CameraService::Client::notifyError() {
void CameraService::Client::disconnect() {
    BasicClient::disconnect();
    mCameraService->setCameraFree(mCameraId);
    mCameraService->updateStatus(ICameraServiceListener::STATUS_AVAILABLE,
    mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
                                 mCameraId);
}

@@ -1017,6 +1125,16 @@ void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
        ALOGV("%s: Status has changed for camera ID %d from 0x%x to 0x%x",
              __FUNCTION__, cameraId, (uint32_t)oldStatus, (uint32_t)status);

        if (oldStatus == ICameraServiceListener::STATUS_NOT_PRESENT &&
            (status != ICameraServiceListener::STATUS_PRESENT &&
             status != ICameraServiceListener::STATUS_ENUMERATING)) {

            ALOGW("%s: From NOT_PRESENT can only transition into PRESENT"
                  " or ENUMERATING", __FUNCTION__);
            mStatusList[cameraId] = oldStatus;
            return;
        }

        /**
          * ProClients lose their exclusive lock.
          * - Done before the CameraClient can initialize the HAL device,
@@ -1041,4 +1159,14 @@ void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
    }
}

ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
    if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
        return ICameraServiceListener::STATUS_UNKNOWN;
    }

    Mutex::Autolock al(mStatusMutex);
    return mStatusList[cameraId];
}

}; // namespace android
+12 −2
Original line number Diff line number Diff line
@@ -45,7 +45,8 @@ class MediaPlayer;
class CameraService :
    public BinderService<CameraService>,
    public BnCameraService,
    public IBinder::DeathRecipient
    public IBinder::DeathRecipient,
    public camera_module_callbacks_t
{
    friend class BinderService<CameraService>;
public:
@@ -58,6 +59,11 @@ public:
                        CameraService();
    virtual             ~CameraService();

    /////////////////////////////////////////////////////////////////////
    // HAL Callbacks
    virtual void        onDeviceStatusChanged(int cameraId,
                                              int newStatus);

    /////////////////////////////////////////////////////////////////////
    // ICameraService
    virtual int32_t     getNumberOfCameras();
@@ -327,10 +333,14 @@ private:
                        mListenerList;

    // guard only mStatusList and the broadcasting of ICameraServiceListener
    Mutex               mStatusMutex;
    mutable Mutex       mStatusMutex;
    ICameraServiceListener::Status
                        mStatusList[MAX_CAMERAS];

    // Read the current status (locks mStatusMutex)
    ICameraServiceListener::Status
                        getStatus(int cameraId) const;

    // Broadcast the new status if it changed (locks the service mutex)
    void                updateStatus(
                            ICameraServiceListener::Status status,