diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp index c53e6c3358..aecb70abad 100644 --- a/camera/CameraBase.cpp +++ b/camera/CameraBase.cpp @@ -60,6 +60,13 @@ status_t CameraStatus::writeToParcel(android::Parcel* parcel) const { if (res != OK) return res; res = parcel->writeInt32(status); + if (res != OK) return res; + + std::vector unavailablePhysicalIds16; + for (auto& id8 : unavailablePhysicalIds) { + unavailablePhysicalIds16.push_back(String16(id8)); + } + res = parcel->writeString16Vector(unavailablePhysicalIds16); return res; } @@ -70,6 +77,14 @@ status_t CameraStatus::readFromParcel(const android::Parcel* parcel) { cameraId = String8(tempCameraId); res = parcel->readInt32(&status); + if (res != OK) return res; + + std::vector unavailablePhysicalIds16; + res = parcel->readString16Vector(&unavailablePhysicalIds16); + if (res != OK) return res; + for (auto& id16 : unavailablePhysicalIds16) { + unavailablePhysicalIds.push_back(String8(id16)); + } return res; } diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl index e9dcbdb6f6..81657fd675 100644 --- a/camera/aidl/android/hardware/ICameraServiceListener.aidl +++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl @@ -53,6 +53,12 @@ interface ICameraServiceListener oneway void onStatusChanged(int status, String cameraId); + /** + * Notify registered client about status changes for a physical camera backing + * a logical camera. + */ + oneway void onPhysicalCameraStatusChanged(int status, String cameraId, String physicalCameraId); + /** * The torch mode status of a camera. * diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp index 320c499c2c..22e9578da3 100644 --- a/camera/cameraserver/Android.bp +++ b/camera/cameraserver/Android.bp @@ -32,6 +32,7 @@ cc_binary { "android.hardware.camera.common@1.0", "android.hardware.camera.provider@2.4", "android.hardware.camera.provider@2.5", + "android.hardware.camera.provider@2.6", "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.4", diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h index 74a2dce29a..499b0e6b09 100644 --- a/camera/include/camera/CameraBase.h +++ b/camera/include/camera/CameraBase.h @@ -80,10 +80,16 @@ struct CameraStatus : public android::Parcelable { */ int32_t status; + /** + * Unavailable physical camera names for a multi-camera device + */ + std::vector unavailablePhysicalIds; + virtual status_t writeToParcel(android::Parcel* parcel) const; virtual status_t readFromParcel(const android::Parcel* parcel); - CameraStatus(String8 id, int32_t s) : cameraId(id), status(s) {} + CameraStatus(String8 id, int32_t s, const std::vector& unavailSubIds) : + cameraId(id), status(s), unavailablePhysicalIds(unavailSubIds) {} CameraStatus() : status(ICameraServiceListener::STATUS_PRESENT) {} }; diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp index 7a0f63bc13..4870265770 100644 --- a/camera/ndk/impl/ACameraManager.cpp +++ b/camera/ndk/impl/ACameraManager.cpp @@ -32,6 +32,7 @@ namespace android { namespace acam { // Static member definitions const char* CameraManagerGlobal::kCameraIdKey = "CameraId"; +const char* CameraManagerGlobal::kPhysicalCameraIdKey = "PhysicalCameraId"; const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp"; const char* CameraManagerGlobal::kContextKey = "CallbackContext"; Mutex CameraManagerGlobal::sLock; @@ -220,7 +221,7 @@ void CameraManagerGlobal::registerAvailabilityCallback( if (pair.second) { for (auto& pair : mDeviceStatusMap) { const String8& cameraId = pair.first; - int32_t status = pair.second.status; + int32_t status = pair.second.getStatus(); // Don't send initial callbacks for camera ids which don't support // camera2 if (!pair.second.supportsHAL3) { @@ -264,9 +265,9 @@ void CameraManagerGlobal::getCameraIdList(std::vector* cameraIds) { // Needed to make sure we're connected to cameraservice getCameraServiceLocked(); for(auto& deviceStatus : mDeviceStatusMap) { - if (deviceStatus.second.status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT || - deviceStatus.second.status == - hardware::ICameraServiceListener::STATUS_ENUMERATING) { + int32_t status = deviceStatus.second.getStatus(); + if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT || + status == hardware::ICameraServiceListener::STATUS_ENUMERATING) { continue; } if (!deviceStatus.second.supportsHAL3) { @@ -341,6 +342,39 @@ void CameraManagerGlobal::CallbackHandler::onMessageReceived( (*cb)(context); break; } + case kWhatSendSinglePhysicalCameraCallback: + { + ACameraManager_PhysicalCameraAvailabilityCallback cb; + void* context; + AString cameraId; + AString physicalCameraId; + bool found = msg->findPointer(kCallbackFpKey, (void**) &cb); + if (!found) { + ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__); + return; + } + if (cb == nullptr) { + // Physical camera callback is null + return; + } + found = msg->findPointer(kContextKey, &context); + if (!found) { + ALOGE("%s: Cannot find callback context!", __FUNCTION__); + return; + } + found = msg->findString(kCameraIdKey, &cameraId); + if (!found) { + ALOGE("%s: Cannot find camera ID!", __FUNCTION__); + return; + } + found = msg->findString(kPhysicalCameraIdKey, &physicalCameraId); + if (!found) { + ALOGE("%s: Cannot find physical camera ID!", __FUNCTION__); + return; + } + (*cb)(context, cameraId.c_str(), physicalCameraId.c_str()); + break; + } default: ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what()); break; @@ -368,6 +402,17 @@ binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged( return binder::Status::ok(); } +binder::Status CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged( + int32_t status, const String16& cameraId, const String16& physicalCameraId) { + sp cm = mCameraManager.promote(); + if (cm != nullptr) { + cm->onStatusChanged(status, String8(cameraId), String8(physicalCameraId)); + } else { + ALOGE("Cannot deliver physical camera status change. Global camera manager died"); + } + return binder::Status::ok(); +} + void CameraManagerGlobal::onCameraAccessPrioritiesChanged() { Mutex::Autolock _l(mLock); for (auto cb : mCallbacks) { @@ -397,7 +442,7 @@ void CameraManagerGlobal::onStatusChangedLocked( bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0); int32_t oldStatus = firstStatus ? status : // first status - mDeviceStatusMap[cameraId].status; + mDeviceStatusMap[cameraId].getStatus(); if (!firstStatus && isStatusAvailable(status) == isStatusAvailable(oldStatus)) { @@ -406,8 +451,14 @@ void CameraManagerGlobal::onStatusChangedLocked( } bool supportsHAL3 = supportsCamera2ApiLocked(cameraId); + if (firstStatus) { + mDeviceStatusMap.emplace(std::piecewise_construct, + std::forward_as_tuple(cameraId), + std::forward_as_tuple(status, supportsHAL3)); + } else { + mDeviceStatusMap[cameraId].updateStatus(status); + } // Iterate through all registered callbacks - mDeviceStatusMap[cameraId] = StatusAndHAL3Support(status, supportsHAL3); if (supportsHAL3) { for (auto cb : mCallbacks) { sp msg = new AMessage(kWhatSendSingleCallback, mHandler); @@ -424,6 +475,81 @@ void CameraManagerGlobal::onStatusChangedLocked( } } +void CameraManagerGlobal::onStatusChanged( + int32_t status, const String8& cameraId, const String8& physicalCameraId) { + Mutex::Autolock _l(mLock); + onStatusChangedLocked(status, cameraId, physicalCameraId); +} + +void CameraManagerGlobal::onStatusChangedLocked( + int32_t status, const String8& cameraId, const String8& physicalCameraId) { + if (!validStatus(status)) { + ALOGE("%s: Invalid status %d", __FUNCTION__, status); + return; + } + + auto logicalStatus = mDeviceStatusMap.find(cameraId); + if (logicalStatus == mDeviceStatusMap.end()) { + ALOGE("%s: Physical camera id %s status change on a non-present id %s", + __FUNCTION__, physicalCameraId.c_str(), cameraId.c_str()); + return; + } + int32_t logicalCamStatus = mDeviceStatusMap[cameraId].getStatus(); + if (logicalCamStatus != hardware::ICameraServiceListener::STATUS_PRESENT && + logicalCamStatus != hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE) { + ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d", + __FUNCTION__, physicalCameraId.string(), status, logicalCamStatus); + return; + } + + bool supportsHAL3 = supportsCamera2ApiLocked(cameraId); + + bool updated = false; + if (status == hardware::ICameraServiceListener::STATUS_PRESENT) { + updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId); + } else { + updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId); + } + + // Iterate through all registered callbacks + if (supportsHAL3 && updated) { + for (auto cb : mCallbacks) { + sp msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler); + ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ? + cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable; + msg->setPointer(kCallbackFpKey, (void *) cbFp); + msg->setPointer(kContextKey, cb.mContext); + msg->setString(kCameraIdKey, AString(cameraId)); + msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId)); + msg->post(); + } + } +} + +int32_t CameraManagerGlobal::StatusAndHAL3Support::getStatus() { + std::lock_guard lock(mLock); + return status; +} + +void CameraManagerGlobal::StatusAndHAL3Support::updateStatus(int32_t newStatus) { + std::lock_guard lock(mLock); + status = newStatus; +} + +bool CameraManagerGlobal::StatusAndHAL3Support::addUnavailablePhysicalId( + const String8& physicalCameraId) { + std::lock_guard lock(mLock); + auto result = unavailablePhysicalIds.insert(physicalCameraId); + return result.second; +} + +bool CameraManagerGlobal::StatusAndHAL3Support::removeUnavailablePhysicalId( + const String8& physicalCameraId) { + std::lock_guard lock(mLock); + auto count = unavailablePhysicalIds.erase(physicalCameraId); + return count > 0; +} + } // namespace acam } // namespace android diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h index e945ba0cbd..98cd934865 100644 --- a/camera/ndk/impl/ACameraManager.h +++ b/camera/ndk/impl/ACameraManager.h @@ -85,6 +85,8 @@ class CameraManagerGlobal final : public RefBase { public: explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {} virtual binder::Status onStatusChanged(int32_t status, const String16& cameraId); + virtual binder::Status onPhysicalCameraStatusChanged(int32_t status, + const String16& cameraId, const String16& physicalCameraId); // Torch API not implemented yet virtual binder::Status onTorchStatusChanged(int32_t, const String16&) { @@ -104,18 +106,24 @@ class CameraManagerGlobal final : public RefBase { mAvailable(callback->onCameraAvailable), mUnavailable(callback->onCameraUnavailable), mAccessPriorityChanged(nullptr), + mPhysicalCamAvailable(nullptr), + mPhysicalCamUnavailable(nullptr), mContext(callback->context) {} explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) : mAvailable(callback->availabilityCallbacks.onCameraAvailable), mUnavailable(callback->availabilityCallbacks.onCameraUnavailable), mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged), + mPhysicalCamAvailable(callback->onPhysicalCameraAvailable), + mPhysicalCamUnavailable(callback->onPhysicalCameraUnavailable), mContext(callback->availabilityCallbacks.context) {} bool operator == (const Callback& other) const { return (mAvailable == other.mAvailable && mUnavailable == other.mUnavailable && mAccessPriorityChanged == other.mAccessPriorityChanged && + mPhysicalCamAvailable == other.mPhysicalCamAvailable && + mPhysicalCamUnavailable == other.mPhysicalCamUnavailable && mContext == other.mContext); } bool operator != (const Callback& other) const { @@ -124,6 +132,12 @@ class CameraManagerGlobal final : public RefBase { bool operator < (const Callback& other) const { if (*this == other) return false; if (mContext != other.mContext) return mContext < other.mContext; + if (mPhysicalCamAvailable != other.mPhysicalCamAvailable) { + return mPhysicalCamAvailable < other.mPhysicalCamAvailable; + } + if (mPhysicalCamUnavailable != other.mPhysicalCamUnavailable) { + return mPhysicalCamUnavailable < other.mPhysicalCamUnavailable; + } if (mAccessPriorityChanged != other.mAccessPriorityChanged) { return mAccessPriorityChanged < other.mAccessPriorityChanged; } @@ -136,6 +150,8 @@ class CameraManagerGlobal final : public RefBase { ACameraManager_AvailabilityCallback mAvailable; ACameraManager_AvailabilityCallback mUnavailable; ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged; + ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamAvailable; + ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable; void* mContext; }; std::set mCallbacks; @@ -144,8 +160,10 @@ class CameraManagerGlobal final : public RefBase { enum { kWhatSendSingleCallback, kWhatSendSingleAccessCallback, + kWhatSendSinglePhysicalCameraCallback, }; static const char* kCameraIdKey; + static const char* kPhysicalCameraIdKey; static const char* kCallbackFpKey; static const char* kContextKey; class CallbackHandler : public AHandler { @@ -160,6 +178,9 @@ class CameraManagerGlobal final : public RefBase { void onCameraAccessPrioritiesChanged(); void onStatusChanged(int32_t status, const String8& cameraId); void onStatusChangedLocked(int32_t status, const String8& cameraId); + void onStatusChanged(int32_t status, const String8& cameraId, const String8& physicalCameraId); + void onStatusChangedLocked(int32_t status, const String8& cameraId, + const String8& physicalCameraId); // Utils for status static bool validStatus(int32_t status); static bool isStatusAvailable(int32_t status); @@ -187,11 +208,20 @@ class CameraManagerGlobal final : public RefBase { }; struct StatusAndHAL3Support { + private: int32_t status = hardware::ICameraServiceListener::STATUS_NOT_PRESENT; - bool supportsHAL3 = false; + mutable std::mutex mLock; + std::set unavailablePhysicalIds; + public: + const bool supportsHAL3 = false; StatusAndHAL3Support(int32_t st, bool HAL3support): status(st), supportsHAL3(HAL3support) { }; StatusAndHAL3Support() = default; + + bool addUnavailablePhysicalId(const String8& physicalCameraId); + bool removeUnavailablePhysicalId(const String8& physicalCameraId); + int32_t getStatus(); + void updateStatus(int32_t newStatus); }; // Map camera_id -> status diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h index 2cc8a9743b..e2b71bf017 100644 --- a/camera/ndk/include/camera/NdkCameraManager.h +++ b/camera/ndk/include/camera/NdkCameraManager.h @@ -122,6 +122,21 @@ void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList) __INTRODUCED typedef void (*ACameraManager_AvailabilityCallback)(void* context, const char* cameraId); +/** + * Definition of physical camera availability callbacks. + * + * @param context The optional application context provided by user in + * {@link ACameraManager_AvailabilityCallbacks}. + * @param cameraId The ID of the logical multi-camera device whose physical camera status is + * changing. The memory of this argument is owned by camera framework and will + * become invalid immediately after this callback returns. + * @param physicalCameraId The ID of the physical camera device whose status is changing. The + * memory of this argument is owned by camera framework and will become invalid + * immediately after this callback returns. + */ +typedef void (*ACameraManager_PhysicalCameraAvailabilityCallback)(void* context, + const char* cameraId, const char* physicalCameraId); + /** * A listener for camera devices becoming available or unavailable to open. * @@ -320,8 +335,15 @@ typedef struct ACameraManager_ExtendedAvailabilityListener { /// Called when there is camera access permission change ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged; + /// Called when a physical camera becomes available + ACameraManager_PhysicalCameraAvailabilityCallback onPhysicalCameraAvailable __INTRODUCED_IN(30); + + /// Called when a physical camera becomes unavailable + ACameraManager_PhysicalCameraAvailabilityCallback onPhysicalCameraUnavailable + __INTRODUCED_IN(30); + /// Reserved for future use, please ensure that all entries are set to NULL - void *reserved[6]; + void *reserved[4]; } ACameraManager_ExtendedAvailabilityCallbacks; /** diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h index 3ac3ded451..8b371db9c9 100644 --- a/camera/ndk/include/camera/NdkCameraMetadataTags.h +++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h @@ -7941,14 +7941,20 @@ typedef enum acamera_metadata_enum_acamera_request_available_capabilities { *

The camera device is a logical camera backed by two or more physical cameras.

*

In API level 28, the physical cameras must also be exposed to the application via * CameraManager#getCameraIdList.

- *

Starting from API level 29, some or all physical cameras may not be independently - * exposed to the application, in which case the physical camera IDs will not be - * available in CameraManager#getCameraIdList. But the + *

Starting from API level 29:

+ *
    + *
  • Some or all physical cameras may not be independently exposed to the application, + * in which case the physical camera IDs will not be available in + * CameraManager#getCameraIdList. But the * application can still query the physical cameras' characteristics by calling - * CameraManager#getCameraCharacteristics. Additionally, - * if a physical camera is hidden from camera ID list, the mandatory stream combinations - * for that physical camera must be supported through the logical camera using physical - * streams.

    + * CameraManager#getCameraCharacteristics.
  • + *
  • If a physical camera is hidden from camera ID list, the mandatory stream + * combinations for that physical camera must be supported through the logical camera + * using physical streams. One exception is that in API level 30, a physical camera + * may become unavailable via + * {@link ACameraManager_PhysicalCameraAvailabilityCallback } + * callback.
  • + *
*

Combinations of logical and physical streams, or physical streams from different * physical cameras are not guaranteed. However, if the camera device supports * {@link ACameraDevice_isSessionConfigurationSupported }, diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp index cd5bdd1cb9..571cf59e49 100644 --- a/camera/tests/CameraBinderTests.cpp +++ b/camera/tests/CameraBinderTests.cpp @@ -83,6 +83,12 @@ public: return binder::Status::ok(); }; + virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/, + const String16& /*cameraId*/, const String16& /*physicalCameraId*/) { + // No op + return binder::Status::ok(); + }; + virtual binder::Status onTorchStatusChanged(int32_t status, const String16& cameraId) { Mutex::Autolock l(mLock); mCameraTorchStatuses[cameraId] = status; diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp index 496a21b6dc..87cb0b5787 100644 --- a/services/camera/libcameraservice/Android.bp +++ b/services/camera/libcameraservice/Android.bp @@ -117,6 +117,7 @@ cc_library_shared { "android.hardware.camera.common@1.0", "android.hardware.camera.provider@2.4", "android.hardware.camera.provider@2.5", + "android.hardware.camera.provider@2.6", "android.hardware.camera.device@1.0", "android.hardware.camera.device@3.2", "android.hardware.camera.device@3.3", diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 2fe717939b..8666b7bd14 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -420,7 +420,52 @@ void CameraService::onDeviceStatusChanged(const String8& id, } updateStatus(newStatus, id); } +} + +void CameraService::onDeviceStatusChanged(const String8& id, + const String8& physicalId, + CameraDeviceStatus newHalStatus) { + ALOGI("%s: Status changed for cameraId=%s, physicalCameraId=%s, newStatus=%d", + __FUNCTION__, id.string(), physicalId.string(), newHalStatus); + + StatusInternal newStatus = mapToInternal(newHalStatus); + std::shared_ptr state = getCameraState(id); + + if (state == nullptr) { + ALOGE("%s: Physical camera id %s status change on a non-present ID %s", + __FUNCTION__, id.string(), physicalId.string()); + return; + } + + StatusInternal logicalCameraStatus = state->getStatus(); + if (logicalCameraStatus != StatusInternal::PRESENT && + logicalCameraStatus != StatusInternal::NOT_AVAILABLE) { + ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d", + __FUNCTION__, physicalId.string(), newHalStatus, logicalCameraStatus); + return; + } + + bool updated = false; + if (newStatus == StatusInternal::PRESENT) { + updated = state->removeUnavailablePhysicalId(physicalId); + } else { + updated = state->addUnavailablePhysicalId(physicalId); + } + + if (updated) { + logDeviceRemoved(id, String8::format("Device %s-%s availability changed from %d to %d", + id.string(), physicalId.string(), + newStatus != StatusInternal::PRESENT, + newStatus == StatusInternal::PRESENT)); + + String16 id16(id), physicalId16(physicalId); + Mutex::Autolock lock(mStatusListenerLock); + for (auto& listener : mListenerList) { + listener->getListener()->onPhysicalCameraStatusChanged(mapToInterface(newStatus), + id16, physicalId16); + } + } } void CameraService::disconnectClient(const String8& id, sp clientToDisconnect) { @@ -2045,7 +2090,8 @@ Status CameraService::addListenerHelper(const sp& listen { Mutex::Autolock lock(mCameraStatesLock); for (auto& i : mCameraStates) { - cameraStatuses->emplace_back(i.first, mapToInterface(i.second->getStatus())); + cameraStatuses->emplace_back(i.first, + mapToInterface(i.second->getStatus()), i.second->getUnavailablePhysicalIds()); } } // Remove the camera statuses that should be hidden from the client, we do @@ -3188,6 +3234,12 @@ CameraService::StatusInternal CameraService::CameraState::getStatus() const { return mStatus; } +std::vector CameraService::CameraState::getUnavailablePhysicalIds() const { + Mutex::Autolock lock(mStatusLock); + std::vector res(mUnavailablePhysicalIds.begin(), mUnavailablePhysicalIds.end()); + return res; +} + CameraParameters CameraService::CameraState::getShimParams() const { return mShimParams; } @@ -3212,6 +3264,18 @@ SystemCameraKind CameraService::CameraState::getSystemCameraKind() const { return mSystemCameraKind; } +bool CameraService::CameraState::addUnavailablePhysicalId(const String8& physicalId) { + Mutex::Autolock lock(mStatusLock); + auto result = mUnavailablePhysicalIds.insert(physicalId); + return result.second; +} + +bool CameraService::CameraState::removeUnavailablePhysicalId(const String8& physicalId) { + Mutex::Autolock lock(mStatusLock); + auto count = mUnavailablePhysicalIds.erase(physicalId); + return count > 0; +} + // ---------------------------------------------------------------------------- // ClientEventListener // ---------------------------------------------------------------------------- @@ -3569,7 +3633,7 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId, return; } // Update the status for this camera state, then send the onStatusChangedCallbacks to each - // of the listeners with both the mStatusStatus and mStatusListenerLock held + // of the listeners with both the mStatusLock and mStatusListenerLock held state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3] (const String8& cameraId, StatusInternal status) { @@ -3591,6 +3655,8 @@ void CameraService::updateStatus(StatusInternal status, const String8& cameraId, Mutex::Autolock lock(mStatusListenerLock); + notifyPhysicalCameraStatusLocked(mapToInterface(status), cameraId); + for (auto& listener : mListenerList) { bool isVendorListener = listener->isVendorListener(); if (shouldSkipStatusUpdates(deviceKind, isVendorListener, @@ -3684,6 +3750,28 @@ status_t CameraService::setTorchStatusLocked(const String8& cameraId, return OK; } +void CameraService::notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId) { + Mutex::Autolock lock(mCameraStatesLock); + for (const auto& state : mCameraStates) { + std::vector physicalCameraIds; + if (!mCameraProviderManager->isLogicalCamera(state.first.c_str(), &physicalCameraIds)) { + // This is not a logical multi-camera. + continue; + } + if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), cameraId.c_str()) + == physicalCameraIds.end()) { + // cameraId is not a physical camera of this logical multi-camera. + continue; + } + + String16 id16(state.first), physicalId16(cameraId); + for (auto& listener : mListenerList) { + listener->getListener()->onPhysicalCameraStatusChanged(status, + id16, physicalId16); + } + } +} + void CameraService::blockClientsForUid(uid_t uid) { const auto clients = mActiveClientManager.getAll(); for (auto& current : clients) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 726cb0f4a1..34b970d29e 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -103,6 +103,9 @@ public: virtual void onDeviceStatusChanged(const String8 &cameraId, hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override; + virtual void onDeviceStatusChanged(const String8 &cameraId, + const String8 &physicalCameraId, + hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override; virtual void onTorchStatusChanged(const String8& cameraId, hardware::camera::common::V1_0::TorchModeStatus newStatus) override; virtual void onNewProviderRegistered() override; @@ -556,11 +559,24 @@ private: */ SystemCameraKind getSystemCameraKind() const; + /** + * Add/Remove the unavailable physical camera ID. + */ + bool addUnavailablePhysicalId(const String8& physicalId); + bool removeUnavailablePhysicalId(const String8& physicalId); + + /** + * Return the unavailable physical ids for this device. + * + * This method acquires mStatusLock. + */ + std::vector getUnavailablePhysicalIds() const; private: const String8 mId; StatusInternal mStatus; // protected by mStatusLock const int mCost; std::set mConflicting; + std::set mUnavailablePhysicalIds; mutable Mutex mStatusLock; CameraParameters mShimParams; const SystemCameraKind mSystemCameraKind; @@ -962,6 +978,9 @@ private: status_t setTorchStatusLocked(const String8 &cameraId, hardware::camera::common::V1_0::TorchModeStatus status); + // notify physical camera status when the physical camera is public. + void notifyPhysicalCameraStatusLocked(int32_t status, const String8& cameraId); + // IBinder::DeathRecipient implementation virtual void binderDied(const wp &who); diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 0f74a48af6..57f812ff48 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp @@ -1255,20 +1255,6 @@ status_t CameraProviderManager::ProviderInfo::initialize( mMinorVersion = 4; } - // cameraDeviceStatusChange callbacks may be called (and causing new devices added) - // before setCallback returns - hardware::Return status = interface->setCallback(this); - if (!status.isOk()) { - ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s", - __FUNCTION__, mProviderName.c_str(), status.description().c_str()); - return DEAD_OBJECT; - } - if (status != Status::OK) { - ALOGE("%s: Unable to register callbacks with camera provider '%s'", - __FUNCTION__, mProviderName.c_str()); - return mapToStatusT(status); - } - hardware::Return linked = interface->linkToDeath(this, /*cookie*/ mId); if (!linked.isOk()) { ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s", @@ -1297,6 +1283,7 @@ status_t CameraProviderManager::ProviderInfo::initialize( return res; } + Status status; // Get initial list of camera devices, if any std::vector devices; hardware::Return ret = interface->getCameraIdList([&status, this, &devices]( @@ -1353,6 +1340,22 @@ status_t CameraProviderManager::ProviderInfo::initialize( } } + // cameraDeviceStatusChange callbacks may be called (and causing new devices added) + // before setCallback returns. setCallback must be called after addDevice so that + // the physical camera status callback can look up available regular + // cameras. + hardware::Return st = interface->setCallback(this); + if (!st.isOk()) { + ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s", + __FUNCTION__, mProviderName.c_str(), st.description().c_str()); + return DEAD_OBJECT; + } + if (st != Status::OK) { + ALOGE("%s: Unable to register callbacks with camera provider '%s'", + __FUNCTION__, mProviderName.c_str()); + return mapToStatusT(st); + } + ALOGI("Camera provider %s ready with %zu camera devices", mProviderName.c_str(), mDevices.size()); @@ -1604,6 +1607,61 @@ hardware::Return CameraProviderManager::ProviderInfo::cameraDeviceStatusCh return hardware::Void(); } +hardware::Return CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange( + const hardware::hidl_string& cameraDeviceName, + const hardware::hidl_string& physicalCameraDeviceName, + CameraDeviceStatus newStatus) { + sp listener; + std::string id; + bool initialized = false; + { + std::lock_guard lock(mLock); + bool known = false; + for (auto& deviceInfo : mDevices) { + if (deviceInfo->mName == cameraDeviceName) { + id = deviceInfo->mId; + + if (!deviceInfo->mIsLogicalCamera) { + ALOGE("%s: Invalid combination of camera id %s, physical id %s", + __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str()); + return hardware::Void(); + } + if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(), + physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) { + ALOGE("%s: Invalid combination of camera id %s, physical id %s", + __FUNCTION__, id.c_str(), physicalCameraDeviceName.c_str()); + return hardware::Void(); + } + ALOGI("Camera device %s physical device %s status is now %s, was %s", + cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), + deviceStatusToString(newStatus), deviceStatusToString( + deviceInfo->mPhysicalStatus[physicalCameraDeviceName])); + known = true; + break; + } + } + // Previously unseen device; status must not be NOT_PRESENT + if (!known) { + ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.", + mProviderName.c_str(), cameraDeviceName.c_str(), + physicalCameraDeviceName.c_str()); + return hardware::Void(); + } + listener = mManager->getStatusListener(); + initialized = mInitialized; + } + // Call without lock held to allow reentrancy into provider manager + // Don't send the callback if providerInfo hasn't been initialized. + // CameraService will initialize device status after provider is + // initialized + if (listener != nullptr && initialized) { + String8 physicalId(physicalCameraDeviceName.c_str()); + listener->onDeviceStatusChanged(String8(id.c_str()), + physicalId, newStatus); + } + return hardware::Void(); +} + hardware::Return CameraProviderManager::ProviderInfo::torchModeStatusChange( const hardware::hidl_string& cameraDeviceName, TorchModeStatus newStatus) { diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h index 58df0e845b..3eba162933 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.h +++ b/services/camera/libcameraservice/common/CameraProviderManager.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,9 @@ public: virtual void onDeviceStatusChanged(const String8 &cameraId, hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0; + virtual void onDeviceStatusChanged(const String8 &cameraId, + const String8 &physicalCameraId, + hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0; virtual void onTorchStatusChanged(const String8 &cameraId, hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0; virtual void onNewProviderRegistered() = 0; @@ -342,7 +346,7 @@ private: std::mutex mProviderInterfaceMapLock; struct ProviderInfo : - virtual public hardware::camera::provider::V2_4::ICameraProviderCallback, + virtual public hardware::camera::provider::V2_6::ICameraProviderCallback, virtual public hardware::hidl_death_recipient { const std::string mProviderName; @@ -380,12 +384,16 @@ private: status_t dump(int fd, const Vector& args) const; // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex - virtual hardware::Return cameraDeviceStatusChange( + hardware::Return cameraDeviceStatusChange( const hardware::hidl_string& cameraDeviceName, hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override; - virtual hardware::Return torchModeStatusChange( + hardware::Return torchModeStatusChange( const hardware::hidl_string& cameraDeviceName, hardware::camera::common::V1_0::TorchModeStatus newStatus) override; + hardware::Return physicalCameraDeviceStatusChange( + const hardware::hidl_string& cameraDeviceName, + const hardware::hidl_string& physicalCameraDeviceName, + hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override; // hidl_death_recipient interface - this locks the parent mInterfaceMutex virtual void serviceDied(uint64_t cookie, const wp& who) override; @@ -417,6 +425,8 @@ private: const hardware::camera::common::V1_0::CameraResourceCost mResourceCost; hardware::camera::common::V1_0::CameraDeviceStatus mStatus; + std::map + mPhysicalStatus; sp mParentProvider; diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h index 0f6be79be0..175eb8e941 100644 --- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h +++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h @@ -46,12 +46,18 @@ struct H2BCameraServiceListener : ~H2BCameraServiceListener() { } virtual ::android::binder::Status onStatusChanged(int32_t status, - const ::android::String16& cameraId) override; + const ::android::String16& cameraId) override; + virtual ::android::binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/, + const ::android::String16& /*cameraId*/, + const ::android::String16& /*physicalCameraId*/) override { + // no implementation yet. + return binder::Status::ok(); + } virtual ::android::binder::Status onTorchStatusChanged( - int32_t status, const ::android::String16& cameraId) override; + int32_t status, const ::android::String16& cameraId) override; virtual binder::Status onCameraAccessPrioritiesChanged() { - // TODO: no implementation yet. + // TODO: no implementation yet. b/148146086 return binder::Status::ok(); } }; diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk index ec5e876c77..ea4eb3b3b9 100644 --- a/services/camera/libcameraservice/tests/Android.mk +++ b/services/camera/libcameraservice/tests/Android.mk @@ -31,6 +31,7 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.camera.common@1.0 \ android.hardware.camera.provider@2.4 \ android.hardware.camera.provider@2.5 \ + android.hardware.camera.provider@2.6 \ android.hardware.camera.device@1.0 \ android.hardware.camera.device@3.2 \ android.hardware.camera.device@3.4 diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp index 084dc62adb..a8f6889a1d 100644 --- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp +++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp @@ -236,6 +236,8 @@ struct TestStatusListener : public CameraProviderManager::StatusListener { void onDeviceStatusChanged(const String8 &, hardware::camera::common::V1_0::CameraDeviceStatus) override {} + void onDeviceStatusChanged(const String8 &, const String8 &, + hardware::camera::common::V1_0::CameraDeviceStatus) override {} void onTorchStatusChanged(const String8 &, hardware::camera::common::V1_0::TorchModeStatus) override {} void onNewProviderRegistered() override {}