Snap for 14805172 from eba1fb4f9c8072e6aaa8e4cb248147c1cf8e1ec8 to internal-android15-automotiveos-lts-release Change-Id: I5a80e13dc5a69ef64ecb324682aee87110c3aab2
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl index ce6c2d3..6431737 100644 --- a/camera/aidl/android/hardware/ICameraService.aidl +++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -157,6 +157,7 @@ * policy for default device context). Only virtual cameras would be exposed * only for custom policy and only real cameras would be exposed for default * policy. + * @param sharedMode Parameter specifying if the camera should be opened in shared mode. */ ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks, @utf8InCpp String cameraId, @@ -164,7 +165,8 @@ int targetSdkVersion, int rotationOverride, in AttributionSourceState clientAttribution, - int devicePolicy); + int devicePolicy, + boolean sharedMode); /** * Add listener for changes to camera device and flashlight state.
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl index 9c8c88a..c0fd50e 100644 --- a/camera/aidl/android/hardware/ICameraServiceListener.aidl +++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -105,5 +105,6 @@ * will receive such callbacks. */ oneway void onCameraOpened(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId, int deviceId); + oneway void onCameraOpenedInSharedMode(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId, int deviceId, boolean primaryClient); oneway void onCameraClosed(@utf8InCpp String cameraId, int deviceId); }
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl index 58b19a3..49e9920 100644 --- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl +++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -50,4 +50,15 @@ oneway void onRepeatingRequestError(in long lastFrameNumber, in int repeatingRequestId); oneway void onRequestQueueEmpty(); + + /** + * Notify registered clients about client shared access priority changes when the camera device + * has been opened in shared mode. + * + * If the client priority changes from secondary to primary, then it can now + * create capture request and change the capture request parameters. If client priority + * changes from primary to secondary, that implies that another higher priority client is also + * accessing the camera in shared mode and is now the primary client. + */ + oneway void onClientSharedAccessPriorityChanged(boolean primaryClient); }
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl index 8e1fcc0..30566c8 100644 --- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -34,6 +34,20 @@ SubmitInfo submitRequest(in CaptureRequest request, boolean streaming); SubmitInfo submitRequestList(in CaptureRequest[] requestList, boolean streaming); + /** + * When a camera device is opened in shared mode, only the primary client can change capture + * parameters and submit capture requests. Secondary clients can use the startStreaming API to + * provide the stream and surface IDs they want to stream on. If the primary client has an + * ongoing repeating request, camera service will attach these surfaces to it. Otherwise, + * camera service will create a default capture request with a preview template. + * + * @param streamIdxArray stream ids of the target surfaces + * @param surfaceIdxArray surface ids of the target surfaces + * @return SubmitInfo data structure containing the request id of the capture request and the + * frame number of the last request, of the previous batch of repeating requests, if + * any. If there is no previous batch, the frame number returned will be -1. + */ + SubmitInfo startStreaming(in int[] streamIdxArray, in int[] surfaceIdxArray); /** * Cancel the repeating request specified by requestId @@ -68,6 +82,17 @@ const int CONSTRAINED_HIGH_SPEED_MODE = 1; /** + * The shared operating mode for a camera device. + * + * <p> + * When in shared mode, the camera device can be opened and accessed by multiple applications + * simultaneously. + * </p> + * + */ + const int SHARED_MODE = 2; + + /** * Start of custom vendor modes */ const int VENDOR_MODE_START = 0x8000; @@ -194,4 +219,12 @@ */ ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks, in int[] offlineOutputIds); + + /** + * Get the client status as primary or secondary when camera is opened in shared mode. + * + * @return true if this is primary client when camera is opened in shared mode. + * false if another higher priority client with primary access is also using the camera. + */ + boolean isPrimaryClient(); }
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp index 2d1af32..cf386e9 100644 --- a/camera/camera2/OutputConfiguration.cpp +++ b/camera/camera2/OutputConfiguration.cpp
@@ -32,6 +32,7 @@ namespace android { const int OutputConfiguration::INVALID_ROTATION = -1; +const int OutputConfiguration::ROTATION_0 = 0; const int OutputConfiguration::INVALID_SET_ID = -1; const std::vector<sp<IGraphicBufferProducer>>& @@ -142,6 +143,29 @@ mUsage(0) { } +OutputConfiguration::OutputConfiguration(int surfaceType, int width, int height, int format, + int32_t colorSpace, int mirrorMode, bool useReadoutTimestamp, int timestampBase, + int dataspace, int64_t usage, int64_t streamusecase, std::string physicalCamId): + mRotation(ROTATION_0), + mSurfaceSetID(INVALID_SET_ID), + mSurfaceType(surfaceType), + mWidth(width), + mHeight(height), + mIsDeferred(false), + mIsShared(false), + mPhysicalCameraId(physicalCamId), + mIsMultiResolution(false), + mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD), + mColorSpace(colorSpace), + mStreamUseCase(streamusecase), + mTimestampBase(timestampBase), + mMirrorMode(mirrorMode), + mUseReadoutTimestamp(useReadoutTimestamp), + mFormat(format), + mDataspace(dataspace), + mUsage(usage){ +} + OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) : mRotation(INVALID_ROTATION), mSurfaceSetID(INVALID_SET_ID) {
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml index 5d85909..d8264df 100644 --- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml +++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
@@ -11,7 +11,7 @@ <hal format="aidl"> <name>android.frameworks.cameraservice.service</name> - <version>2</version> + <version>3</version> <interface> <name>ICameraService</name> <instance>default</instance>
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h index 83ce39d..8cde55d 100644 --- a/camera/include/camera/camera2/OutputConfiguration.h +++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -33,6 +33,7 @@ class OutputConfiguration : public android::Parcelable { public: + static const int ROTATION_0; static const int INVALID_ROTATION; static const int INVALID_SET_ID; enum SurfaceType { @@ -107,6 +108,9 @@ int surfaceSetID = INVALID_SET_ID, int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0, int height = 0, bool isShared = false); + OutputConfiguration(int surfaceType, int width, int height, int format, int32_t colorSpace, + int mirrorMode, bool useReadoutTimestamp,int timestampBase, int dataspace, + int64_t usage, int64_t streamusecase, std::string physicalCamId); bool operator == (const OutputConfiguration& other) const { return ( mRotation == other.mRotation && @@ -204,6 +208,28 @@ bool sensorPixelModesUsedLessThan(const OutputConfiguration& other) const; bool gbpsLessThan(const OutputConfiguration& other) const; void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);} + bool sharedConfigEqual(const OutputConfiguration& other) const { + return (mRotation == other.mRotation && + mSurfaceSetID == other.mSurfaceSetID && + mSurfaceType == other.mSurfaceType && + mWidth == other.mWidth && + mHeight == other.mHeight && + mIsDeferred == other.mIsDeferred && + mIsShared == other.mIsShared && + mPhysicalCameraId == other.mPhysicalCameraId && + mIsMultiResolution == other.mIsMultiResolution && + sensorPixelModesUsedEqual(other) && + mDynamicRangeProfile == other.mDynamicRangeProfile && + mColorSpace == other.mColorSpace && + mStreamUseCase == other.mStreamUseCase && + mTimestampBase == other.mTimestampBase && + mMirrorMode == other.mMirrorMode && + mUseReadoutTimestamp == other.mUseReadoutTimestamp && + mFormat == other.mFormat && + mDataspace == other.mDataspace && + mUsage == other.mUsage); + } + private: std::vector<sp<IGraphicBufferProducer>> mGbps; int mRotation;
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp index 379c0b5..508808f 100644 --- a/camera/ndk/Android.bp +++ b/camera/ndk/Android.bp
@@ -79,6 +79,7 @@ shared_libs: [ "android.companion.virtual.virtualdevice_aidl-cpp", "android.companion.virtualdevice.flags-aconfig-cc", + "camera_platform_flags_c_lib", "framework-permission-aidl-cpp", "libandroid_runtime", "libbinder", @@ -147,8 +148,8 @@ shared_libs: [ "android.frameworks.cameraservice.common-V1-ndk", - "android.frameworks.cameraservice.device-V2-ndk", - "android.frameworks.cameraservice.service-V2-ndk", + "android.frameworks.cameraservice.device-V3-ndk", + "android.frameworks.cameraservice.service-V3-ndk", "libbinder_ndk", "libcamera_metadata", "libcutils",
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp index 92de1e4..06ee714 100644 --- a/camera/ndk/NdkCameraCaptureSession.cpp +++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -177,6 +177,43 @@ } EXPORT +camera_status_t ACameraCaptureSessionShared_startStreaming( + ACameraCaptureSession* session, + /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks, + int numOutputWindows, ANativeWindow** windows, + /*optional*/int* captureSequenceId) { + ATRACE_CALL(); + return startStreamingTemplate(session, callbacks, numOutputWindows, windows, + captureSequenceId); +} + +EXPORT +camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming( + ACameraCaptureSession* session, + /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks, + int numOutputWindows, ANativeWindow** windows, + /*optional*/int* captureSequenceId) { + ATRACE_CALL(); + return startStreamingTemplate(session, callbacks, numOutputWindows, windows, + captureSequenceId); +} + +EXPORT +camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* session) { + ATRACE_CALL(); + if (session == nullptr) { + ALOGE("%s: Error: session is null", __FUNCTION__); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + + if (session->isClosed()) { + ALOGE("%s: session %p is already closed", __FUNCTION__, session); + return ACAMERA_ERROR_SESSION_CLOSED; + } + return session->stopStreaming(); +} + +EXPORT camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session, ACaptureSessionOutput* output) { ATRACE_CALL();
diff --git a/camera/ndk/NdkCameraCaptureSession.inc b/camera/ndk/NdkCameraCaptureSession.inc index 258e20d..3112735 100644 --- a/camera/ndk/NdkCameraCaptureSession.inc +++ b/camera/ndk/NdkCameraCaptureSession.inc
@@ -68,3 +68,24 @@ return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId); } + +template <class CallbackType> +camera_status_t startStreamingTemplate(ACameraCaptureSession* session, + /*optional*/CallbackType* callbacks, + int numOutputWindows, ANativeWindow** windows, + /*optional*/int* captureSequenceId) { + ATRACE_CALL(); + if (session == nullptr || windows == nullptr || numOutputWindows < 1) { + ALOGE("%s: Error: invalid input: session %p, numOutputWindows %d, windows %p", + __FUNCTION__, session, numOutputWindows, windows); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + if (session->isClosed()) { + ALOGE("%s: session %p is already closed", __FUNCTION__, session); + if (captureSequenceId) { + *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE; + } + return ACAMERA_ERROR_SESSION_CLOSED; + } + return session->startStreaming(callbacks, numOutputWindows, windows, captureSequenceId); +}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp index f2ec573..bc6b87a 100644 --- a/camera/ndk/NdkCameraDevice.cpp +++ b/camera/ndk/NdkCameraDevice.cpp
@@ -59,6 +59,9 @@ __FUNCTION__, device, request); return ACAMERA_ERROR_INVALID_PARAMETER; } + if (device->isSharedMode() && !device->isPrimaryClient()) { + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } switch (templateId) { case TEMPLATE_PREVIEW: case TEMPLATE_STILL_CAPTURE: @@ -86,6 +89,9 @@ __FUNCTION__, device, request, physicalCameraIdList); return ACAMERA_ERROR_INVALID_PARAMETER; } + if (device->isSharedMode() && !device->isPrimaryClient()) { + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } switch (templateId) { case TEMPLATE_PREVIEW: case TEMPLATE_STILL_CAPTURE:
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp index 1b3343e..e7a1c93 100644 --- a/camera/ndk/NdkCameraManager.cpp +++ b/camera/ndk/NdkCameraManager.cpp
@@ -27,6 +27,8 @@ #include "ndk_vendor/impl/ACameraManager.h" #else #include "impl/ACameraManager.h" +#include <com_android_internal_camera_flags.h> +namespace flags = com::android::internal::camera::flags; #endif #include "impl/ACameraMetadata.h" @@ -159,6 +161,18 @@ } EXPORT +camera_status_t ACameraManager_isCameraDeviceSharingSupported(ACameraManager *mgr, + const char *cameraId, bool *isSharingSupported) { + ATRACE_CALL(); + if (mgr == nullptr || cameraId == nullptr || isSharingSupported == nullptr) { + ALOGE("%s: invalid argument! mgr %p cameraId %p isSharingSupported %p", + __FUNCTION__, mgr, cameraId, isSharingSupported); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + return mgr->isCameraDeviceSharingSupported(cameraId, isSharingSupported); +} + +EXPORT camera_status_t ACameraManager_getCameraCharacteristics( ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){ ATRACE_CALL(); @@ -188,7 +202,27 @@ __FUNCTION__, mgr, cameraId, callback, device); return ACAMERA_ERROR_INVALID_PARAMETER; } - return mgr->openCamera(cameraId, callback, device); + bool primaryClient; + return mgr->openCamera(cameraId, /*sharedMode*/false, callback, device, &primaryClient); +} + +EXPORT +camera_status_t ACameraManager_openSharedCamera( + ACameraManager* mgr, const char* cameraId, ACameraDevice_StateCallbacks* callback, + /*out*/ACameraDevice** device, /*out*/bool* primaryClient) { + ATRACE_CALL(); + if (mgr == nullptr || cameraId == nullptr || callback == nullptr || device == nullptr || + primaryClient == nullptr) { + ALOGE("%s: invalid argument! mgr %p cameraId %p callback %p device %p primary %p", + __FUNCTION__, mgr, cameraId, callback, device, primaryClient); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + bool sharedMode; + camera_status_t status = mgr->isCameraDeviceSharingSupported(cameraId, &sharedMode); + if ((status != ACAMERA_OK) || !sharedMode) { + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } + return mgr->openCamera(cameraId, /*sharedMode*/true, callback, device, primaryClient); } #ifdef __ANDROID_VNDK__
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp index 449c0b4..8e7264a 100644 --- a/camera/ndk/impl/ACameraCaptureSession.cpp +++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -96,6 +96,10 @@ camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode() && !dev->isPrimaryClient()) { + dev->unlockDevice(); + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->stopRepeatingLocked(); } @@ -103,6 +107,27 @@ return ret; } +camera_status_t ACameraCaptureSession::stopStreaming() { +#ifdef __ANDROID_VNDK__ + std::shared_ptr<acam::CameraDevice> dev = getDevicePtr(); +#else + sp<acam::CameraDevice> dev = getDeviceSp(); +#endif + if (dev == nullptr) { + ALOGE("Error: Device associated with session %p has been closed!", this); + return ACAMERA_ERROR_SESSION_CLOSED; + } + + camera_status_t ret; + dev->lockDeviceForSessionOps(); + { + Mutex::Autolock _l(mSessionLock); + ret = dev->stopStreamingLocked(); + } + dev->unlockDevice(); + return ret; +} + camera_status_t ACameraCaptureSession::abortCaptures() { #ifdef __ANDROID_VNDK__ @@ -114,10 +139,13 @@ ALOGE("Error: Device associated with session %p has been closed!", this); return ACAMERA_ERROR_SESSION_CLOSED; } - camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode() && !dev->isPrimaryClient()) { + dev->unlockDevice(); + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->flushLocked(this); } @@ -139,6 +167,10 @@ camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode()) { + dev->unlockDevice(); + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->updateOutputConfigurationLocked(output); } @@ -160,6 +192,10 @@ camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode()) { + dev->unlockDevice(); + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->prepareLocked(window); }
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h index 0d7a2c1..eb13b96 100644 --- a/camera/ndk/impl/ACameraCaptureSession.h +++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -150,6 +150,12 @@ ACameraDevice* getDevice(); + template<class T> + camera_status_t startStreaming(/*optional*/T* callbacks, + int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId); + + camera_status_t stopStreaming(); + private: friend class android::acam::CameraDevice;
diff --git a/camera/ndk/impl/ACameraCaptureSession.inc b/camera/ndk/impl/ACameraCaptureSession.inc index da535f8..695eb37 100644 --- a/camera/ndk/impl/ACameraCaptureSession.inc +++ b/camera/ndk/impl/ACameraCaptureSession.inc
@@ -42,6 +42,9 @@ camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode() && !dev->isPrimaryClient()) { + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->setRepeatingRequestsLocked( this, cbs, numRequests, requests, captureSequenceId); @@ -67,9 +70,37 @@ camera_status_t ret; dev->lockDeviceForSessionOps(); { + if (dev->isSharedMode() && !dev->isPrimaryClient()) { + return ACAMERA_ERROR_UNSUPPORTED_OPERATION; + } Mutex::Autolock _l(mSessionLock); ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId); } dev->unlockDevice(); return ret; } + +template <class T> +camera_status_t ACameraCaptureSession::startStreaming( + /*optional*/T* callbacks, int numOutputWindows, ANativeWindow** windows, + /*optional*/int* captureSequenceId) { +#ifdef __ANDROID_VNDK__ + std::shared_ptr<acam::CameraDevice> dev = getDevicePtr(); +#else + sp<acam::CameraDevice> dev = getDeviceSp(); +#endif + if (dev == nullptr) { + ALOGE("Error: Device associated with session %p has been closed!", this); + return ACAMERA_ERROR_SESSION_CLOSED; + } + + camera_status_t ret; + dev->lockDeviceForSessionOps(); + { + Mutex::Autolock _l(mSessionLock); + ret = dev->startStreamingLocked(this, callbacks, numOutputWindows, windows, + captureSequenceId); + } + dev->unlockDevice(); + return ret; +}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp index 1fa71f4..cd59e5a 100644 --- a/camera/ndk/impl/ACameraDevice.cpp +++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -26,6 +26,9 @@ #include "ACameraMetadata.h" #include "ACaptureRequest.h" #include "ACameraCaptureSession.h" +#include <com_android_internal_camera_flags.h> + +namespace flags = com::android::internal::camera::flags; ACameraDevice::~ACameraDevice() { mDevice->stopLooperAndDisconnect(); @@ -57,12 +60,13 @@ const char* id, ACameraDevice_StateCallbacks* cb, sp<ACameraMetadata> chars, - ACameraDevice* wrapper) : + ACameraDevice* wrapper, bool sharedMode) : mCameraId(id), mAppCallbacks(*cb), mChars(chars), mServiceCallback(new ServiceCallback(this)), mWrapper(wrapper), + mSharedMode(sharedMode), mInError(false), mError(ACAMERA_OK), mIdle(true), @@ -264,6 +268,28 @@ } } +camera_status_t CameraDevice::stopStreamingLocked() { + camera_status_t ret = checkCameraClosedOrErrorLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret); + return ret; + } + ret = stopRepeatingLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret); + return ret; + } + for (auto& outputTarget : mPreviewRequestOutputs) { + ACameraOutputTarget_free(outputTarget); + } + mPreviewRequestOutputs.clear(); + if (mPreviewRequest) { + ACaptureRequest_free(mPreviewRequest); + mPreviewRequest = nullptr; + } + return ACAMERA_OK; +} + camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) { camera_status_t ret = checkCameraClosedOrErrorLocked(); if (ret != ACAMERA_OK) { @@ -682,6 +708,11 @@ if (ret != ACAMERA_OK) { return ret; } + // Surface sharing cannot be enabled when a camera has been opened + // in shared mode. + if (mSharedMode && outConfig.mIsShared) { + return ACAMERA_ERROR_INVALID_PARAMETER; + } outputSet.insert(std::make_pair( anw, OutputConfiguration(iGBP, outConfig.mRotation, outConfig.mPhysicalCameraId, OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared))); @@ -706,10 +737,14 @@ return ret; } - ret = waitUntilIdleLocked(); - if (ret != ACAMERA_OK) { - ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret); - return ret; + // If device is opened in shared mode, there can be multiple clients accessing the + // camera device. So do not wait for idle if the device is opened in shared mode. + if (!mSharedMode) { + ret = waitUntilIdleLocked(); + if (ret != ACAMERA_OK) { + ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret); + return ret; + } } // Send onReady to previous session @@ -970,6 +1005,7 @@ case kWhatCaptureSeqAbort: case kWhatCaptureBufferLost: case kWhatPreparedCb: + case kWhatClientSharedAccessPriorityChanged: ALOGV("%s: Received msg %d", __FUNCTION__, msg->what()); break; case kWhatCleanUpSessions: @@ -1007,6 +1043,29 @@ (*onDisconnected)(context, dev); break; } + + case kWhatClientSharedAccessPriorityChanged: + { + ACameraDevice* dev; + found = msg->findPointer(kDeviceKey, (void**) &dev); + if (!found || dev == nullptr) { + ALOGE("%s: Cannot find device pointer!", __FUNCTION__); + return; + } + ACameraDevice_ClientSharedAccessPriorityChangedCallback + onClientSharedAccessPriorityChanged; + found = msg->findPointer(kCallbackFpKey, (void**) &onClientSharedAccessPriorityChanged); + if (!found) { + ALOGE("%s: Cannot find onClientSharedAccessPriorityChanged!", __FUNCTION__); + return; + } + if (onClientSharedAccessPriorityChanged == nullptr) { + return; + } + (*onClientSharedAccessPriorityChanged)(context, dev, dev->isPrimaryClient()); + break; + } + case kWhatOnError: { ACameraDevice* dev; @@ -1624,6 +1683,28 @@ } binder::Status +CameraDevice::ServiceCallback::onClientSharedAccessPriorityChanged(bool primaryClient) { + ALOGV("onClientSharedAccessPriorityChanged received. primaryClient = %d", primaryClient); + binder::Status ret = binder::Status::ok(); + sp<CameraDevice> dev = mDevice.promote(); + if (dev == nullptr) { + return ret; // device has been closed + } + Mutex::Autolock _l(dev->mDeviceLock); + if (dev->isClosed() || dev->mRemote == nullptr) { + return ret; + } + dev->setPrimaryClient(primaryClient); + sp<AMessage> msg = new AMessage(kWhatClientSharedAccessPriorityChanged, dev->mHandler); + msg->setPointer(kContextKey, dev->mAppCallbacks.context); + msg->setPointer(kDeviceKey, (void*) dev->getWrapper()); + msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onClientSharedAccessPriorityChanged); + msg->post(); + + return binder::Status::ok(); +} + +binder::Status CameraDevice::ServiceCallback::onDeviceIdle() { ALOGV("Camera is now idle"); binder::Status ret = binder::Status::ok();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h index 2b9f327..39037bb 100644 --- a/camera/ndk/impl/ACameraDevice.h +++ b/camera/ndk/impl/ACameraDevice.h
@@ -63,7 +63,7 @@ public: CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb, sp<ACameraMetadata> chars, - ACameraDevice* wrapper); + ACameraDevice* wrapper, bool sharedMode); ~CameraDevice(); inline const char* getId() const { return mCameraId.c_str(); } @@ -98,6 +98,7 @@ binder::Status onRequestQueueEmpty() override; binder::Status onRepeatingRequestError(int64_t lastFrameNumber, int32_t stoppedSequenceId) override; + binder::Status onClientSharedAccessPriorityChanged(bool isPrimaryClient) override; private: const wp<CameraDevice> mDevice; }; @@ -113,6 +114,10 @@ // Stop the looper thread and unregister the handler void stopLooperAndDisconnect(); + void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;}; + bool isPrimaryClient() {return mIsPrimaryClient;}; + bool isSharedMode() {return mSharedMode;}; + private: friend ACameraCaptureSession; camera_status_t checkCameraClosedOrErrorLocked() const; @@ -128,6 +133,15 @@ camera_status_t waitUntilIdleLocked(); + camera_status_t stopStreamingLocked(); + + template<class T> + camera_status_t startStreamingLocked(ACameraCaptureSession* session, + /*optional*/T* callbacks, + int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId); + + ACaptureRequest* mPreviewRequest = nullptr; + std::vector<ACameraOutputTarget*> mPreviewRequestOutputs; template<class T> camera_status_t captureLocked(sp<ACameraCaptureSession> session, @@ -186,6 +200,8 @@ const sp<ACameraMetadata> mChars; // Camera characteristics const sp<ServiceCallback> mServiceCallback; ACameraDevice* mWrapper; + bool mSharedMode; + bool mIsPrimaryClient; // stream id -> pair of (ANW* from application, OutputConfiguration used for camera service) std::map<int, std::pair<ANativeWindow*, OutputConfiguration>> mConfiguredOutputs; @@ -227,7 +243,8 @@ kWhatCaptureBufferLost, // onCaptureBufferLost kWhatPreparedCb, // onWindowPrepared // Internal cleanup - kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession> + kWhatCleanUpSessions, // Cleanup cached sp<ACameraCaptureSession> + kWhatClientSharedAccessPriorityChanged }; static const char* kContextKey; static const char* kDeviceKey; @@ -403,8 +420,8 @@ */ struct ACameraDevice { ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb, - sp<ACameraMetadata> chars) : - mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {} + sp<ACameraMetadata> chars, bool sharedMode) : + mDevice(new android::acam::CameraDevice(id, cb, chars, this, sharedMode)) {} ~ACameraDevice(); @@ -445,7 +462,19 @@ mDevice->setRemoteDevice(remote); } - private: + inline void setPrimaryClient(bool isPrimary) { + mDevice->setPrimaryClient(isPrimary); + } + + inline bool isPrimaryClient() const { + return mDevice->isPrimaryClient(); + } + + inline bool isSharedMode() const{ + return mDevice->isSharedMode(); + } + + private: android::sp<android::acam::CameraDevice> mDevice; };
diff --git a/camera/ndk/impl/ACameraDevice.inc b/camera/ndk/impl/ACameraDevice.inc index 1fc5352..7e70d39 100644 --- a/camera/ndk/impl/ACameraDevice.inc +++ b/camera/ndk/impl/ACameraDevice.inc
@@ -126,5 +126,102 @@ return ACAMERA_OK; } +template<class T> +camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session, + /*optional*/T* callbacks, int numOutputWindows, + ANativeWindow** windows, /*optional*/int* captureSequenceId) { + camera_status_t ret = checkCameraClosedOrErrorLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret); + return ret; + } + CameraMetadata rawPreviewRequest; + binder::Status remoteRet = mRemote->createDefaultRequest(TEMPLATE_PREVIEW, &rawPreviewRequest); + if (!remoteRet.isOk()) { + ALOGE("%s: Create capture request failed: %s", __FUNCTION__, remoteRet.toString8().c_str()); + return ACAMERA_ERROR_UNKNOWN; + } + // ToDo: Check if the memory allocation can be freed automatically using either default_delete + // or ScopedAResource. + mPreviewRequest = new ACaptureRequest(); + mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest.release(), + ACameraMetadata::ACM_REQUEST); + mPreviewRequest->targets = new ACameraOutputTargets(); + for (int i = 0; i < numOutputWindows ; i++) { + ACameraOutputTarget* outputTarget = nullptr; + ret = ACameraOutputTarget_create(windows[i], &outputTarget); + if (ret != ACAMERA_OK) { + ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret); + return ret; + } + ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget); + if (ret != ACAMERA_OK) { + ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret); + return ret; + } + mPreviewRequestOutputs.push_back(outputTarget); + } + + sp<CaptureRequest> req; + ret = allocateCaptureRequest(mPreviewRequest, req); + if (ret != ACAMERA_OK) { + ALOGE("Convert capture request to internal format failure! ret %d", ret); + return ret; + } + if (req->mSurfaceList.empty()) { + ALOGE("Capture request without output target cannot be submitted!"); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + + // In shared session mode, if there are other active clients streaming then + // stoprepeating does not actually send request to HAL to cancel the request. + // Cameraservice will use this call to remove this client surfaces provided in its + // previous streaming request. If this is the only client for the shared camera device + // then camerservice will ask HAL to cancel the previous repeating request. + ret = stopRepeatingLocked(); + if (ret != ACAMERA_OK) { + ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret); + return ret; + } + + hardware::camera2::utils::SubmitInfo info; + std::vector<int> streamIds(req->mStreamIdxList.begin(), req->mStreamIdxList.end()); + std::vector<int> surfaceIds(req->mSurfaceIdxList.begin(), req->mSurfaceIdxList.end()); + remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info); + int sequenceId = info.mRequestId; + int64_t lastFrameNumber = info.mLastFrameNumber; + if (sequenceId < 0) { + ALOGE("Camera %s start streaming remote failure: ret %d", getId(), sequenceId); + return ACAMERA_ERROR_UNKNOWN; + } + + Vector<sp<CaptureRequest> > requestsV; + requestsV.push_back(req); + CallbackHolder cbHolder(session, requestsV, true, callbacks); + mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder)); + + // stopRepeating above should have cleanup repeating sequence id + if (mRepeatingSequenceId != REQUEST_ID_NONE) { + setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE); + return ACAMERA_ERROR_CAMERA_DEVICE; + } + mRepeatingSequenceId = sequenceId; + + if (mIdle) { + sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler); + msg->setPointer(kContextKey, session->mUserSessionCallback.context); + msg->setObject(kSessionSpKey, session); + msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive); + postSessionMsgAndCleanup(msg); + } + mIdle = false; + mBusySession = session; + + if (captureSequenceId) { + *captureSequenceId = sequenceId; + } + return ACAMERA_OK; +} + } // namespace acam } // namespace android
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp index 6d29ef5..07d7c21 100644 --- a/camera/ndk/impl/ACameraManager.cpp +++ b/camera/ndk/impl/ACameraManager.cpp
@@ -28,9 +28,11 @@ #include <memory> #include "ACameraDevice.h" #include "ACameraMetadata.h" +#include <com_android_internal_camera_flags.h> using namespace android::acam; namespace vd_flags = android::companion::virtualdevice::flags; +namespace flags = com::android::internal::camera::flags; namespace android { namespace acam { @@ -838,10 +840,36 @@ } camera_status_t -ACameraManager::openCamera( +ACameraManager::isCameraDeviceSharingSupported( const char* cameraId, + /*out*/bool* isSharingSupported) { + sp<ACameraMetadata> spChars; + camera_status_t ret = getCameraCharacteristics(cameraId, &spChars); + if (ret != ACAMERA_OK) { + ALOGE("%s: cannot get camera characteristics for camera %s. err %d", + __FUNCTION__, cameraId, ret); + return ret; + } + + ACameraMetadata* chars = spChars.get(); + ACameraMetadata_const_entry entry; + ret = ACameraMetadata_getConstEntry(chars, ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS, + &entry); + if (ret != ACAMERA_OK) { + // If shared session metadata is not found return with sharing + // supported as false. + *isSharingSupported = false; + return ACAMERA_OK; + } + *isSharingSupported = (entry.count > 0) ? true : false; + return ACAMERA_OK; +} + +camera_status_t +ACameraManager::openCamera( + const char* cameraId, bool sharedMode, ACameraDevice_StateCallbacks* callback, - /*out*/ACameraDevice** outDevice) { + /*out*/ACameraDevice** outDevice, /*out*/bool* primaryClient) { sp<ACameraMetadata> chars; camera_status_t ret = getCameraCharacteristics(cameraId, &chars); Mutex::Autolock _l(mLock); @@ -851,7 +879,7 @@ return ACAMERA_ERROR_INVALID_PARAMETER; } - ACameraDevice* device = new ACameraDevice(cameraId, callback, chars); + ACameraDevice* device = new ACameraDevice(cameraId, callback, chars, sharedMode); sp<hardware::ICameraService> cs = mGlobalManager->getCameraService(); if (cs == nullptr) { @@ -876,7 +904,7 @@ binder::Status serviceRet = cs->connectDevice( callbacks, cameraId, /*oomScoreOffset*/0, targetSdkVersion, /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, static_cast<int32_t>(mDeviceContext.policy), + clientAttribution, static_cast<int32_t>(mDeviceContext.policy), sharedMode, /*out*/&deviceRemote); if (!serviceRet.isOk()) { @@ -920,6 +948,14 @@ return ACAMERA_ERROR_CAMERA_DISCONNECTED; } device->setRemoteDevice(deviceRemote); + if (sharedMode) { + binder::Status remoteRet = deviceRemote->isPrimaryClient(primaryClient); + if (!remoteRet.isOk()) { + delete device; + return ACAMERA_ERROR_UNKNOWN; + } + device->setPrimaryClient(*primaryClient); + } *outDevice = device; return ACAMERA_OK; }
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h index f4124ef..499f982 100644 --- a/camera/ndk/impl/ACameraManager.h +++ b/camera/ndk/impl/ACameraManager.h
@@ -136,6 +136,10 @@ virtual binder::Status onCameraOpened(const std::string&, const std::string&, int32_t) { return binder::Status::ok(); } + virtual binder::Status onCameraOpenedInSharedMode(const std::string&, const std::string&, + int32_t, bool) { + return binder::Status::ok(); + } virtual binder::Status onCameraClosed(const std::string&, int32_t) { return binder::Status::ok(); } @@ -325,16 +329,17 @@ camera_status_t getCameraCharacteristics( const char* cameraId, android::sp<ACameraMetadata>* characteristics); - camera_status_t openCamera(const char* cameraId, + camera_status_t openCamera(const char* cameraId, bool sharedMode, ACameraDevice_StateCallbacks* callback, - /*out*/ACameraDevice** device); + /*out*/ACameraDevice** device, /*out*/bool* primaryClient); void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback); void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback); void registerExtendedAvailabilityCallback( const ACameraManager_ExtendedAvailabilityCallbacks* callback); void unregisterExtendedAvailabilityCallback( const ACameraManager_ExtendedAvailabilityCallbacks* callback); - + camera_status_t isCameraDeviceSharingSupported( + const char* cameraId, bool* isSharingSupported); private: enum { kCameraIdListNotInit = -1
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h index 1400121..c2aae1c 100644 --- a/camera/ndk/include/camera/NdkCameraCaptureSession.h +++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -1099,6 +1099,150 @@ camera_status_t ACameraCaptureSession_prepareWindow( ACameraCaptureSession* session, ANativeWindow *window) __INTRODUCED_IN(34); + +/** + * Request continuous streaming of a sequence of images for the shared capture session + * when more than one clients can open the same camera in shared mode by calling + * {@link ACameraManager_openSharedCamera}. In shared mode, the highest priority client among all + * the clients will be the primary client while the others would be secondary clients. In shared + * capture session, only primary clients can create a capture request and change capture parameters. + * Secondary clients can only request streaming of images by calling this api + * {@link ACameraCaptureSessionShared_startStreaming}. Calling this api for normal sessions when + * {@link ACameraManager_openCamera} is used to open the camera will throw + * {@link ACAMERA_ERROR_INVALID_OPERATION}. + * + * <p>The priority of client access is determined by considering two factors: its current process + * state and its "out of memory" score. Clients operating in the background are assigned a lower + * priority. In contrast, clients running in the foreground, along with system-level clients, are + * given a higher priority.</p> + * + * <p>With this method, the camera device will continually capture images, cycling through the + * settings in the list of {@link ACaptureRequest} specified by the primary client. If primary + * client does not have ongoing repeating request, camera service will use a capture request with + * default capture parameters for preview template.</p> + * + * <p>To stop the continuous streaming, call {@link ACameraCaptureSessionShared_stopStreaming}.</p> + * + * <p>Calling this method will replace an existing continuous streaming request.</p> + * + * @param sharedSession the shared capture session when camera is opened in + * shared mode. + * @param callbacks the {@link ACameraCaptureSession_captureCallbacks} to be associated with this + * capture sequence. No capture callback will be fired if callbacks is set to NULL. + * @param numOutputWindows number of native windows to be used for streaming. Must be at least 1. + * @param windows an array of {@link ANativeWindow} to be used for streaming. Length must be at + * least numOutputWindows. + * @param captureSequenceId the capture sequence ID associated with this capture method invocation + * will be stored here if this argument is not NULL and the method call succeeds. + * When this argument is set to NULL, the capture sequence ID will not be returned. + * + * @return <ul> + * <li>{@link ACAMERA_OK} if the method succeeds. captureSequenceId will be filled + * if it is not NULL.</li> + * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session or requests is NULL, or + * if numRequests < 1</li> + * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li> + * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error + * </li> + * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if the session passed is not a shared + * session</li> + * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li> + * </ul> + */ +camera_status_t ACameraCaptureSessionShared_startStreaming( + ACameraCaptureSession* sharedSession, + /*optional*/ACameraCaptureSession_captureCallbacksV2 *callbacks, + int numOutputWindows, ANativeWindow **window, + /*optional*/int *captureSequenceId) __INTRODUCED_IN(36); + +/** + * This has the same functionality as ACameraCaptureSessionShared_startStreaming, with added + * support for logical multi-camera where the capture callbacks supports result metadata for + * physical cameras. + * + * Request continuous streaming of a sequence of images for the shared capture session + * when more than one clients can open the same camera in shared mode by calling + * {@link ACameraManager_openSharedCamera}. In shared mode, the highest priority client among all + * the clients will be the primary client while the others would be secondary clients. In shared + * capture session, only primary clients can create a capture request and change capture parameters. + * Secondary clients can only request streaming of images by calling this api + * {@link ACameraCaptureSessionShared_logicalCamera_startStreaming}. Calling this api for normal + * sessions when {@link ACameraManager_openCamera} is used to open the camera will throw + * {@link ACAMERA_ERROR_INVALID_OPERATION}. + * + * <p>The priority of client access is determined by considering two factors: its current process + * state and its "out of memory" score. Clients operating in the background are assigned a lower + * priority. In contrast, clients running in the foreground, along with system-level clients, are + * given a higher priority.</p> + * + * <p>With this method, the camera device will continually capture images, cycling through the + * settings in the list of {@link ACaptureRequest} specified by the primary client. If primary + * client does not have ongoing repeating request, camera service will use a capture request with + * default capture parameters for preview template.</p> + * + * <p>To stop the continuous streaming, call {@link ACameraCaptureSessionShared_stopStreaming}.</p> + * + * <p>Calling this method will replace an existing continuous streaming request.</p> + * + * @param sharedSession the shared capture session when camera is opened in + * shared mode. + * @param callbacks the {@link ACameraCaptureSession_logicalCamera_captureCallbacksV2} to be + * associated with this capture sequence. No capture callback will be fired if callbacks + * is set to NULL. + * @param numOutputWindows number of native windows to be used for streaming. Must be at least 1. + * @param windows an array of {@link ANativeWindow} to be used for streaming. Length must be at + * least numOutputWindows. + * @param captureSequenceId the capture sequence ID associated with this capture method invocation + * will be stored here if this argument is not NULL and the method call succeeds. + * When this argument is set to NULL, the capture sequence ID will not be returned. + * + * @return <ul> + * <li>{@link ACAMERA_OK} if the method succeeds. captureSequenceId will be filled + * if it is not NULL.</li> + * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session or requests is NULL, or + * if numRequests < 1</li> + * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li> + * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error + * </li> + * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if the session passed is not a shared + * session</li> + * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li> + * </ul> + */ +camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming( + ACameraCaptureSession* sharedSession, + /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2 *callbacks, + int numOutputWindows, ANativeWindow **windows, + /*optional*/int *captureSequenceId) __INTRODUCED_IN(36); + +/** + * Cancel any ongoing streaming started by {@link ACameraCaptureSessionShared_startStreaming}. + * Calling this api does not effect any streaming requests submitted by other clients who have + * opened the camera in shared mode. Calling this api for normal sessions when + * {@link ACameraManager_openCamera} is used to open the camera will throw + * {@link ACAMERA_ERROR_INVALID_OPERATION}. + * + * @param sharedSession the capture session of interest + * + * @return <ul> + * <li>{@link ACAMERA_OK} if the method succeeds.</li> + * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session is NULL.</li> + * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li> + * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error + * </li> + * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if the session passed is not a shared + * session</li> + * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li> + * </ul> + */ +camera_status_t ACameraCaptureSessionShared_stopStreaming( + ACameraCaptureSession* sharedSession) __INTRODUCED_IN(36); __END_DECLS #endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h index fbd0ee1..8c7eb1f 100644 --- a/camera/ndk/include/camera/NdkCameraDevice.h +++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -125,6 +125,18 @@ typedef void (*ACameraDevice_ErrorStateCallback)(void* context, ACameraDevice* device, int error); /** + * Client access priorities changed callbacks to be used in {@link ACameraDevice_StateCallbacks} + * when camera is opened in shared mode. + * + * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be passed to + * this callback. + * @param device The {@link ACameraDevice} whose access priorities has been changed. + * @param isPrimaryClient whether the client is primary client. + */ +typedef void (*ACameraDevice_ClientSharedAccessPriorityChangedCallback)(void* context, + ACameraDevice* device, bool isPrimaryClient); + +/** * Applications' callbacks for camera device state changes, register with * {@link ACameraManager_openCamera}. */ @@ -163,6 +175,17 @@ * */ ACameraDevice_ErrorStateCallback onError; + + /** + * Notify registered clients about client shared access priority changes when the camera device + * has been opened in shared mode. + * + * If the client priority changes from secondary to primary, then it can now + * create capture request and change the capture request parameters. If client priority + * changes from primary to secondary, that implies that another higher priority client is also + * accessing the camera in shared mode and is now the primary client. + */ + ACameraDevice_ClientSharedAccessPriorityChangedCallback onClientSharedAccessPriorityChanged; } ACameraDevice_StateCallbacks; /** @@ -671,7 +694,9 @@ * <li>{@link ACAMERA_OK} if the method call succeeds. The created capture session will be * filled in session argument.</li> * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if any of device, outputs, callbacks or - * session is NULL.</li> + * session is NULL or if the outputs does not match the predefined + * shared session configuration when camera is opened in shared mode. + * </li> * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed.</li> * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error.</li> * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error.</li>
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h index b4f3bf1..492c41b 100644 --- a/camera/ndk/include/camera/NdkCameraManager.h +++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -293,6 +293,61 @@ /*out*/ACameraDevice** device) __INTRODUCED_IN(24); /** + * Open a shared connection to a camera with the given ID. The opened camera device will be + * returned in the `device` parameter. The behavior of this method matches that of + * {@link ACameraManager_openCamera(ACameraManager*, const char*, ACameraDevice_StateCallbacks*, + * ACameraDevice**)} except that it opens the camera in shared mode so that more + * than one client can access the camera at the same time. + * + * <p>When camera is opened in shared mode, the highest priority client among all the clients will + * be the primary client while the others would be secondary clients. Primary clients can create + * capture requests, modify any capture parameters and send them to the capture session for a + * one-shot capture or as a repeating request.</p> + * + * <p>Secondary clients cannot create a capture request and modify any capture parameters. However, + * they can start the camera streaming to desired surface targets using + * {@link ACameraCaptureSessionShared_startStreaming}. Once the streaming has successfully started, + * then they can stop the streaming using {@link ACameraCaptureSessionShared_stopStreaming}.</p> + * + * <p>The priority of client access is determined by considering two factors: its current process + * state and its "out of memory" score. Clients operating in the background are assigned a lower + * priority. In contrast, clients running in the foreground, along with system-level clients, are + * given a higher priority.</p> + * + * <p>Processes need to have android.permission.SYSTEM_CAMERA in addition to + * android.permission.CAMERA in order to connect to this camera device in shared + * mode.</p> + * + * @param manager the {@link ACameraManager} of interest. + * @param cameraId the ID string of the camera device to be opened. + * @param callback the {@link ACameraDevice_StateCallbacks} associated with the opened camera + * device. + * @param device the opened {@link ACameraDevice} will be filled here if the method call succeeds. + * @param isPrimaryClient will return as true if the client is a primary client. + * + * @return <ul> + * <li>{@link ACAMERA_OK} if the method call succeeds.</li> + * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager, cameraId, callback, or device + * is NULL, or cameraId does not match any camera devices connected.</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if connection to camera service fails.</li> + * <li>{@link ACAMERA_ERROR_NOT_ENOUGH_MEMORY} if allocating memory fails.</li> + * <li>{@link ACAMERA_ERROR_CAMERA_IN_USE} if camera device is being used by a higher + * priority camera API client.</li> + * <li>{@link ACAMERA_ERROR_MAX_CAMERA_IN_USE} if the system-wide limit for number of open + * cameras or camera resources has been reached, and more camera devices cannot be + * opened until previous instances are closed.</li> + * <li>{@link ACAMERA_ERROR_CAMERA_DISABLED} if the camera is disabled due to a device + * policy, and cannot be opened.</li> + * <li>{@link ACAMERA_ERROR_PERMISSION_DENIED} if the application does not have permission + * to open camera.</li> + * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul> + */ +camera_status_t ACameraManager_openSharedCamera( + ACameraManager* manager, const char* cameraId, + ACameraDevice_StateCallbacks* callback, + /*out*/ACameraDevice** device,/*out*/bool* isPrimaryClient) __INTRODUCED_IN(36); + +/** * Definition of camera access permission change callback. * * <p>Notification that camera access priorities have changed and the camera may @@ -397,6 +452,27 @@ ACameraManager* manager, const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29); + +/** + * Checks if a camera can be opened in shared mode by multiple clients. + * + * @param manager the {@link ACameraManager} of interest. + * @param cameraId the ID string of the camera device of interest. + * @param isSharingSupported output will be filled here if the method succeeds. + * This will be true if camera can be opened in shared mode, false + * otherwise. + * + * @return <ul> + * <li>{@link ACAMERA_OK} if the method call succeeds.</li> + * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager, cameraId, or isSharingSupported + * is NULL, or cameraId does not match any camera devices connected.</li> + * </ul> + */ +camera_status_t ACameraManager_isCameraDeviceSharingSupported( + ACameraManager *manager, + const char *cameraId, + bool *isSharingSupported) __INTRODUCED_IN(36); + #ifdef __ANDROID_VNDK__ /** * Retrieve the tag value, given the tag name and camera id.
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h index 1817490..c713077 100644 --- a/camera/ndk/include/camera/NdkCameraMetadataTags.h +++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -91,6 +91,7 @@ ACAMERA_AUTOMOTIVE_LENS, ACAMERA_EXTENSION, ACAMERA_JPEGR, + ACAMERA_SHARED_SESSION, ACAMERA_SECTION_COUNT, ACAMERA_VENDOR = 0x8000 @@ -138,6 +139,7 @@ ACAMERA_AUTOMOTIVE_LENS_START = ACAMERA_AUTOMOTIVE_LENS << 16, ACAMERA_EXTENSION_START = ACAMERA_EXTENSION << 16, ACAMERA_JPEGR_START = ACAMERA_JPEGR << 16, + ACAMERA_SHARED_SESSION_START = ACAMERA_SHARED_SESSION << 16, ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16 } acamera_metadata_section_start_t; @@ -11571,6 +11573,7 @@ + __END_DECLS #endif /* _NDK_CAMERA_METADATA_TAGS_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt index 7d7868b..60d4775 100644 --- a/camera/ndk/libcamera2ndk.map.txt +++ b/camera/ndk/libcamera2ndk.map.txt
@@ -28,6 +28,8 @@ ACameraManager_getCameraCharacteristics; ACameraManager_getCameraIdList; ACameraManager_openCamera; + ACameraManager_openSharedCamera; # systemapi introduced=36 + ACameraManager_isCameraDeviceSharingSupported; # systemapi introduced=36 ACameraManager_registerAvailabilityCallback; ACameraManager_unregisterAvailabilityCallback; ACameraManager_registerExtendedAvailabilityCallback; # introduced=29 @@ -72,6 +74,9 @@ ACaptureSessionSharedOutput_remove; # introduced=28 ACaptureSessionPhysicalOutput_create; # introduced=29 ACaptureSessionOutput_free; + ACameraCaptureSessionShared_startStreaming; # systemapi introduced=36 + ACameraCaptureSessionShared_logicalCamera_startStreaming; # systemapi introduced=36 + ACameraCaptureSessionShared_stopStreaming; # systemapi introduced=36 local: *; };
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp index 3325da6..2c32636 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -85,11 +85,12 @@ const char* id, ACameraDevice_StateCallbacks* cb, sp<ACameraMetadata> chars, - ACameraDevice* wrapper) : + ACameraDevice* wrapper, bool sharedMode) : mCameraId(id), mAppCallbacks(*cb), mChars(std::move(chars)), mWrapper(wrapper), + mSharedMode(sharedMode), mInError(false), mError(ACAMERA_OK), mIdle(true), @@ -561,6 +562,28 @@ return ACAMERA_OK; } +camera_status_t CameraDevice::stopStreamingLocked() { + camera_status_t ret = checkCameraClosedOrErrorLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret); + return ret; + } + ret = stopRepeatingLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret); + return ret; + } + for (auto& outputTarget : mPreviewRequestOutputs) { + ACameraOutputTarget_free(outputTarget); + } + mPreviewRequestOutputs.clear(); + if (mPreviewRequest) { + ACaptureRequest_free(mPreviewRequest); + mPreviewRequest = nullptr; + } + return ACAMERA_OK; +} + camera_status_t CameraDevice::flushLocked(ACameraCaptureSession* session) { camera_status_t ret = checkCameraClosedOrErrorLocked(); if (ret != ACAMERA_OK) { @@ -960,6 +983,7 @@ case kWhatCaptureSeqAbort: case kWhatCaptureBufferLost: case kWhatPreparedCb: + case kWhatClientSharedAccessPriorityChanged: ALOGV("%s: Received msg %d", __FUNCTION__, msg->what()); break; case kWhatCleanUpSessions: @@ -997,6 +1021,28 @@ (*onDisconnected)(context, dev); break; } + case kWhatClientSharedAccessPriorityChanged: + { + ACameraDevice* dev; + found = msg->findPointer(kDeviceKey, (void**) &dev); + if (!found || dev == nullptr) { + ALOGE("%s: Cannot find device pointer!", __FUNCTION__); + return; + } + ACameraDevice_ClientSharedAccessPriorityChangedCallback + onClientSharedAccessPriorityChanged; + found = msg->findPointer(kCallbackFpKey, (void**) &onClientSharedAccessPriorityChanged); + if (!found) { + ALOGE("%s: Cannot find onClientSharedAccessPriorityChanged!", __FUNCTION__); + return; + } + if (onClientSharedAccessPriorityChanged == nullptr) { + return; + } + (*onClientSharedAccessPriorityChanged)(context, dev, dev->isPrimaryClient()); + break; + } + case kWhatOnError: { ACameraDevice* dev; @@ -1614,6 +1660,28 @@ return ScopedAStatus::ok(); } +ScopedAStatus CameraDevice::ServiceCallback::onClientSharedAccessPriorityChanged( + bool primaryClient) { + ALOGV("onClientSharedAccessPriorityChanged received. primaryClient = %d", primaryClient); + ScopedAStatus ret = ScopedAStatus::ok(); + std::shared_ptr<CameraDevice> dev = mDevice.lock(); + if (dev == nullptr) { + return ret; // device has been closed + } + Mutex::Autolock _l(dev->mDeviceLock); + if (dev->isClosed() || dev->mRemote == nullptr) { + return ret; + } + dev->setPrimaryClient(primaryClient); + sp<AMessage> msg = new AMessage(kWhatClientSharedAccessPriorityChanged, dev->mHandler); + msg->setPointer(kContextKey, dev->mAppCallbacks.context); + msg->setPointer(kDeviceKey, (void*) dev->getWrapper()); + msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onClientSharedAccessPriorityChanged); + msg->post(); + + return ScopedAStatus::ok(); +} + ScopedAStatus CameraDevice::ServiceCallback::onDeviceIdle() { ALOGV("Camera is now idle");
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h index b771d47..5d03e95 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -95,7 +95,7 @@ public: CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb, sp<ACameraMetadata> chars, - ACameraDevice* wrapper); + ACameraDevice* wrapper, bool sharedMode); ~CameraDevice(); // Called to initialize fields that require shared_ptr to `this` @@ -136,6 +136,7 @@ const CaptureResultExtras& in_resultExtras, const std::vector<PhysicalCaptureResultInfo>& in_physicalCaptureResultInfos) override; + ndk::ScopedAStatus onClientSharedAccessPriorityChanged(bool isPrimaryClient) override; private: camera_status_t readOneResultMetadata(const CaptureMetadataInfo& captureMetadataInfo, @@ -154,6 +155,9 @@ // Stop the looper thread and unregister the handler void stopLooperAndDisconnect(); + void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;}; + bool isPrimaryClient() {return mIsPrimaryClient;}; + bool isSharedMode() {return mSharedMode;}; private: friend ACameraCaptureSession; @@ -192,6 +196,13 @@ /*out*/int* captureSequenceId, bool isRepeating); + camera_status_t stopStreamingLocked(); + + template<class T> + camera_status_t startStreamingLocked(ACameraCaptureSession* session, + /*optional*/T* callbacks, + int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId); + void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest, sp<CaptureRequest> &req); camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output); @@ -232,6 +243,10 @@ const sp<ACameraMetadata> mChars; // Camera characteristics std::shared_ptr<ServiceCallback> mServiceCallback; ACameraDevice* mWrapper; + bool mSharedMode; + bool mIsPrimaryClient; + ACaptureRequest* mPreviewRequest = nullptr; + std::vector<ACameraOutputTarget*> mPreviewRequestOutputs; // stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for // camera service) @@ -274,7 +289,8 @@ kWhatCaptureBufferLost, // onCaptureBufferLost kWhatPreparedCb, // onPrepared // Internal cleanup - kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession> + kWhatCleanUpSessions, // Cleanup cached sp<ACameraCaptureSession> + kWhatClientSharedAccessPriorityChanged }; static const char* kContextKey; static const char* kDeviceKey; @@ -434,9 +450,9 @@ */ struct ACameraDevice { ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb, - sp<ACameraMetadata> chars) : + sp<ACameraMetadata> chars, bool sharedMode) : mDevice(std::make_shared<android::acam::CameraDevice>(id, cb, - std::move(chars), this)) { + std::move(chars), this, sharedMode)) { mDevice->init(); } @@ -481,6 +497,16 @@ inline bool setDeviceMetadataQueues() { return mDevice->setDeviceMetadataQueues(); } + inline void setPrimaryClient(bool isPrimary) { + mDevice->setPrimaryClient(isPrimary); + } + inline bool isPrimaryClient() const { + return mDevice->isPrimaryClient(); + } + inline bool isSharedMode() const { + return mDevice->isSharedMode(); + } + private: std::shared_ptr<android::acam::CameraDevice> mDevice; };
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc index 1e724eb..1f568d2 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc +++ b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
@@ -147,5 +147,131 @@ return ACAMERA_OK; } +template<class T> +camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session, + /*optional*/T* callbacks, int numOutputWindows, + ANativeWindow** windows, /*optional*/int* captureSequenceId) { + camera_status_t ret = checkCameraClosedOrErrorLocked(); + if (ret != ACAMERA_OK) { + ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret); + return ret; + } + utils::AidlCameraMetadata aidlMetadata; + ndk::ScopedAStatus remoteRet = mRemote->createDefaultRequest(utils::TemplateId::PREVIEW, + &aidlMetadata); + if (!remoteRet.isOk()) { + if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) { + Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError()); + ALOGE("%s: submitRequestList call failed: %s", + __FUNCTION__, toString(errStatus).c_str()); + return utils::convertFromAidl(errStatus); + } else { + ALOGE("%s: Transaction error for submitRequestList call: %d", __FUNCTION__, + remoteRet.getExceptionCode()); + return ACAMERA_ERROR_UNKNOWN; + } + } + camera_metadata_t* rawPreviewRequest; + utils::cloneFromAidl(aidlMetadata, &rawPreviewRequest); + // ToDo: Check if the memory allocation can be freed automatically using either default_delete + // or ScopedAResource. + mPreviewRequest = new ACaptureRequest(); + mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest, + ACameraMetadata::ACM_REQUEST); + mPreviewRequest->targets = new ACameraOutputTargets(); + for (int i = 0; i < numOutputWindows ; i++) { + ACameraOutputTarget* outputTarget = nullptr; + ret = ACameraOutputTarget_create(windows[i], &outputTarget); + if (ret != ACAMERA_OK) { + ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret); + return ret; + } + ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget); + if (ret != ACAMERA_OK) { + ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret); + return ret; + } + mPreviewRequestOutputs.push_back(outputTarget); + } + + std::vector<sp<CaptureRequest>> requestsV; + sp<CaptureRequest> req; + ret = allocateCaptureRequestLocked(mPreviewRequest, req); + // We need to call this method since after submitRequestList is called, + // the request metadata queue might have removed the capture request + // metadata. Therefore we simply add the metadata to its wrapper class, + // so that it can be retrieved later. + addRequestSettingsMetadata(mPreviewRequest, req); + if (ret != ACAMERA_OK) { + ALOGE("Convert capture request to internal format failure! ret %d", ret); + return ret; + } + if (req->mCaptureRequest.streamAndWindowIds.size() == 0) { + ALOGE("Capture request without output target cannot be submitted!"); + return ACAMERA_ERROR_INVALID_PARAMETER; + } + requestsV.push_back(req); + // In shared session mode, if there are other active clients streaming then + // stoprepeating does not actually send request to HAL to cancel the request. + // Cameraservice will use this call to remove this client surfaces provided in its + // previous streaming request. If this is the only client for the shared camera device + // then camerservice will ask HAL to cancel the previous repeating request. + ret = stopRepeatingLocked(); + if (ret != ACAMERA_OK) { + ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret); + return ret; + } + SubmitInfo info; + std::vector<int> streamIds; + std::vector<int> surfaceIds; + for (const auto& streamAndWindowId : req->mCaptureRequest.streamAndWindowIds) { + streamIds.push_back(streamAndWindowId.streamId); + surfaceIds.push_back(streamAndWindowId.windowId); + } + remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info); + if (!remoteRet.isOk()) { + if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) { + Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError()); + ALOGE("%s: startStreaming call failed: %s", + __FUNCTION__, toString(errStatus).c_str()); + return utils::convertFromAidl(errStatus); + } else { + ALOGE("%s: Transaction error for startStreaming call: %d", __FUNCTION__, + remoteRet.getExceptionCode()); + return ACAMERA_ERROR_UNKNOWN; + } + } + + int32_t sequenceId = info.requestId; + int64_t lastFrameNumber = info.lastFrameNumber; + if (sequenceId < 0) { + ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId); + return ACAMERA_ERROR_UNKNOWN; + } + CallbackHolder cbHolder(session, requestsV, true, callbacks); + mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder)); + // stopRepeating above should have cleanup repeating sequence id + if (mRepeatingSequenceId != REQUEST_ID_NONE) { + setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE); + return ACAMERA_ERROR_CAMERA_DEVICE; + } + mRepeatingSequenceId = sequenceId; + + if (mIdle) { + sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler); + msg->setPointer(kContextKey, session->mUserSessionCallback.context); + msg->setObject(kSessionSpKey, session); + msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive); + postSessionMsgAndCleanup(msg); + } + mIdle = false; + mBusySession = session; + + if (captureSequenceId) { + *captureSequenceId = sequenceId; + } + return ACAMERA_OK; +} + } // namespace acam } // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp index cdba8ff..b59964c 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp +++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -791,10 +791,33 @@ } camera_status_t -ACameraManager::openCamera( +ACameraManager::isCameraDeviceSharingSupported( const char* cameraId, + /*out*/bool* isSharingSupported) { + sp<ACameraMetadata> spChars; + camera_status_t ret = getCameraCharacteristics(cameraId, &spChars); + if (ret != ACAMERA_OK) { + ALOGE("%s: cannot get camera characteristics for camera %s. err %d", + __FUNCTION__, cameraId, ret); + return ret; + } + + ACameraMetadata* chars = spChars.get(); + ACameraMetadata_const_entry entry; + ret = ACameraMetadata_getConstEntry(chars, ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS, + &entry); + if (ret != ACAMERA_OK) { + return ret; + } + *isSharingSupported = (entry.count > 0) ? true : false; + return ACAMERA_OK; +} + +camera_status_t +ACameraManager::openCamera( + const char* cameraId, bool sharedMode, ACameraDevice_StateCallbacks* callback, - /*out*/ACameraDevice** outDevice) { + /*out*/ACameraDevice** outDevice, /*out*/bool* isPrimaryClient) { sp<ACameraMetadata> rawChars; camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars); Mutex::Autolock _l(mLock); @@ -804,7 +827,7 @@ return ACAMERA_ERROR_INVALID_PARAMETER; } - ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars)); + ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars), sharedMode); std::shared_ptr<ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService(); if (cs == nullptr) { @@ -815,11 +838,18 @@ std::shared_ptr<BnCameraDeviceCallback> deviceCallback = device->getServiceCallback(); std::shared_ptr<ICameraDeviceUser> deviceRemote; + ScopedAStatus serviceRet; // No way to get package name from native. // Send a zero length package name and let camera service figure it out from UID - ScopedAStatus serviceRet = cs->connectDevice(deviceCallback, - std::string(cameraId), &deviceRemote); + if (sharedMode) { + serviceRet = cs->connectDeviceV2(deviceCallback, + std::string(cameraId), sharedMode, &deviceRemote); + } else { + serviceRet = cs->connectDevice(deviceCallback, + std::string(cameraId), &deviceRemote); + } + if (!serviceRet.isOk()) { if (serviceRet.getExceptionCode() == EX_SERVICE_SPECIFIC) { Status errStatus = static_cast<Status>(serviceRet.getServiceSpecificError()); @@ -842,6 +872,13 @@ } device->setRemoteDevice(deviceRemote); + if (sharedMode) { + ScopedAStatus remoteRet = deviceRemote->isPrimaryClient(isPrimaryClient); + if (!remoteRet.isOk()) { + return ACAMERA_ERROR_UNKNOWN; + } + device->setPrimaryClient(*isPrimaryClient); + } device->setDeviceMetadataQueues(); *outDevice = device; return ACAMERA_OK;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h index 2d8eefa..2fa4cce 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraManager.h +++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -261,9 +261,9 @@ camera_status_t getCameraCharacteristics( const char* cameraId, android::sp<ACameraMetadata>* characteristics); - camera_status_t openCamera(const char* cameraId, - ACameraDevice_StateCallbacks* callback, - /*out*/ACameraDevice** device); + camera_status_t openCamera(const char* cameraId, bool sharedMode, + ACameraDevice_StateCallbacks* callback, /*out*/ACameraDevice** device, + /*out*/bool* primaryClient); camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag); void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback); void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback); @@ -271,6 +271,8 @@ const ACameraManager_ExtendedAvailabilityCallbacks* callback); void unregisterExtendedAvailabilityCallback( const ACameraManager_ExtendedAvailabilityCallbacks* callback); + camera_status_t isCameraDeviceSharingSupported(const char *cameraId, + bool *isSharingSupported); private: enum {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp index 5135b5d..4384df9 100644 --- a/camera/tests/CameraBinderTests.cpp +++ b/camera/tests/CameraBinderTests.cpp
@@ -130,6 +130,15 @@ return binder::Status::ok(); } + virtual binder::Status onCameraOpenedInSharedMode( + [[maybe_unused]] const std::string& /*cameraId*/, + [[maybe_unused]] const std::string& /*clientPackageName*/, + [[maybe_unused]] int32_t /*deviceId*/, + [[maybe_unused]] bool /*isPrimaryClient*/) override { + // No op + return binder::Status::ok(); + } + bool waitForNumCameras(size_t num) const { Mutex::Autolock l(mLock); @@ -281,6 +290,12 @@ return binder::Status::ok(); } + virtual binder::Status onClientSharedAccessPriorityChanged( + [[maybe_unused]] bool /*isPrimaryClient*/) { + // No-op + return binder::Status::ok(); + } + // Test helper functions: bool hadError() const { @@ -402,7 +417,8 @@ res = service->connectDevice(callbacks, cameraId, /*oomScoreOffset*/ 0, /*targetSdkVersion*/__ANDROID_API_FUTURE__, - /*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0, /*out*/&device); + /*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0, + /*sharedMode*/false, /*out*/&device); EXPECT_TRUE(res.isOk()) << res; ASSERT_NE(nullptr, device.get()); device->disconnect(); @@ -451,7 +467,7 @@ /*oomScoreOffset*/ 0, /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0, - /*out*/&device); + /*sharedMode*/false, /*out*/&device); EXPECT_TRUE(res.isOk()) << res; } auto p = std::make_pair(callbacks, device);
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp index 4ec26d6..8f5081a 100644 --- a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp +++ b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
@@ -542,6 +542,7 @@ Dav1dSettings lib_settings; dav1d_default_settings(&lib_settings); + lib_settings.all_layers = 0; int cpu_count = GetCPUCoreCount(); lib_settings.n_threads = std::max(cpu_count / 2, 1); // use up to half the cores by default.
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp index fcdaff9..e413241 100644 --- a/media/libmediaplayerservice/fuzzer/Android.bp +++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -33,6 +33,7 @@ "liblog", ], shared_libs: [ + "camera_platform_flags_c_lib", "framework-permission-aidl-cpp", "libbinder", "libbinder_ndk",
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp index a74b6d6..fbc613c 100644 --- a/services/camera/libcameraservice/Android.bp +++ b/services/camera/libcameraservice/Android.bp
@@ -73,6 +73,7 @@ "libsensorprivacy", "libstagefright", "libstagefright_foundation", + "libtinyxml2", "libvendorsupport", "libxml2", "libyuv", @@ -101,8 +102,8 @@ "android.frameworks.cameraservice.device@2.0", "android.frameworks.cameraservice.device@2.1", "android.frameworks.cameraservice.common-V1-ndk", - "android.frameworks.cameraservice.service-V2-ndk", - "android.frameworks.cameraservice.device-V2-ndk", + "android.frameworks.cameraservice.service-V3-ndk", + "android.frameworks.cameraservice.device-V3-ndk", "android.hardware.camera.common-V1-ndk", "android.hardware.camera.device-V3-ndk", "android.hardware.camera.metadata-V3-ndk", @@ -140,6 +141,8 @@ "common/FrameProcessorBase.cpp", "common/hidl/HidlProviderInfo.cpp", "common/aidl/AidlProviderInfo.cpp", + "config/SharedSessionConfigUtils.cpp", + "config/SharedSessionConfigReader.cpp", "api1/Camera2Client.cpp", "api1/client2/Parameters.cpp", "api1/client2/FrameProcessor.cpp", @@ -179,6 +182,7 @@ "device3/aidl/AidlCamera3Device.cpp", "device3/aidl/AidlCamera3OutputUtils.cpp", "device3/aidl/AidlCamera3OfflineSession.cpp", + "device3/aidl/AidlCamera3SharedDevice.cpp", "gui/RingBufferConsumer.cpp", "hidl/AidlCameraDeviceCallbacks.cpp", "hidl/AidlCameraServiceListener.cpp", @@ -218,6 +222,7 @@ "libcamera_client", "libfmq", "libsensorprivacy", + "libtinyxml2", ], include_dirs: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index eb8708e..f030b91 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp
@@ -550,7 +550,7 @@ updateStatus(StatusInternal::NOT_PRESENT, cameraId); mVirtualDeviceCameraIdMapper.removeCamera(cameraId); - sp<BasicClient> clientToDisconnectOnline, clientToDisconnectOffline; + std::vector<sp<BasicClient>> clientsToDisconnectOnline, clientsToDisconnectOffline; { // Don't do this in updateStatus to avoid deadlock over mServiceLock Mutex::Autolock lock(mServiceLock); @@ -560,12 +560,12 @@ // Remove online as well as offline client from the list of active clients, // if they are present - clientToDisconnectOnline = removeClientLocked(cameraId); - clientToDisconnectOffline = removeClientLocked(kOfflineDevice + cameraId); + clientsToDisconnectOnline = removeClientsLocked(cameraId); + clientsToDisconnectOffline = removeClientsLocked(kOfflineDevice + cameraId); } - disconnectClient(cameraId, clientToDisconnectOnline); - disconnectClient(kOfflineDevice + cameraId, clientToDisconnectOffline); + disconnectClients(cameraId, clientsToDisconnectOnline); + disconnectClients(kOfflineDevice + cameraId, clientsToDisconnectOffline); removeStates(cameraId); } else { @@ -639,6 +639,13 @@ } } +void CameraService::disconnectClients(const std::string& id, + std::vector<sp<BasicClient>> clientsToDisconnect) { + for (auto& client : clientsToDisconnect) { + disconnectClient(id, client); + } +} + void CameraService::disconnectClient(const std::string& id, sp<BasicClient> clientToDisconnect) { if (clientToDisconnect.get() != nullptr) { ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL", @@ -1471,7 +1478,7 @@ int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid, int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport, apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride, - bool forceSlowJpegMode, const std::string& originalCameraId, + bool forceSlowJpegMode, const std::string& originalCameraId, bool sharedMode, /*out*/sp<BasicClient>* client) { // For HIDL devices if (deviceVersionAndTransport.second == IPCTransport::HIDL) { @@ -1507,7 +1514,7 @@ cameraService->mAttributionAndPermissionUtils, packageName, featureId, cameraId, api1CameraId, facing, sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass, rotationOverride, - forceSlowJpegMode); + forceSlowJpegMode, /*sharedMode*/false); ALOGI("%s: Camera1 API (legacy), rotationOverride %d, forceSlowJpegMode %d", __FUNCTION__, rotationOverride, forceSlowJpegMode); } else { // Camera2 API route @@ -1517,7 +1524,7 @@ cameraService->mCameraServiceProxyWrapper, cameraService->mAttributionAndPermissionUtils, packageName, systemNativeClient, featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid, - overrideForPerfClass, rotationOverride, originalCameraId); + overrideForPerfClass, rotationOverride, originalCameraId, sharedMode); ALOGI("%s: Camera2 API, rotationOverride %d", __FUNCTION__, rotationOverride); } return Status::ok(); @@ -1613,7 +1620,7 @@ API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0, /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT, - /*forceSlowJpegMode*/false, cameraIdStr, /*isNonSystemNdk*/ false, /*out*/ tmp) + /*forceSlowJpegMode*/false, cameraIdStr, /*isNonSystemNdk*/ false, /*sharedMode*/false, /*out*/ tmp) ).isOk()) { ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().c_str()); } @@ -1683,14 +1690,13 @@ } Status CameraService::validateConnectLocked(const std::string& cameraId, - const std::string& clientName8, int clientUid, int clientPid) const { - + const std::string& clientName8, int clientUid, int clientPid, bool sharedMode) const { #ifdef __BRILLO__ UNUSED(clientName8); UNUSED(clientUid); UNUSED(clientPid); #else - Status allowed = validateClientPermissionsLocked(cameraId, clientName8, clientUid, clientPid); + Status allowed = validateClientPermissionsLocked(cameraId, clientName8, clientUid, clientPid, sharedMode); if (!allowed.isOk()) { return allowed; } @@ -1742,7 +1748,7 @@ } Status CameraService::validateClientPermissionsLocked(const std::string& cameraId, - const std::string& clientName, int clientUid, int clientPid) const { + const std::string& clientName, int clientUid, int clientPid, bool sharedMode) const { int callingPid = getCallingPid(); int callingUid = getCallingUid(); @@ -1759,6 +1765,14 @@ "found while trying to query device kind", cameraId.c_str()); } + if (sharedMode + && (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA)) { + ALOGE("%s: camera id %s is not system camera. Device sharing only supported for" + " system cameras.", __FUNCTION__, cameraId.c_str()); + return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "camera device sharing not supported for " + "camera ID \"%s\"", cameraId.c_str()); + } + // Get the device id that owns this camera. auto [deviceId, _] = mVirtualDeviceCameraIdMapper.getDeviceIdAndMappedCameraIdPair(cameraId); @@ -1880,6 +1894,26 @@ __FUNCTION__); } + sp<BasicClient> clientSp = clientDescriptor->getValue(); + auto primaryClient = mActiveClientManager.getPrimaryClient(desc->getKey()); + if (primaryClient == nullptr) { + // There is no primary client yet. Assign this first client as + // primary + clientSp->setPrimaryClient(true); + } else { + // There is already primary client. If the incoming client has a + // higher priority than the existing primary, then assign incoming + // client as primary and change the existing client to secondary. + // Otherwise incoming client is secondary client. + if (clientDescriptor->getPriority() <= primaryClient->getPriority()) { + clientSp->setPrimaryClient(true); + primaryClient->getValue()->setPrimaryClient(false); + primaryClient->getValue()->notifyClientSharedAccessPriorityChanged(false); + } else { + clientSp->setPrimaryClient(false); + } + } + // And register a death notification for the client callback. Do // this last to avoid Binder policy where a nested Binder // transaction might be pre-empted to service the client death @@ -1894,6 +1928,7 @@ status_t CameraService::handleEvictionsLocked(const std::string& cameraId, int clientPid, apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, const std::string& packageName, int oomScoreOffset, bool systemNativeClient, + bool sharedMode, /*out*/ sp<BasicClient>* client, std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>>* partial) { @@ -1945,7 +1980,8 @@ clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId, sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()), state->getConflicting(), resource_policy::NATIVE_ADJ, clientPid, - ActivityManager::PROCESS_STATE_BOUND_TOP, oomScoreOffset, systemNativeClient); + ActivityManager::PROCESS_STATE_BOUND_TOP, oomScoreOffset, systemNativeClient, + sharedMode); } else { // Get current active client PIDs std::vector<int> ownerPids(mActiveClientManager.getAllOwners()); @@ -1981,7 +2017,7 @@ clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId, sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()), state->getConflicting(), actualScore, clientPid, actualState, - oomScoreOffset, systemNativeClient); + oomScoreOffset, systemNativeClient, sharedMode); } resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority(); @@ -2160,7 +2196,7 @@ clientPackageName, /*systemNativeClient*/ false, {}, clientUid, clientPid, API_1, /*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, - rotationOverride, forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*out*/client); + rotationOverride, forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false, /*out*/client); if (!ret.isOk()) { logRejected(cameraIdStr, getCallingPid(), clientAttribution.packageName.value_or(""), @@ -2243,8 +2279,7 @@ const std::string& unresolvedCameraId, int oomScoreOffset, int targetSdkVersion, int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy, - /*out*/ - sp<hardware::camera2::ICameraDeviceUser>* device) { + bool sharedMode, /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) { ATRACE_CALL(); RunThreadWithRealtimePriority priorityBump; Status ret = Status::ok(); @@ -2324,7 +2359,7 @@ cameraId, /*api1CameraId*/-1, clientPackageName, systemNativeClient, clientAttribution.attributionTag, clientUid, clientPid, API_2, /*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride, - /*forceSlowJpegMode*/false, unresolvedCameraId, isNonSystemNdk, /*out*/client); + /*forceSlowJpegMode*/false, unresolvedCameraId, isNonSystemNdk, sharedMode, /*out*/client); if (!ret.isOk()) { logRejected(cameraId, callingPid, clientPackageName, toStdString(ret.toString8())); @@ -2463,7 +2498,7 @@ const std::optional<std::string>& clientFeatureId, int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion, int rotationOverride, bool forceSlowJpegMode, - const std::string& originalCameraId, bool isNonSystemNdk, /*out*/sp<CLIENT>& device) { + const std::string& originalCameraId, bool isNonSystemNdk, bool sharedMode, /*out*/sp<CLIENT>& device) { binder::Status ret = binder::Status::ok(); int packageUid = (clientUid == USE_CALLING_UID) ? @@ -2492,7 +2527,7 @@ // Enforce client permissions and do basic validity checks if (!(ret = validateConnectLocked(cameraId, clientPackageName, - /*inout*/clientUid, /*inout*/clientPid)).isOk()) { + /*inout*/clientUid, /*inout*/clientPid, sharedMode)).isOk()) { return ret; } @@ -2511,7 +2546,7 @@ std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>> partial; if ((err = handleEvictionsLocked(cameraId, clientPid, effectiveApiLevel, IInterface::asBinder(cameraCb), clientPackageName, oomScoreOffset, - systemNativeClient, /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) { + systemNativeClient, sharedMode, /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) { switch (err) { case -ENODEV: return STATUS_ERROR_FMT(ERROR_DISCONNECTED, @@ -2561,7 +2596,7 @@ clientFeatureId, cameraId, api1CameraId, facing, orientation, getCallingPid(), clientUid, getpid(), deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass, - rotationOverride, forceSlowJpegMode, originalCameraId, + rotationOverride, forceSlowJpegMode, originalCameraId, sharedMode, /*out*/&tmp)).isOk()) { return ret; } @@ -2807,7 +2842,7 @@ /*conflictingKeys*/ std::set<std::string>(), onlinePriority.getScore(), onlineClientDesc->getOwnerId(), onlinePriority.getState(), // native clients don't have offline processing support. - /*ommScoreOffset*/ 0, /*systemNativeClient*/false); + /*ommScoreOffset*/ 0, /*systemNativeClient*/false, /*sharedMode*/false); if (offlineClientDesc == nullptr) { ALOGE("%s: Offline client descriptor was NULL", __FUNCTION__); return BAD_VALUE; @@ -3213,6 +3248,53 @@ } } +void CameraService::updateSharedClientAccessPriorities(std::vector<int> sharedClientPids) { + Mutex::Autolock lock(mServiceLock); + if (sharedClientPids.empty()) { + return; + } + std::vector<int> scores(sharedClientPids.size()); + std::vector<int> states(sharedClientPids.size()); + status_t err = ProcessInfoService::getProcessStatesScoresFromPids(sharedClientPids.size(), + &sharedClientPids[0], /*out*/&states[0], /*out*/&scores[0]); + if (err != OK) { + return; + } + for (size_t i = 0; i < sharedClientPids.size(); i++) { + auto clientDescriptorPtr = mActiveClientManager.getSharedClient(sharedClientPids[i]); + if (clientDescriptorPtr == nullptr) { + continue; + } + const auto& clientPriority = clientDescriptorPtr->getPriority(); + int score = clientPriority.getScore(); + int state = clientPriority.getState(); + if ((score != scores[i]) || (state != states[i])){ + clientDescriptorPtr->setPriority(resource_policy::ClientPriority(scores[i], states[i], + false, 0)); + notifySharedClientPrioritiesChanged(clientDescriptorPtr->getKey()); + } + } +} + +void CameraService::notifySharedClientPrioritiesChanged(const std::string& cameraId) { + auto primaryClientDesc = mActiveClientManager.getPrimaryClient(cameraId); + if (primaryClientDesc == nullptr) { + return; + } + auto primaryClient = primaryClientDesc->getValue(); + if (primaryClient == nullptr) { + return; + } + auto highestPriorityClient = mActiveClientManager.getHighestPrioritySharedClient(cameraId); + if (highestPriorityClient == primaryClient) { + return; + } + highestPriorityClient->setPrimaryClient(true); + highestPriorityClient->notifyClientSharedAccessPriorityChanged(true); + primaryClient->setPrimaryClient(false); + primaryClient->notifyClientSharedAccessPriorityChanged(false); +} + Status CameraService::notifyDeviceStateChange(int64_t newState) { const int pid = getCallingPid(); const int selfPid = getpid(); @@ -3740,6 +3822,22 @@ updateAudioRestrictionLocked(); } +bool CameraService::isOnlyClient(const BasicClient* client) { + Mutex::Autolock lock(mServiceLock); + bool ret = true; + if (client != nullptr) { + std::string camId = client->mCameraIdStr; + for (const auto& i : mActiveClientManager.getAll()) { + auto clientSp = i->getValue(); + auto curCamId = i->getKey(); + if (!curCamId.compare(camId) && clientSp.get() != client) { + return false; + } + } + } + return ret; +} + bool CameraService::evictClientIdByRemote(const wp<IBinder>& remote) { bool ret = false; { @@ -3800,20 +3898,22 @@ return state; } -sp<CameraService::BasicClient> CameraService::removeClientLocked(const std::string& cameraId) { +std::vector<sp<CameraService::BasicClient>> CameraService::removeClientsLocked( + const std::string& cameraId) { // Remove from active clients list - auto clientDescriptorPtr = mActiveClientManager.remove(cameraId); - if (clientDescriptorPtr == nullptr) { - ALOGW("%s: Could not evict client, no client for camera ID %s", __FUNCTION__, - cameraId.c_str()); - return sp<BasicClient>{nullptr}; + std::vector<sp<CameraService::BasicClient>> clients; + std::vector<CameraService::DescriptorPtr> clientDescriptors; + clientDescriptors = mActiveClientManager.removeAll(cameraId); + for (const auto& clientDescriptorPtr : clientDescriptors) { + if (clientDescriptorPtr != nullptr) { + sp<BasicClient> client = clientDescriptorPtr->getValue(); + if (client.get() != nullptr) { + cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get()); + clients.push_back(client); + } + } } - - sp<BasicClient> client = clientDescriptorPtr->getValue(); - if (client.get() != nullptr) { - cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get()); - } - return client; + return clients; } void CameraService::doUserSwitch(const std::vector<int32_t>& newUserIds) { @@ -4100,14 +4200,14 @@ const std::string& cameraIdStr, int api1CameraId, int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid, - int servicePid, int rotationOverride) : + int servicePid, int rotationOverride, bool sharedMode) : CameraService::BasicClient(cameraService, IInterface::asBinder(cameraClient), attributionAndPermissionUtils, clientPackageName, systemNativeClient, clientFeatureId, cameraIdStr, cameraFacing, sensorOrientation, clientPid, clientUid, - servicePid, rotationOverride), + servicePid, rotationOverride, sharedMode), mCameraId(api1CameraId) { int callingPid = getCallingPid(); @@ -4138,7 +4238,7 @@ const std::string& clientPackageName, bool nativeClient, const std::optional<std::string>& clientFeatureId, const std::string& cameraIdStr, int cameraFacing, int sensorOrientation, int clientPid, uid_t clientUid, - int servicePid, int rotationOverride): + int servicePid, int rotationOverride, bool sharedMode): AttributionAndPermissionUtilsEncapsulator(attributionAndPermissionUtils), mDestructionStarted(false), mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing), mOrientation(sensorOrientation), @@ -4147,7 +4247,7 @@ mClientPid(clientPid), mClientUid(clientUid), mServicePid(servicePid), mDisconnected(false), mUidIsTrusted(false), - mRotationOverride(rotationOverride), + mRotationOverride(rotationOverride), mSharedMode(sharedMode), mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE), mRemoteBinder(remoteCallback), mOpsActive(false), @@ -4189,8 +4289,15 @@ sCameraService->removeByClient(this); sCameraService->logDisconnected(mCameraIdStr, mClientPid, mClientPackageName); - sCameraService->mCameraProviderManager->removeRef(CameraProviderManager::DeviceMode::CAMERA, - mCameraIdStr); + if (!mSharedMode || (mSharedMode && + sCameraService->isOnlyClient(this))) { + // Remove the HAL reference for the camera in either of the following scenarios : + // 1) Camera was opened in non-shared mode. + // 2) Camera was opened in shared mode and this is the last client using + // the camera which is being disconnected + sCameraService->mCameraProviderManager->removeRef(CameraProviderManager::DeviceMode::CAMERA, + mCameraIdStr); + } sp<IBinder> remote = getRemote(); if (remote != nullptr) { @@ -4198,8 +4305,11 @@ } finishCameraOps(); - // Notify flashlight that a camera device is closed. - sCameraService->mFlashlight->deviceClosed(mCameraIdStr); + if (!mSharedMode || (mSharedMode && + sCameraService->isOnlyClient(this))) { + // Notify flashlight that a camera device is closed. + sCameraService->mFlashlight->deviceClosed(mCameraIdStr); + } ALOGI("%s: Disconnected client for camera %s for PID %d", __FUNCTION__, mCameraIdStr.c_str(), mClientPid); @@ -4361,8 +4471,12 @@ sCameraService->mUidPolicy->registerMonitorUid(mClientUid, /*openCamera*/true); + if (mSharedMode) { + sCameraService->mUidPolicy->addSharedClientPid(getClientUid(), getClientPid()); + } + // Notify listeners of camera open/close status - sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName); + sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName, mSharedMode); return OK; } @@ -4459,8 +4573,11 @@ StatusInternal::ENUMERATING, StatusInternal::NOT_PRESENT}; // Transition to PRESENT if the camera is not in either of the rejected states - sCameraService->updateStatus(StatusInternal::PRESENT, - mCameraIdStr, rejected); + if (!mSharedMode || (mSharedMode + && sCameraService->isOnlyClient(this))) { + sCameraService->updateStatus(StatusInternal::PRESENT, + mCameraIdStr, rejected); + } } // Always stop watching, even if no camera op is active if (mOpsCallback != nullptr && mAppOpsManager != nullptr) { @@ -4470,8 +4587,12 @@ sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid, /*closeCamera*/true); + if (mSharedMode) { + sCameraService->mUidPolicy->removeSharedClientPid(getClientUid(), getClientPid()); + } + // Notify listeners of camera open/close status - sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName); + sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName, mSharedMode); return OK; } @@ -4547,6 +4668,25 @@ disconnect(); } +status_t CameraService::BasicClient::isPrimaryClient(bool* isPrimary) { + ATRACE_CALL(); + if (!mSharedMode) { + return INVALID_OPERATION; + } + *isPrimary = mIsPrimaryClient; + return OK; +} + +status_t CameraService::BasicClient::setPrimaryClient(bool isPrimary) { + ATRACE_CALL(); + + if (!mSharedMode) { + return INVALID_OPERATION; + } + mIsPrimaryClient = isPrimary; + return OK; +} + // ---------------------------------------------------------------------------- void CameraService::Client::notifyError(int32_t errorCode, @@ -4667,21 +4807,33 @@ void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq __unused, int32_t capability __unused) { bool procStateChange = false; + std::vector<int> sharedPids; { Mutex::Autolock _l(mUidLock); - if (mMonitoredUids.find(uid) != mMonitoredUids.end() && - mMonitoredUids[uid].procState != procState) { - mMonitoredUids[uid].procState = procState; - procStateChange = true; + if (mMonitoredUids.find(uid) != mMonitoredUids.end()) { + if (mMonitoredUids[uid].procState != procState) { + mMonitoredUids[uid].procState = procState; + procStateChange = true; + } + std::unordered_set<int> sharedClientPids = mMonitoredUids[uid].sharedClientPids; + if (!sharedClientPids.empty()) { + sharedPids.assign(sharedClientPids.begin(), sharedClientPids.end()); + } } } + sp<CameraService> service = mService.promote(); if (procStateChange) { - sp<CameraService> service = mService.promote(); if (service != nullptr) { service->notifyMonitoredUids(); } } + + if (!sharedPids.empty()) { + if (service != nullptr) { + service->updateSharedClientAccessPriorities(sharedPids); + } + } } /** @@ -4694,6 +4846,7 @@ */ void CameraService::UidPolicy::onUidProcAdjChanged(uid_t uid, int32_t adj) { std::unordered_set<uid_t> notifyUidSet; + std::vector<int> sharedPids; { Mutex::Autolock _l(mUidLock); auto it = mMonitoredUids.find(uid); @@ -4717,15 +4870,26 @@ } } it->second.procAdj = adj; + std::unordered_set<int> sharedClientPids = it->second.sharedClientPids; + if (!sharedClientPids.empty()) { + sharedPids.assign(sharedClientPids.begin(), sharedClientPids.end()); + } } } + sp<CameraService> service = mService.promote(); + if (notifyUidSet.size() > 0) { - sp<CameraService> service = mService.promote(); if (service != nullptr) { service->notifyMonitoredUids(notifyUidSet); } } + + if (!sharedPids.empty()) { + if (service != nullptr) { + service->updateSharedClientAccessPriorities(sharedPids); + } + } } /** @@ -4859,6 +5023,20 @@ updateOverrideUid(uid, callingPackage, false, false); } +void CameraService::UidPolicy::addSharedClientPid(uid_t uid, int pid) { + Mutex::Autolock _l(mUidLock); + if (mMonitoredUids.find(uid) != mMonitoredUids.end()) { + mMonitoredUids[uid].sharedClientPids.insert(pid); + } +} + +void CameraService::UidPolicy::removeSharedClientPid(uid_t uid, int pid) { + Mutex::Autolock _l(mUidLock); + if (mMonitoredUids.find(uid) != mMonitoredUids.end()) { + mMonitoredUids[uid].sharedClientPids.erase(pid); + } +} + void CameraService::UidPolicy::binderDied(const wp<IBinder>& /*who*/) { Mutex::Autolock _l(mUidLock); ALOGV("UidPolicy: ActivityManager has died"); @@ -5097,12 +5275,27 @@ void CameraService::CameraState::setClientPackage(const std::string& clientPackage) { Mutex::Autolock lock(mStatusLock); - mClientPackage = clientPackage; + mClientPackages.clear(); + mClientPackages.insert(clientPackage); } std::string CameraService::CameraState::getClientPackage() const { Mutex::Autolock lock(mStatusLock); - return mClientPackage; + if (!mClientPackages.empty()) { + std::set<std::string>::iterator it = mClientPackages.begin(); + return *it; + } + return std::string(); +} + +void CameraService::CameraState::addClientPackage(const std::string& clientPackage) { + Mutex::Autolock lock(mStatusLock); + mClientPackages.insert(clientPackage); +} + +void CameraService::CameraState::removeClientPackage(const std::string& clientPackage) { + Mutex::Autolock lock(mStatusLock); + mClientPackages.erase(clientPackage); } // ---------------------------------------------------------------------------- @@ -5150,6 +5343,48 @@ return descriptor->getValue(); } +sp<CameraService::BasicClient> CameraService::CameraClientManager::getHighestPrioritySharedClient( + const std::string& id) const { + auto clientDescriptor = get(id); + if (clientDescriptor == nullptr) { + ALOGV("CameraService::CameraClientManager::no other clients are using same camera"); + return sp<BasicClient>{nullptr}; + } + if (!clientDescriptor->getSharedMode()) { + return sp<BasicClient>{nullptr}; + } + resource_policy::ClientPriority highestPriority = clientDescriptor->getPriority(); + sp<BasicClient> highestPriorityClient = clientDescriptor->getValue(); + if (highestPriorityClient.get() == nullptr) { + return sp<BasicClient>{nullptr}; + } + for (auto& i : getAll()) { + if ((i->getKey() == id) && (i->getSharedMode()) && (i->getPriority() < highestPriority)) { + highestPriority = i->getPriority(); + highestPriorityClient = i->getValue(); + } + } + return highestPriorityClient; +} + +void CameraService::CameraClientManager::remove(const CameraService::DescriptorPtr& value) { + ClientManager::remove(value); + auto clientToRemove = value->getValue(); + if ((clientToRemove.get() != nullptr) && clientToRemove->mSharedMode) { + bool primaryClient = false; + status_t ret = clientToRemove->isPrimaryClient(&primaryClient); + if ((ret == OK) && primaryClient) { + // Primary client is being removed. Find the next higher priority + // client to become primary client. + auto highestPriorityClient = getHighestPrioritySharedClient(value->getKey()); + if (highestPriorityClient != nullptr) { + highestPriorityClient->setPrimaryClient(true); + highestPriorityClient->notifyClientSharedAccessPriorityChanged(true); + } + } + } +} + std::string CameraService::CameraClientManager::toString() const { auto all = getAll(); std::ostringstream ret; @@ -5195,14 +5430,14 @@ CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor( const std::string& key, const sp<BasicClient>& value, int32_t cost, const std::set<std::string>& conflictingKeys, int32_t score, int32_t ownerId, - int32_t state, int32_t oomScoreOffset, bool systemNativeClient) { + int32_t state, int32_t oomScoreOffset, bool systemNativeClient, bool sharedMode) { int32_t score_adj = systemNativeClient ? kSystemNativeClientScore : score; int32_t state_adj = systemNativeClient ? kSystemNativeClientState : state; return std::make_shared<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>>( key, value, cost, conflictingKeys, score_adj, ownerId, state_adj, - systemNativeClient, oomScoreOffset); + systemNativeClient, oomScoreOffset, sharedMode); } CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor( @@ -5211,7 +5446,7 @@ return makeClientDescriptor(partial->getKey(), value, partial->getCost(), partial->getConflicting(), partial->getPriority().getScore(), partial->getOwnerId(), partial->getPriority().getState(), oomScoreOffset, - systemNativeClient); + systemNativeClient, partial->getSharedMode()); } // ---------------------------------------------------------------------------- @@ -5743,7 +5978,7 @@ } void CameraService::updateOpenCloseStatus(const std::string& cameraId, bool open, - const std::string& clientPackageName) { + const std::string& clientPackageName, bool sharedMode) { auto state = getCameraState(cameraId); if (state == nullptr) { ALOGW("%s: Could not update the status for %s, no such device exists", __FUNCTION__, @@ -5751,9 +5986,17 @@ return; } if (open) { - state->setClientPackage(clientPackageName); + if (sharedMode) { + state->addClientPackage(clientPackageName); + } else { + state->setClientPackage(clientPackageName); + } } else { - state->setClientPackage(std::string()); + if (sharedMode) { + state->removeClientPackage(clientPackageName); + } else { + state->setClientPackage(std::string()); + } } // Get the device id and app-visible camera id for the given HAL-visible camera id. @@ -5772,7 +6015,10 @@ ret = it->getListener()->onCameraOpened(mappedCameraId, clientPackageName, deviceId); } else { - ret = it->getListener()->onCameraClosed(mappedCameraId, deviceId); + if (!sharedMode || (sharedMode && + mActiveClientManager.getCameraClient(cameraId) == nullptr)) { + ret = it->getListener()->onCameraClosed(mappedCameraId, deviceId); + } } it->handleBinderStatus(ret,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 0ac391d..ad6b6ba 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h
@@ -181,7 +181,7 @@ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const std::string& cameraId, int scoreOffset, int targetSdkVersion, int rotationOverride, const AttributionSourceState& clientAttribution, - int32_t devicePolicy, + int32_t devicePolicy, bool sharedMode, /*out*/ sp<hardware::camera2::ICameraDeviceUser>* device); @@ -384,6 +384,8 @@ virtual void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) = 0; + virtual void notifyClientSharedAccessPriorityChanged(bool primaryClient) = 0; + // Get the UID of the application client using this virtual uid_t getClientUid() const; @@ -450,8 +452,12 @@ virtual status_t injectSessionParams( const hardware::camera2::impl::CameraMetadataNative& sessionParams) = 0; + status_t isPrimaryClient(/*out*/bool* isPrimary); + + status_t setPrimaryClient(bool isPrimary); + protected: - BasicClient(const sp<CameraService>& cameraService, + BasicClient(const sp<CameraService>& cameraService, const sp<IBinder>& remoteCallback, std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils, const std::string& clientPackageName, @@ -463,7 +469,8 @@ int clientPid, uid_t clientUid, int servicePid, - int rotationOverride); + int rotationOverride, + bool sharedMode); virtual ~BasicClient(); @@ -487,6 +494,8 @@ bool mDisconnected; bool mUidIsTrusted; int mRotationOverride; + bool mSharedMode; + bool mIsPrimaryClient; mutable Mutex mAudioRestrictionLock; int32_t mAudioRestriction; @@ -578,7 +587,9 @@ int clientPid, uid_t clientUid, int servicePid, - int rotationOverride); + int rotationOverride, + bool sharedMode); + ~Client(); // return our camera client @@ -638,6 +649,11 @@ CameraClientManager(); virtual ~CameraClientManager(); + // Bring all remove() functions into scope + using ClientManager::remove; + + virtual void remove(const DescriptorPtr& value) override; + /** * Return a strong pointer to the active BasicClient for this camera ID, or an empty * if none exists. @@ -645,6 +661,12 @@ sp<CameraService::BasicClient> getCameraClient(const std::string& id) const; /** + * Return a strong pointer to the highest priority client among all the clients which + * have opened this camera ID in shared mode, or empty if none exists. + */ + sp<CameraService::BasicClient> getHighestPrioritySharedClient(const std::string& id) const; + + /** * Return a string describing the current state. */ std::string toString() const; @@ -655,7 +677,8 @@ static DescriptorPtr makeClientDescriptor(const std::string& key, const sp<BasicClient>& value, int32_t cost, const std::set<std::string>& conflictingKeys, int32_t score, - int32_t ownerId, int32_t state, int oomScoreOffset, bool systemNativeClient); + int32_t ownerId, int32_t state, int oomScoreOffset, bool systemNativeClient, + bool sharedMode); /** * Make a ClientDescriptor object wrapping the given BasicClient strong pointer with @@ -670,6 +693,15 @@ int32_t updateAudioRestriction(); int32_t updateAudioRestrictionLocked(); + /** + * Returns true if the given client is the only client in the active clients list for a given + * camera. + * + * This method acquires mServiceLock. + */ + bool isOnlyClient(const BasicClient* client); + + private: // TODO: b/263304156 update this to make use of a death callback for more @@ -806,6 +838,10 @@ void setClientPackage(const std::string& clientPackage); std::string getClientPackage() const; + void addClientPackage(const std::string& clientPackage); + void removeClientPackage(const std::string& clientPackage); + std::set<std::string> getClientPackages() const; + /** * Return the unavailable physical ids for this device. * @@ -818,7 +854,7 @@ const int mCost; std::set<std::string> mConflicting; std::set<std::string> mUnavailablePhysicalIds; - std::string mClientPackage; + std::set<std::string> mClientPackages; mutable Mutex mStatusLock; CameraParameters mShimParams; const SystemCameraKind mSystemCameraKind; @@ -855,6 +891,9 @@ void registerMonitorUid(uid_t uid, bool openCamera); void unregisterMonitorUid(uid_t uid, bool closeCamera); + void addSharedClientPid(uid_t uid, int pid); + void removeSharedClientPid(uid_t uid, int pid); + // Implementation of IServiceManager::LocalRegistrationCallback virtual void onServiceRegistration(const String16& name, const sp<IBinder>& binder) override; @@ -872,6 +911,9 @@ int32_t procAdj; bool hasCamera; size_t refCount; + // This field is only valid when camera has been opened in shared mode, to adjust the + // priority of active clients based on the latest process score and state. + std::unordered_set<int> sharedClientPids; }; Mutex mUidLock; @@ -947,12 +989,11 @@ void removeStates(const std::string& id); // Check if we can connect, before we acquire the service lock. - // If clientPid/clientUid are USE_CALLING_PID/USE_CALLING_UID, they will be overwritten with - // the calling pid/uid. binder::Status validateConnectLocked(const std::string& cameraId, const std::string& clientName, - int clientUid, int clientPid) const; + int clientUid, int clientPid, bool sharedMode) const; binder::Status validateClientPermissionsLocked(const std::string& cameraId, - const std::string& clientName, int clientUid, int clientPid) const; + const std::string& clientName, int clientUid, int clientPid, bool sharedMode) const; + // If clientPackageNameMaybe is empty, attempts to resolve the package name. std::string resolvePackageName(int clientUid, const std::string& clientPackageNameMaybe) const; @@ -968,7 +1009,7 @@ // Only call with with mServiceLock held. status_t handleEvictionsLocked(const std::string& cameraId, int clientPid, apiLevel effectiveApiLevel, const sp<IBinder>& remoteCallback, - const std::string& packageName, int scoreOffset, bool systemNativeClient, + const std::string& packageName, int scoreOffset, bool systemNativeClient, bool sharedMode, /*out*/ sp<BasicClient>* client, std::shared_ptr<resource_policy::ClientDescriptor<std::string, sp<BasicClient>>>* partial); @@ -1013,7 +1054,7 @@ const std::optional<std::string>& clientFeatureId, int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion, int rotationOverride, bool forceSlowJpegMode, - const std::string& originalCameraId, bool isNonSystemNdk, + const std::string& originalCameraId, bool isNonSystemNdk, bool sharedMode, /*out*/sp<CLIENT>& device); // Lock guarding camera service state @@ -1110,6 +1151,18 @@ int oomScoreOffset, bool systemNativeClient); /** + * When multiple clients open the camera in shared mode, adjust the priority of active clients + * based on the latest process score and state. + */ + void updateSharedClientAccessPriorities(std::vector<int> sharedClientPids); + + /** + * Update all clients on any changes in the primary or secondary client status if the priority + * of any client changes when multiple clients are sharing a camera. + */ + void notifySharedClientPrioritiesChanged(const std::string& cameraId); + + /** * Returns the underlying camera Id string mapped to a camera id int * Empty string is returned when the cameraIdInt is invalid. */ @@ -1122,12 +1175,12 @@ std::string cameraIdIntToStrLocked(int cameraIdInt, int32_t deviceId, int32_t devicePolicy); /** - * Remove a single client corresponding to the given camera id from the list of active clients. + * Remove all the clients corresponding to the given camera id from the list of active clients. * If none exists, return an empty strongpointer. * * This method must be called with mServiceLock held. */ - sp<CameraService::BasicClient> removeClientLocked(const std::string& cameraId); + std::vector<sp<CameraService::BasicClient>> removeClientsLocked(const std::string& cameraId); /** * Handle a notification that the current device user has changed. @@ -1335,7 +1388,7 @@ * This method acqiures mStatusListenerLock. */ void updateOpenCloseStatus(const std::string& cameraId, bool open, - const std::string& packageName); + const std::string& packageName, bool sharedMode); // flashlight control sp<CameraFlashlight> mFlashlight; @@ -1508,9 +1561,10 @@ int clientPid, uid_t clientUid, int servicePid, std::pair<int, IPCTransport> deviceVersionAndIPCTransport, apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride, bool forceSlowJpegMode, - const std::string& originalCameraId, + const std::string& originalCameraId, bool sharedMode, /*out*/ sp<BasicClient>* client); + static std::string toString(std::set<userid_t> intSet); static int32_t mapToInterface(TorchModeStatus status); static StatusInternal mapToInternal(CameraDeviceStatus status); @@ -1524,6 +1578,9 @@ void disconnectClient(const std::string& id, sp<BasicClient> clientToDisconnect); + void disconnectClients(const std::string& id, + std::vector<sp<BasicClient>> clientsToDisconnect); + // Regular online and offline devices must not be in conflict at camera service layer. // Use separate keys for offline devices. static const std::string kOfflineDevice;
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp index e648a36..eac61e7 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp +++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
@@ -79,6 +79,12 @@ return binder::Status::ok(); } +binder::Status AidlCameraDeviceCallbacks::onClientSharedAccessPriorityChanged(bool primaryClient) { + auto ret = mBase->onClientSharedAccessPriorityChanged(primaryClient); + LOG_STATUS_ERROR_IF_NOT_OK(ret, "onClientSharedAccessPriorityChanged") + return binder::Status::ok(); + } + binder::Status AidlCameraDeviceCallbacks::onDeviceIdle() { auto ret = mBase->onDeviceIdle(); LOG_STATUS_ERROR_IF_NOT_OK(ret, "onDeviceIdle")
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h index 5cff5b3..07bf7d8 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h +++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
@@ -75,6 +75,8 @@ binder::Status onRequestQueueEmpty() override; + binder::Status onClientSharedAccessPriorityChanged(bool primaryClient) override; + status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags) override; status_t unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp index 9e6a925..eacfeac 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp +++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
@@ -192,6 +192,30 @@ return fromUStatus(ret); } +ndk::ScopedAStatus AidlCameraDeviceUser::isPrimaryClient(bool* _aidl_return) { + bool isPrimary; + UStatus ret = mDeviceRemote->isPrimaryClient(&isPrimary); + if (!ret.isOk()) { + ALOGE("%s: Failed to get isPrimaryClient: %s", __FUNCTION__, ret.toString8().c_str()); + } + *_aidl_return = isPrimary; + return fromUStatus(ret); +} + +ndk::ScopedAStatus AidlCameraDeviceUser::startStreaming( + const std::vector<int32_t>& in_streamIdxArray, + const std::vector<int32_t>& in_surfaceIdxArray, SSubmitInfo* _aidl_return){ + USubmitInfo submitInfo; + UStatus ret = mDeviceRemote->startStreaming(in_streamIdxArray, in_surfaceIdxArray, &submitInfo); + if (!ret.isOk()) { + ALOGE("%s: Failed to start streaming: %s", __FUNCTION__, ret.toString8().c_str()); + return fromUStatus(ret); + } + mRequestId = submitInfo.mRequestId; + convertToAidl(submitInfo, _aidl_return); + return ScopedAStatus::ok(); +} + ndk::ScopedAStatus AidlCameraDeviceUser::flush(int64_t* _aidl_return) { UStatus ret = mDeviceRemote->flush(_aidl_return); return fromUStatus(ret); @@ -278,4 +302,4 @@ return true; } -} // namespace android::frameworks::cameraservice::device::implementation \ No newline at end of file +} // namespace android::frameworks::cameraservice::device::implementation
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h index 8014951..25464a5 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h +++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
@@ -97,6 +97,11 @@ return mCaptureResultMetadataQueue; } + ndk::ScopedAStatus isPrimaryClient(bool* _aidl_return) override; + + ndk::ScopedAStatus startStreaming(const std::vector<int32_t>& in_streamIdxArray, + const std::vector<int32_t>& in_surfaceIdxArray, SSubmitInfo* _aidl_return) override; + private: bool initDevice();
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp index 7f674bd..d683d61 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp +++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -30,6 +30,9 @@ #include <hidl/HidlTransportSupport.h> #include <utils/AttributionAndPermissionUtils.h> #include <utils/Utils.h> +#include <com_android_internal_camera_flags.h> + +namespace flags = com::android::internal::camera::flags; namespace android::frameworks::cameraservice::service::implementation { @@ -131,10 +134,25 @@ return ScopedAStatus::ok(); } + ndk::ScopedAStatus AidlCameraService::connectDevice( const std::shared_ptr<SICameraDeviceCallback>& in_callback, const std::string& in_cameraId, std::shared_ptr<SICameraDeviceUser>* _aidl_return) { + return connectDeviceImpl(in_callback, in_cameraId, /*sharedMode*/false, _aidl_return); +} + +ndk::ScopedAStatus AidlCameraService::connectDeviceV2( + const std::shared_ptr<SICameraDeviceCallback>& in_callback, + const std::string& in_cameraId, bool sharedMode, + std::shared_ptr<SICameraDeviceUser>* _aidl_return) { + return connectDeviceImpl(in_callback, in_cameraId, sharedMode, _aidl_return); +} + +ndk::ScopedAStatus AidlCameraService::connectDeviceImpl( + const std::shared_ptr<SICameraDeviceCallback>& in_callback, + const std::string& in_cameraId, bool sharedMode, + std::shared_ptr<SICameraDeviceUser>* _aidl_return) { // Here, we first get NDK ICameraDeviceUser from mCameraService, then save // that interface in the newly created AidlCameraDeviceUser impl class. if (mCameraService == nullptr) { @@ -164,6 +182,7 @@ ROTATION_OVERRIDE_NONE, clientAttribution, /* devicePolicy= */ 0, + sharedMode, &unstableDevice); if (!serviceRet.isOk()) { ALOGE("%s: Unable to connect to camera device: %s", __FUNCTION__,
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.h b/services/camera/libcameraservice/aidl/AidlCameraService.h index 4c67ac7..80e965d 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraService.h +++ b/services/camera/libcameraservice/aidl/AidlCameraService.h
@@ -60,6 +60,9 @@ ndk::ScopedAStatus removeListener( const std::shared_ptr<SICameraServiceListener>& in_listener) override; + ndk::ScopedAStatus connectDeviceV2(const std::shared_ptr<SICameraDeviceCallback>& in_callback, + const std::string& in_cameraId, bool sharedMode, + std::shared_ptr<SICameraDeviceUser>* _aidl_return); private: void addToListenerCacheLocked(std::shared_ptr<SICameraServiceListener> stableCsListener, sp<hardware::ICameraServiceListener> csListener); @@ -70,6 +73,9 @@ SStatus addListenerInternal(const std::shared_ptr<SICameraServiceListener>& listener, std::vector<hardware::CameraStatus>* cameraStatusAndIds); + ndk::ScopedAStatus connectDeviceImpl(const std::shared_ptr<SICameraDeviceCallback>& in_callback, + const std::string& in_cameraId, bool sharedMode, + std::shared_ptr<SICameraDeviceUser>* _aidl_return); ::android::CameraService* mCameraService;
diff --git a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h index a7c32e3..c0dc688 100644 --- a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h +++ b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
@@ -75,6 +75,11 @@ uint32_t flags) override; status_t unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, wp<DeathRecipient>* outRecipient) override; + binder::Status onCameraOpenedInSharedMode(const std::string& /*cameraId*/, + const std::string& /*clientPackageId*/, int32_t /*deviceId*/, bool /*primaryClient*/) { + // empty implementation + return binder::Status::ok(); + } private: std::shared_ptr<SICameraServiceListener> mBase; @@ -86,4 +91,4 @@ } // android -#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICELISTENER_H_ \ No newline at end of file +#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICELISTENER_H_
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h index b07d8d5..b8d88c0 100644 --- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h +++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -93,6 +93,10 @@ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL, ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION, } }, + {36, { + ANDROID_SHARED_SESSION_COLOR_SPACE, + ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS, + } }, }; /**
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 861414f..ae68a72 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -70,12 +70,13 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, - bool forceSlowJpegMode): + bool forceSlowJpegMode, + bool sharedMode): Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper, attributionAndPermissionUtils, clientPackageName, false/*systemNativeClient - since no ndk for api1*/, clientFeatureId, cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid, - clientUid, servicePid, overrideForPerfClass, rotationOverride, + clientUid, servicePid, overrideForPerfClass, rotationOverride, sharedMode, /*legacyClient*/ true), mParameters(api1CameraId, cameraFacing), mLatestRequestIds(kMaxRequestIds),
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index a0c9f2d..e7ff923 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -115,7 +115,7 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, - bool forceSlowJpegMode); + bool forceSlowJpegMode, bool sharedMode); virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index f469aad..888875e 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -54,6 +54,7 @@ using namespace camera2; using namespace camera3; using camera3::camera_stream_rotation_t::CAMERA_STREAM_ROTATION_0; +using hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES; namespace flags = com::android::internal::camera::flags; @@ -71,7 +72,8 @@ int clientPid, uid_t clientUid, int servicePid, - int rotationOverride) : + int rotationOverride, + bool sharedMode) : BasicClient(cameraService, IInterface::asBinder(remoteCallback), attributionAndPermissionUtils, @@ -84,7 +86,8 @@ clientPid, clientUid, servicePid, - rotationOverride), + rotationOverride, + sharedMode), mRemoteCallback(remoteCallback) { } @@ -105,14 +108,16 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, - const std::string& originalCameraId) : + const std::string& originalCameraId, + bool sharedMode) : Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper, attributionAndPermissionUtils, clientPackageName, systemNativeClient, clientFeatureId, cameraId, /*API1 camera ID*/ -1, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid, overrideForPerfClass, - rotationOverride), + rotationOverride, sharedMode), mInputStream(), mStreamingRequestId(REQUEST_ID_NONE), + mStreamingRequestLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES), mRequestIdCounter(0), mOverrideForPerfClass(overrideForPerfClass), mOriginalCameraId(originalCameraId) { @@ -136,13 +141,23 @@ return res; } - mFrameProcessor = new FrameProcessorBase(mDevice); - std::string threadName = std::string("CDU-") + mCameraIdStr + "-FrameProc"; - res = mFrameProcessor->run(threadName.c_str()); - if (res != OK) { - ALOGE("%s: Unable to start frame processor thread: %s (%d)", - __FUNCTION__, strerror(-res), res); - return res; + if (mSharedMode) { + // In shared camera device mode, there can be more than one clients and + // frame processor thread is started by shared camera device. + mFrameProcessor = mDevice->getSharedFrameProcessor(); + if (mFrameProcessor == nullptr) { + ALOGE("%s: Unable to start frame processor thread", __FUNCTION__); + return UNKNOWN_ERROR; + } + } else { + mFrameProcessor = new FrameProcessorBase(mDevice); + std::string threadName = std::string("CDU-") + mCameraIdStr + "-FrameProc"; + res = mFrameProcessor->run(threadName.c_str()); + if (res != OK) { + ALOGE("%s: Unable to start frame processor thread: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } } mFrameProcessor->registerListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID, @@ -268,6 +283,98 @@ return intersection; } +binder::Status CameraDeviceClient::startStreaming(const std::vector<int>& streamIds, + const std::vector<int>& surfaceIds, + /*out*/ + hardware::camera2::utils::SubmitInfo *submitInfo) { + ATRACE_CALL(); + ALOGV("%s-start of function. Stream list size %zu. Surface list size %zu", __FUNCTION__, + streamIds.size(), surfaceIds.size()); + + binder::Status res = binder::Status::ok(); + status_t err; + if ( !(res = checkPidStatus(__FUNCTION__) ).isOk()) { + return res; + } + + Mutex::Autolock icl(mBinderSerializationLock); + + if (!mDevice.get()) { + return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive"); + } + + if (!mSharedMode) { + ALOGE("%s: Camera %s: Invalid operation.", __FUNCTION__, mCameraIdStr.c_str()); + return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Invalid operation"); + } + + if (streamIds.empty() || surfaceIds.empty()) { + ALOGE("%s: Camera %s: Sent empty streamIds or surface Ids. Rejecting request.", + __FUNCTION__, mCameraIdStr.c_str()); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Empty Stream or surface Ids"); + } + + if (streamIds.size() != surfaceIds.size()) { + ALOGE("%s: Camera %s: Sent different size array for stream and surface Ids.", + __FUNCTION__, mCameraIdStr.c_str()); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, + "Stream and surface Ids are not of same size"); + } + + submitInfo->mRequestId = mRequestIdCounter; + SurfaceMap surfaceMap; + Vector<int32_t> outputStreamIds; + for (size_t i = 0; i < streamIds.size(); i++) { + int streamId = streamIds[i]; + int surfaceIdx = surfaceIds[i]; + + ssize_t index = mConfiguredOutputs.indexOfKey(streamId); + if (index < 0) { + ALOGE("%s: Camera %s: Tried to start streaming with a surface that" + " we have not called createStream on: stream %d", + __FUNCTION__, mCameraIdStr.c_str(), streamId); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, + "Start streaming targets Surface that is not part of current capture session"); + } + + const auto& surfaces = mConfiguredOutputs.valueAt(index).getGraphicBufferProducers(); + if ((size_t)surfaceIdx >= surfaces.size()) { + ALOGE("%s: Camera %s: Tried to start streaming with a surface that" + " we have not called createStream on: stream %d, surfaceIdx %d", + __FUNCTION__, mCameraIdStr.c_str(), streamId, surfaceIdx); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, + "Start streaming targets Surface has invalid surface index"); + } + + res = insertGbpLocked(surfaces[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr); + + if (!res.isOk()) { + return res; + } + } + + mRequestIdCounter++; + int sharedReqID; + + err = mDevice->startStreaming(submitInfo->mRequestId, surfaceMap, &sharedReqID, + &(submitInfo->mLastFrameNumber)); + if (err != OK) { + std::string msg = fmt::sprintf( + "Camera %s: Got error %s (%d) after trying to start streaming request", + mCameraIdStr.c_str(), strerror(-err), err); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); + return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str()); + } else { + Mutex::Autolock idLock(mStreamingRequestIdLock); + mStreamingRequestId = submitInfo->mRequestId; + mSharedStreamingRequest = {sharedReqID, submitInfo->mRequestId}; + } + + markClientActive(); + ALOGV("%s: Camera %s: End of function", __FUNCTION__, mCameraIdStr.c_str()); + return binder::Status::ok(); +} + binder::Status CameraDeviceClient::submitRequestList( const std::vector<hardware::camera2::CaptureRequest>& requests, bool streaming, @@ -294,6 +401,12 @@ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Empty request list"); } + if (mSharedMode && !mIsPrimaryClient) { + ALOGE("%s: Camera %s: This client is not a primary client of the shared camera device.", + __FUNCTION__, mCameraIdStr.c_str()); + return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Invalid Operation."); + } + List<const CameraDeviceBase::PhysicalCameraSettingsList> metadataRequestList; std::list<SurfaceMap> surfaceMapList; submitInfo->mRequestId = mRequestIdCounter; @@ -564,9 +677,16 @@ } mRequestIdCounter++; + int32_t sharedReqID; if (streaming) { - err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList, - &(submitInfo->mLastFrameNumber)); + if (mSharedMode) { + err = mDevice->setSharedStreamingRequest(*metadataRequestList.begin(), + *surfaceMapList.begin(), &sharedReqID, &(submitInfo->mLastFrameNumber)); + } else { + err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList, + &(submitInfo->mLastFrameNumber)); + } + if (err != OK) { std::string msg = fmt::sprintf( "Camera %s: Got error %s (%d) after trying to set streaming request", @@ -577,10 +697,19 @@ } else { Mutex::Autolock idLock(mStreamingRequestIdLock); mStreamingRequestId = submitInfo->mRequestId; + if (mSharedMode) { + mSharedStreamingRequest = {sharedReqID, submitInfo->mRequestId}; + markClientActive(); + } } } else { - err = mDevice->captureList(metadataRequestList, surfaceMapList, - &(submitInfo->mLastFrameNumber)); + if (mSharedMode) { + err = mDevice->setSharedCaptureRequest(*metadataRequestList.begin(), + *surfaceMapList.begin(), &sharedReqID, &(submitInfo->mLastFrameNumber)); + } else { + err = mDevice->captureList(metadataRequestList, surfaceMapList, + &(submitInfo->mLastFrameNumber)); + } if (err != OK) { std::string msg = fmt::sprintf( "Camera %s: Got error %s (%d) after trying to submit capture request", @@ -589,6 +718,10 @@ res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str()); } + if (mSharedMode) { + mSharedRequestMap[sharedReqID] = submitInfo->mRequestId; + markClientActive(); + } ALOGV("%s: requestId = %d ", __FUNCTION__, submitInfo->mRequestId); } @@ -622,12 +755,19 @@ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str()); } - err = mDevice->clearStreamingRequest(lastFrameNumber); + if (mSharedMode) { + err = mDevice->clearSharedStreamingRequest(lastFrameNumber); + } else { + err = mDevice->clearStreamingRequest(lastFrameNumber); + } if (err == OK) { ALOGV("%s: Camera %s: Successfully cleared streaming request", __FUNCTION__, mCameraIdStr.c_str()); mStreamingRequestId = REQUEST_ID_NONE; + if (mSharedMode) { + mStreamingRequestLastFrameNumber = *lastFrameNumber; + } } else { res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION, "Camera %s: Error clearing streaming request: %s (%d)", @@ -638,9 +778,17 @@ } binder::Status CameraDeviceClient::beginConfigure() { - // TODO: Implement this. ATRACE_CALL(); - ALOGV("%s: Not implemented yet.", __FUNCTION__); + if (!mDevice.get()) { + return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive"); + } + status_t res = mDevice->beginConfigure(); + if (res != OK) { + std::string msg = fmt::sprintf("Camera %s: Error beginning stream configuration: %s (%d)", + mCameraIdStr.c_str(), strerror(-res), res); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); + return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str()); + } return binder::Status::ok(); } @@ -673,6 +821,12 @@ return res; } + if (mSharedMode) { + // For shared camera session, streams are already configured + // earlier, hence no need to do it here. + return res; + } + status_t err = mDevice->configureStreams(sessionParams, operatingMode); if (err == BAD_VALUE) { std::string msg = fmt::sprintf("Camera %s: Unsupported set of inputs/outputs provided", @@ -796,6 +950,7 @@ bool isInput = false; std::vector<sp<IBinder>> surfaces; + std::vector<size_t> removedSurfaceIds; ssize_t dIndex = NAME_NOT_FOUND; ssize_t compositeIndex = NAME_NOT_FOUND; @@ -806,6 +961,9 @@ for (size_t i = 0; i < mStreamMap.size(); ++i) { if (streamId == mStreamMap.valueAt(i).streamId()) { surfaces.push_back(mStreamMap.keyAt(i)); + if (mSharedMode) { + removedSurfaceIds.push_back(mStreamMap.valueAt(i).surfaceId()); + } } } @@ -833,8 +991,14 @@ } } - // Also returns BAD_VALUE if stream ID was not valid - status_t err = mDevice->deleteStream(streamId); + + status_t err; + if (mSharedMode) { + err = mDevice->removeSharedSurfaces(streamId, removedSurfaceIds); + } else { + // Also returns BAD_VALUE if stream ID was not valid + err = mDevice->deleteStream(streamId); + } if (err != OK) { std::string msg = fmt::sprintf("Camera %s: Unexpected error %s (%d) when deleting stream " @@ -929,6 +1093,7 @@ std::vector<sp<Surface>> surfaces; std::vector<sp<IBinder>> binders; + std::vector<OutputStreamInfo> streamInfos; status_t err; // Create stream for deferred surface case. @@ -967,51 +1132,67 @@ binders.push_back(IInterface::asBinder(bufferProducer)); surfaces.push_back(surface); + if (mSharedMode) { + streamInfos.push_back(streamInfo); + } } - // If mOverrideForPerfClass is true, do not fail createStream() for small - // JPEG sizes because existing createSurfaceFromGbp() logic will find the - // closest possible supported size. - int streamId = camera3::CAMERA3_STREAM_ID_INVALID; std::vector<int> surfaceIds; - bool isDepthCompositeStream = - camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]); - bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]); - bool isJpegRCompositeStream = - camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0]) && - !mDevice->isCompositeJpegRDisabled(); - if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) { - sp<CompositeStream> compositeStream; - if (isDepthCompositeStream) { - compositeStream = new camera3::DepthCompositeStream(mDevice, getRemoteCallback()); - } else if (isHeicCompositeStream) { - compositeStream = new camera3::HeicCompositeStream(mDevice, getRemoteCallback()); - } else { - compositeStream = new camera3::JpegRCompositeStream(mDevice, getRemoteCallback()); + if (mSharedMode) { + std::vector<int> streamIds; + err = mDevice->getSharedStreamIds(streamInfo, streamIds); + if (err == OK) { + for (auto id: streamIds) { + if (!mStreamInfoMap.contains(id)) { + streamId = id; + break; + } + } + if (streamId == camera3::CAMERA3_STREAM_ID_INVALID) { + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, + "OutputConfiguration isn't valid!"); + } + err = mDevice->addSharedSurfaces(streamId, streamInfos, surfaces, &surfaceIds); } - - err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width, + } else { + bool isDepthCompositeStream = + camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]); + bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]); + bool isJpegRCompositeStream = + camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0]) && + !mDevice->isCompositeJpegRDisabled(); + if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) { + sp<CompositeStream> compositeStream; + if (isDepthCompositeStream) { + compositeStream = new camera3::DepthCompositeStream(mDevice, getRemoteCallback()); + } else if (isHeicCompositeStream) { + compositeStream = new camera3::HeicCompositeStream(mDevice, getRemoteCallback()); + } else { + compositeStream = new camera3::JpegRCompositeStream(mDevice, getRemoteCallback()); + } + err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width, streamInfo.height, streamInfo.format, static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()), &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds, outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution, streamInfo.colorSpace, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase, useReadoutTimestamp); - if (err == OK) { - Mutex::Autolock l(mCompositeLock); - mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()), - compositeStream); + if (err == OK) { + Mutex::Autolock l(mCompositeLock); + mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()), + compositeStream); + } + } else { + err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width, + streamInfo.height, streamInfo.format, streamInfo.dataSpace, + static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()), + &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds, + outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution, + /*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase, + streamInfo.timestampBase, streamInfo.mirrorMode, streamInfo.colorSpace, + useReadoutTimestamp); } - } else { - err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width, - streamInfo.height, streamInfo.format, streamInfo.dataSpace, - static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()), - &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds, - outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution, - /*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase, - streamInfo.timestampBase, streamInfo.mirrorMode, streamInfo.colorSpace, - useReadoutTimestamp); } if (err != OK) { @@ -1521,6 +1702,10 @@ "Camera %s: Error flushing device: %s (%d)", mCameraIdStr.c_str(), strerror(-err), err); } + if (mSharedMode) { + mSharedRequestMap.clear(); + mStreamingRequestLastFrameNumber = *lastFrameNumber; + } return res; } @@ -1805,6 +1990,17 @@ return binder::Status::ok(); } +binder::Status CameraDeviceClient::isPrimaryClient(/*out*/bool* isPrimary) { + ATRACE_CALL(); + binder::Status res = binder::Status::ok(); + if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res; + if (isPrimary != nullptr) { + status_t ret = BasicClient::isPrimaryClient(isPrimary); + return binder::Status::fromStatusT(ret); + } + return res; +} + status_t CameraDeviceClient::setCameraServiceWatchdog(bool enabled) { return mDevice->setCameraServiceWatchdog(enabled); } @@ -1937,7 +2133,7 @@ offlineClient = new CameraOfflineSessionClient(sCameraService, offlineSession, offlineCompositeStreamMap, cameraCb, mAttributionAndPermissionUtils, mClientPackageName, mClientFeatureId, mCameraIdStr, mCameraFacing, mOrientation, - mClientPid, mClientUid, mServicePid); + mClientPid, mClientUid, mServicePid, /*sharedMode*/false); ret = sCameraService->addOfflineClient(mCameraIdStr, offlineClient); } @@ -2047,8 +2243,26 @@ const CaptureResultExtras& resultExtras) { // Thread safe. Don't bother locking. sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback(); - bool skipClientNotification = false; + if (mSharedMode && (resultExtras.requestId != -1)) { + int clientReqId; + bool matchStreamingRequest = matchSharedStreamingRequest(resultExtras.requestId); + bool matchCaptureRequest = matchSharedCaptureRequest(resultExtras.requestId); + if (matchStreamingRequest) { + clientReqId = mSharedStreamingRequest.second; + } else if (matchCaptureRequest) { + clientReqId = mSharedRequestMap[resultExtras.requestId]; + mSharedRequestMap.erase(resultExtras.requestId); + } else { + return; + } + CaptureResultExtras mutableResultExtras = resultExtras; + mutableResultExtras.requestId = clientReqId; + if (remoteCb != 0) { + remoteCb->onDeviceError(errorCode, mutableResultExtras); + } + return; + } { // Access to the composite stream map must be synchronized Mutex::Autolock l(mCompositeLock); @@ -2111,10 +2325,30 @@ nsecs_t timestamp) { // Thread safe. Don't bother locking. sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback(); - if (remoteCb != 0) { - remoteCb->onCaptureStarted(resultExtras, timestamp); + CaptureResultExtras mutableResultExtras = resultExtras; + if (mSharedMode) { + int clientReqId; + bool matchStreamingRequest = matchSharedStreamingRequest(resultExtras.requestId); + bool matchCaptureRequest = matchSharedCaptureRequest(resultExtras.requestId); + if (matchStreamingRequest) { + clientReqId = mSharedStreamingRequest.second; + } else if (matchCaptureRequest) { + clientReqId = mSharedRequestMap[resultExtras.requestId]; + } else { + return; + } + mutableResultExtras.requestId = clientReqId; } - Camera2ClientBase::notifyShutter(resultExtras, timestamp); + + if (remoteCb != 0) { + remoteCb->onCaptureStarted(mutableResultExtras, timestamp); + } + Camera2ClientBase::notifyShutter(mutableResultExtras, timestamp); + if (mSharedMode) { + // When camera is opened in shared mode, composite streams are not + // supported. + return; + } // Access to the composite stream map must be synchronized Mutex::Autolock l(mCompositeLock); @@ -2140,46 +2374,79 @@ } } +void CameraDeviceClient::notifyClientSharedAccessPriorityChanged(bool primaryClient) { + // Thread safe. Don't bother locking. + sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback(); + if (remoteCb != 0) { + remoteCb->onClientSharedAccessPriorityChanged(primaryClient); + } +} + void CameraDeviceClient::detachDevice() { if (mDevice == 0) return; nsecs_t startTime = systemTime(); - ALOGV("Camera %s: Stopping processors", mCameraIdStr.c_str()); - if (mFrameProcessor.get() != nullptr) { - mFrameProcessor->removeListener( - camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID, - camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID, /*listener*/this); - mFrameProcessor->requestExit(); - ALOGV("Camera %s: Waiting for threads", mCameraIdStr.c_str()); - mFrameProcessor->join(); - ALOGV("Camera %s: Disconnecting device", mCameraIdStr.c_str()); + mFrameProcessor->removeListener( + camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID, + camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MAX_ID, /*listener*/this); } - // WORKAROUND: HAL refuses to disconnect while there's streams in flight - { - int64_t lastFrameNumber; - status_t code; - if ((code = mDevice->flush(&lastFrameNumber)) != OK) { - ALOGE("%s: flush failed with code 0x%x", __FUNCTION__, code); - } - - if ((code = mDevice->waitUntilDrained()) != OK) { - ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, - code); - } - } - - { - Mutex::Autolock l(mCompositeLock); - for (size_t i = 0; i < mCompositeStreamMap.size(); i++) { - auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams(); - if (ret != OK) { - ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__, - strerror(-ret), ret); + if (mSharedMode) { + for (auto streamInfo : mStreamInfoMap) { + int streamToDelete = streamInfo.first; + std::vector<size_t> removedSurfaceIds; + for (size_t i = 0; i < mStreamMap.size(); ++i) { + if (streamToDelete == mStreamMap.valueAt(i).streamId()) { + removedSurfaceIds.push_back(mStreamMap.valueAt(i).surfaceId()); + } + } + status_t err = mDevice->removeSharedSurfaces(streamToDelete, removedSurfaceIds); + if (err != OK) { + std::string msg = fmt::sprintf("Camera %s: Unexpected error %s (%d) when removing" + "shared surfaces from stream %d", mCameraIdStr.c_str(), strerror(-err), + err, streamToDelete); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); } } - mCompositeStreamMap.clear(); + } + + if (!mSharedMode || + (mSharedMode && sCameraService->isOnlyClient(this))){ + ALOGV("Camera %s: Stopping processors", mCameraIdStr.c_str()); + + if (mFrameProcessor.get() != nullptr) { + mFrameProcessor->requestExit(); + ALOGV("Camera %s: Waiting for threads", mCameraIdStr.c_str()); + mFrameProcessor->join(); + ALOGV("Camera %s: Disconnecting device", mCameraIdStr.c_str()); + } + + // WORKAROUND: HAL refuses to disconnect while there's streams in flight + { + int64_t lastFrameNumber; + status_t code; + if ((code = mDevice->flush(&lastFrameNumber)) != OK) { + ALOGE("%s: flush failed with code 0x%x", __FUNCTION__, code); + } + + if ((code = mDevice->waitUntilDrained()) != OK) { + ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, + code); + } + } + + { + Mutex::Autolock l(mCompositeLock); + for (size_t i = 0; i < mCompositeStreamMap.size(); i++) { + auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams(); + if (ret != OK) { + ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__, + strerror(-ret), ret); + } + } + mCompositeStreamMap.clear(); + } } bool hasDeviceError = mDevice->hasDeviceError(); @@ -2189,25 +2456,121 @@ mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError); } -/** Device-related methods */ +bool CameraDeviceClient::matchSharedStreamingRequest(int reqId) { + if (!mSharedMode) { + return false; + } + // In shared mode, check if the result req id matches the streaming request + // sent by client. + if (reqId == mSharedStreamingRequest.first) { + return true; + } + return false; +} + +bool CameraDeviceClient::matchSharedCaptureRequest(int reqId) { + if (!mSharedMode) { + return false; + } + // In shared mode, only primary clients can send the capture request. If the + // result req id does not match the streaming request id, check against the + // capture request ids sent by the primary client. + if (mIsPrimaryClient) { + auto iter = mSharedRequestMap.find(reqId); + if (iter != mSharedRequestMap.end()) { + return true; + } + } + return false; +} + void CameraDeviceClient::onResultAvailable(const CaptureResult& result) { ATRACE_CALL(); - ALOGV("%s", __FUNCTION__); + ALOGV("%s E", __FUNCTION__); + CaptureResult mutableResult = result; + bool matchStreamingRequest, matchCaptureRequest, sharedStreamingLastFrame; + if (mSharedMode) { + int clientReqId; + matchStreamingRequest = matchSharedStreamingRequest(result.mResultExtras.requestId); + matchCaptureRequest = matchSharedCaptureRequest(result.mResultExtras.requestId); + if (matchStreamingRequest) { + clientReqId = mSharedStreamingRequest.second; + // When a client stops streaming using cancelRequest, we still need to deliver couple + // more capture results to the client, till the lastframe number returned by the + // cancelRequest. Therefore, only clean the shared streaming request once all the frames for + // the repeating request have been delivered to the client. + sharedStreamingLastFrame = (mStreamingRequestId == REQUEST_ID_NONE) + && (result.mResultExtras.frameNumber >= mStreamingRequestLastFrameNumber); + if (sharedStreamingLastFrame) { + mSharedStreamingRequest.first = REQUEST_ID_NONE; + mSharedStreamingRequest.second = REQUEST_ID_NONE; + } + } else if (matchCaptureRequest) { + clientReqId = mSharedRequestMap[result.mResultExtras.requestId]; + mSharedRequestMap.erase(result.mResultExtras.requestId); + } else { + return; + } + mutableResult.mResultExtras.requestId = clientReqId; + if (mutableResult.mMetadata.update(ANDROID_REQUEST_ID, &clientReqId, 1) != OK) { + ALOGE("%s Failed to set request ID in metadata.", __FUNCTION__); + return; + } + } // Thread-safe. No lock necessary. sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = mRemoteCallback; if (remoteCb != NULL) { - remoteCb->onResultReceived(result.mMetadata, result.mResultExtras, - result.mPhysicalMetadatas); + remoteCb->onResultReceived(mutableResult.mMetadata, mutableResult.mResultExtras, + mutableResult.mPhysicalMetadatas); + if (mSharedMode) { + // If all the capture requests for this client has been processed, + // send onDeviceidle callback. + if ((mSharedStreamingRequest.first == REQUEST_ID_NONE) && mSharedRequestMap.empty() ) { + markClientIdle(); + } + } } // Access to the composite stream map must be synchronized Mutex::Autolock l(mCompositeLock); for (size_t i = 0; i < mCompositeStreamMap.size(); i++) { - mCompositeStreamMap.valueAt(i)->onResultAvailable(result); + mCompositeStreamMap.valueAt(i)->onResultAvailable(mutableResult); } } +void CameraDeviceClient::markClientActive() { + Mutex::Autolock l(mDevice->mSharedDeviceActiveLock); + if (mDeviceActive) { + // Already in active state. + return; + } + status_t res = startCameraStreamingOps(); + if (res != OK) { + ALOGE("%s: Camera %s: Error starting camera streaming ops: %d", __FUNCTION__, + mCameraIdStr.c_str(), res); + } + mDeviceActive = true; +} + +void CameraDeviceClient::markClientIdle() { + Mutex::Autolock l(mDevice->mSharedDeviceActiveLock); + if (!mDeviceActive) { + // Already in idle state. + return; + } + sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = mRemoteCallback; + if (remoteCb != NULL) { + remoteCb->onDeviceIdle(); + } + status_t res = finishCameraStreamingOps(); + if (res != OK) { + ALOGE("%s: Camera %s: Error finishing streaming ops: %d", __FUNCTION__, + mCameraIdStr.c_str(), res); + } + mDeviceActive = false; +} + binder::Status CameraDeviceClient::checkPidStatus(const char* checkLocation) { if (mDisconnected) { return STATUS_ERROR(CameraService::ERROR_DISCONNECTED,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 42f2752..a92b465 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -61,7 +61,8 @@ int clientPid, uid_t clientUid, int servicePid, - int rotationOverride); + int rotationOverride, + bool sharedMode); sp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback; }; @@ -95,6 +96,11 @@ virtual binder::Status cancelRequest(int requestId, /*out*/ int64_t* lastFrameNumber = NULL) override; + virtual binder::Status startStreaming( + const std::vector<int>& streamIds, + const std::vector<int>& surfaceIds, + /*out*/ + hardware::camera2::utils::SubmitInfo *submitInfo = nullptr) override; virtual binder::Status beginConfigure() override; @@ -175,6 +181,8 @@ /*out*/ sp<hardware::camera2::ICameraOfflineSession>* session) override; + virtual binder::Status isPrimaryClient(/*out*/bool* isPrimary) override; + /** * Interface used by CameraService */ @@ -194,7 +202,8 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, - const std::string& originalCameraId); + const std::string& originalCameraId, + bool sharedMode); virtual ~CameraDeviceClient(); virtual status_t initialize(sp<CameraProviderManager> manager, @@ -237,6 +246,7 @@ virtual void notifyPrepared(int streamId); virtual void notifyRequestQueueEmpty(); virtual void notifyRepeatingRequestError(long lastFrameNumber); + virtual void notifyClientSharedAccessPriorityChanged(bool primaryClient); void setImageDumpMask(int mask) { if (mDevice != nullptr) mDevice->setImageDumpMask(mask); } /** @@ -315,6 +325,11 @@ /*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds, /*out*/int32_t* currentStreamId); + bool matchSharedStreamingRequest(int reqId); + bool matchSharedCaptureRequest(int reqId); + void markClientActive(); + void markClientIdle(); + // IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap; @@ -336,6 +351,9 @@ // Streaming request ID int32_t mStreamingRequestId; Mutex mStreamingRequestIdLock; + std::pair<int32_t, int32_t> mSharedStreamingRequest; + std::map<int32_t, int32_t> mSharedRequestMap; + int64_t mStreamingRequestLastFrameNumber; static const int32_t REQUEST_ID_NONE = -1; int32_t mRequestIdCounter;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp index 9a1fdd6..9f85594 100644 --- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp +++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -307,6 +307,9 @@ } } +void CameraOfflineSessionClient::notifyClientSharedAccessPriorityChanged(bool /*primaryClient*/) { +} + void CameraOfflineSessionClient::notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h index 77de874..9f441f3 100644 --- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h +++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -52,7 +52,7 @@ const std::string& clientPackageName, const std::optional<std::string>& clientFeatureId, const std::string& cameraIdStr, int cameraFacing, int sensorOrientation, - int clientPid, uid_t clientUid, int servicePid) : + int clientPid, uid_t clientUid, int servicePid, bool sharedMode) : CameraService::BasicClient( cameraService, IInterface::asBinder(remoteCallback), @@ -60,7 +60,7 @@ // (v)ndk doesn't have offline session support clientPackageName, /*overridePackageName*/false, clientFeatureId, cameraIdStr, cameraFacing, sensorOrientation, clientPid, clientUid, servicePid, - hardware::ICameraService::ROTATION_OVERRIDE_NONE), + hardware::ICameraService::ROTATION_OVERRIDE_NONE, sharedMode), mRemoteCallback(remoteCallback), mOfflineSession(session), mCompositeStreamMap(offlineCompositeStreamMap) {} @@ -123,6 +123,7 @@ void notifyRepeatingRequestError(long lastFrameNumber) override; status_t injectCamera(const std::string& injectedCamId, sp<CameraProviderManager> manager) override; + void notifyClientSharedAccessPriorityChanged(bool primaryClient) override; status_t stopInjection() override; status_t injectSessionParams( const hardware::camera2::impl::CameraMetadataNative& sessionParams) override;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index 352c6f8..ef0c387 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -31,6 +31,7 @@ #include <camera/CameraSessionStats.h> #include <camera/StringUtils.h> #include <com_android_window_flags.h> +#include <com_android_internal_camera_flags.h> #include "common/Camera2ClientBase.h" @@ -39,12 +40,14 @@ #include "device3/Camera3Device.h" #include "device3/aidl/AidlCamera3Device.h" #include "device3/hidl/HidlCamera3Device.h" +#include "device3/aidl/AidlCamera3SharedDevice.h" namespace android { using namespace camera2; namespace wm_flags = com::android::window::flags; +namespace flags = com::android::internal::camera::flags; // Interface used by CameraService @@ -66,10 +69,11 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, + bool sharedMode, bool legacyClient): TClientBase(cameraService, remoteCallback, attributionAndPermissionUtils, clientPackageName, systemNativeClient, clientFeatureId, cameraId, api1CameraId, cameraFacing, - sensorOrientation, clientPid, clientUid, servicePid, rotationOverride), + sensorOrientation, clientPid, clientUid, servicePid, rotationOverride, sharedMode), mSharedCameraCallbacks(remoteCallback), mCameraServiceProxyWrapper(cameraServiceProxyWrapper), mDeviceActive(false), mApi1CameraId(api1CameraId) @@ -124,12 +128,19 @@ TClientBase::mRotationOverride, mLegacyClient); break; case IPCTransport::AIDL: - mDevice = + if (TClientBase::mSharedMode) { + mDevice = AidlCamera3SharedDevice::getInstance(mCameraServiceProxyWrapper, + TClientBase::mAttributionAndPermissionUtils, + TClientBase::mCameraIdStr, mOverrideForPerfClass, + TClientBase::mRotationOverride, mLegacyClient); + } else { + mDevice = new AidlCamera3Device(mCameraServiceProxyWrapper, TClientBase::mAttributionAndPermissionUtils, TClientBase::mCameraIdStr, mOverrideForPerfClass, TClientBase::mRotationOverride, mLegacyClient); - break; + } + break; default: ALOGE("%s Invalid transport for camera id %s", __FUNCTION__, TClientBase::mCameraIdStr.c_str()); @@ -171,9 +182,10 @@ Camera2ClientBase<TClientBase>::~Camera2ClientBase() { ATRACE_CALL(); - TClientBase::mDestructionStarted = true; - - disconnect(); + if (!TClientBase::mDisconnected) { + TClientBase::mDestructionStarted = true; + disconnect(); + } ALOGI("%s: Client object's dtor for Camera Id %s completed. Client was: %s (PID %d, UID %u)", __FUNCTION__, TClientBase::mCameraIdStr.c_str(), @@ -261,7 +273,10 @@ template <typename TClientBase> binder::Status Camera2ClientBase<TClientBase>::disconnect() { - return disconnectImpl(); + if ( !TClientBase::mDisconnected) { + return disconnectImpl(); + } + return binder::Status::ok(); } template <typename TClientBase> @@ -299,7 +314,11 @@ template <typename TClientBase> void Camera2ClientBase<TClientBase>::detachDevice() { if (mDevice == 0) return; - mDevice->disconnect(); + if (TClientBase::mSharedMode) { + mDevice->disconnectClient(TClientBase::getClientPid()); + } else { + mDevice->disconnect(); + } ALOGV("Camera %s: Detach complete", TClientBase::mCameraIdStr.c_str()); } @@ -342,6 +361,12 @@ } template <typename TClientBase> +void Camera2ClientBase<TClientBase>::notifyClientSharedAccessPriorityChanged(bool primaryClient) { + ALOGV("%s Camera %s access priorities changed for client %d primaryClient=%d", __FUNCTION__, + TClientBase::mCameraIdStr.c_str(), TClientBase::getClientUid(), primaryClient); +} + +template <typename TClientBase> void Camera2ClientBase<TClientBase>::notifyPhysicalCameraChange(const std::string &physicalId) { using android::hardware::ICameraService; // We're only interested in this notification if rotationOverride is turned on.
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h index c9d5735..a825754 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.h +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -65,6 +65,7 @@ int servicePid, bool overrideForPerfClass, int rotationOverride, + bool sharedMode, bool legacyClient = false); virtual ~Camera2ClientBase(); @@ -97,6 +98,7 @@ virtual void notifyPrepared(int streamId); virtual void notifyRequestQueueEmpty(); virtual void notifyRepeatingRequestError(long lastFrameNumber); + virtual void notifyClientSharedAccessPriorityChanged(bool primaryClient) override; void notifyIdleWithUserTag(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index 9c8f5ad..9b76426 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -34,6 +34,7 @@ #include "device3/Camera3StreamInterface.h" #include "device3/StatusTracker.h" #include "binder/Status.h" +#include "FrameProcessorBase.h" #include "FrameProducer.h" #include "utils/IPCTransport.h" #include "utils/SessionConfigurationUtils.h" @@ -92,6 +93,7 @@ virtual status_t initialize(sp<CameraProviderManager> manager, const std::string& monitorTags) = 0; virtual status_t disconnect() = 0; + virtual status_t disconnectClient(int) {return OK;}; virtual status_t dump(int fd, const Vector<String16> &args) = 0; virtual status_t startWatchingTags(const std::string &tags) = 0; @@ -286,6 +288,75 @@ */ virtual status_t deleteStream(int id) = 0; + + /** + * This function is responsible for configuring camera streams at the start of a session. + * In shared session mode, where multiple clients may access the camera, camera service + * applies a predetermined shared session configuration. If the camera is opened in non-shared + * mode, this function is a no-op. + */ + virtual status_t beginConfigure() = 0; + + /** + * In shared session mode, this function retrieves the stream IDs associated with a specific + * output configuration. + */ + virtual status_t getSharedStreamIds(const android::camera3::OutputStreamInfo &config, + std::vector<int>& streamIds) = 0; + + /** + * In shared session mode, this function add surfaces to an existing shared stream ID. + */ + virtual status_t addSharedSurfaces(int streamId, + const std::vector<android::camera3::OutputStreamInfo> &outputInfo, + const std::vector<sp<Surface>>& surfaces, std::vector<int> *surfaceIds = nullptr) = 0; + + /** + * In shared session mode, this function remove surfaces from an existing shared stream ID. + */ + virtual status_t removeSharedSurfaces(int streamId, const std::vector<size_t> &surfaceIds) = 0; + + /** + * In shared session mode, this function retrieves the frame processor. + */ + virtual sp<camera2::FrameProcessorBase> getSharedFrameProcessor() = 0; + + /** + * Submit a shared streaming request for streaming. + * Output lastFrameNumber is the last frame number of the previous streaming request. + */ + virtual status_t setSharedStreamingRequest( + const PhysicalCameraSettingsList &request, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, + int64_t *lastFrameNumber = NULL) = 0; + + /** + * Clear the shared streaming request slot. + * Output lastFrameNumber is the last frame number of the previous streaming request. + */ + virtual status_t clearSharedStreamingRequest(int64_t *lastFrameNumber = NULL) = 0; + + /** + * In shared session mode, only primary clients can change the capture + * parameters through capture request or repeating request. When the primary + * client sends the capture request to the camera device, the request ID is + * overridden by the camera device to maintain unique ID. This API is + * similar to captureList API, with only difference that the request ID is + * changed by the device before submitting the request to HAL. + * Output sharedReqID is the request ID actually used. + * Output lastFrameNumber is the expected last frame number of the list of requests. + */ + virtual status_t setSharedCaptureRequest(const PhysicalCameraSettingsList &request, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, + int64_t *lastFrameNumber = NULL) = 0; + + /** + * Submit a start streaming request. + * Output lastFrameNumber is the last frame number of the previous streaming request. + */ + virtual status_t startStreaming(const int32_t reqId, const SurfaceMap &surfaceMap, + int32_t *sharedReqID, int64_t *lastFrameNumber = NULL) = 0; + /** * Take the currently-defined set of streams and configure the HAL to use * them. This is a long-running operation (may be several hundered ms). @@ -519,6 +590,9 @@ virtual status_t injectSessionParams( const CameraMetadata& sessionParams) = 0; + // Lock to synchronize onDeviceActive and onDeviceIdle callbacks when camera + // has been opened in shared mode. + mutable Mutex mSharedDeviceActiveLock; protected: bool mImageDumpMask = 0; std::vector<int64_t> mStreamUseCaseOverrides;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 51f06cb..54a7ec9 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -22,6 +22,8 @@ #include "CameraProviderManager.h" +#include "config/SharedSessionConfigReader.h" + #include <aidl/android/hardware/camera/device/ICameraDevice.h> #include <algorithm> @@ -62,6 +64,7 @@ using namespace camera3::SessionConfigurationUtils; using std::literals::chrono_literals::operator""s; using hardware::camera2::utils::CameraIdAndSessionConfiguration; +using hardware::camera2::params::OutputConfiguration; namespace flags = com::android::internal::camera::flags; namespace vd_flags = android::companion::virtualdevice::flags; @@ -1853,6 +1856,84 @@ return res; } +bool CameraProviderManager::ProviderInfo::DeviceInfo3::isAutomotiveDevice() { + // Checks the property ro.hardware.type and returns true if it is + // automotive. + char value[PROPERTY_VALUE_MAX] = {0}; + property_get("ro.hardware.type", value, ""); + return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0; +} + +status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addSharedSessionConfigurationTags( + const std::string &cameraId) { + status_t res = OK; + { + SharedSessionConfigReader configReader; + ErrorCode status = + configReader.parseSharedSessionConfig( + (std::string(SHARED_SESSION_FILE_PATH) + + std::string(SHARED_SESSION_FILE_NAME)).c_str()); + if (status != 0) { + ALOGE("%s: failed to initialize SharedSessionConfigReader with ErrorCode %s", + __FUNCTION__, SharedSessionConfigUtils::toString(status)); + return BAD_VALUE; + } + const int32_t sharedColorSpaceTag = ANDROID_SHARED_SESSION_COLOR_SPACE; + const int32_t sharedOutputConfigurationsTag = ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS; + auto& c = mCameraCharacteristics; + int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED; + + status = configReader.getColorSpace(&colorSpace); + if (status != 0) { + ALOGE("%s: failed to get color space from config reader with ErrorCode %s", + __FUNCTION__, SharedSessionConfigUtils::toString(status)); + return BAD_VALUE; + } + + res = c.update(sharedColorSpaceTag, &colorSpace, 1); + if (res != OK) { + ALOGE("%s: failed to update sharedColorSpaceTag with error %d", __FUNCTION__, res); + return res; + } + + std::vector<SharedSessionConfigReader::SharedSessionConfig> outputConfigurations; + status = configReader.getAvailableSharedSessionConfigs(cameraId.c_str(), + &outputConfigurations); + if (status != 0) { + ALOGE("%s: failed to get output configurations from config reader with ErrorCode %s", + __FUNCTION__, SharedSessionConfigUtils::toString(status)); + return BAD_VALUE; + } + + std::vector<int64_t> sharedOutputConfigEntries; + + for (auto outputConfig : outputConfigurations) { + sharedOutputConfigEntries.push_back(outputConfig.surfaceType); + sharedOutputConfigEntries.push_back(outputConfig.width); + sharedOutputConfigEntries.push_back(outputConfig.height); + sharedOutputConfigEntries.push_back(outputConfig.format); + sharedOutputConfigEntries.push_back(outputConfig.mirrorMode); + sharedOutputConfigEntries.push_back(outputConfig.useReadoutTimestamp); + sharedOutputConfigEntries.push_back(outputConfig.timestampBase); + sharedOutputConfigEntries.push_back(outputConfig.dataSpace); + sharedOutputConfigEntries.push_back(outputConfig.usage); + sharedOutputConfigEntries.push_back(outputConfig.streamUseCase); + if (strcmp(outputConfig.physicalCameraId.c_str(), "")) { + sharedOutputConfigEntries.push_back(outputConfig.physicalCameraId.length()); + for (char c : outputConfig.physicalCameraId) { + sharedOutputConfigEntries.push_back(c); + } + } else { + sharedOutputConfigEntries.push_back(/* physical camera id len */ 0); + } + } + + res = c.update(sharedOutputConfigurationsTag, sharedOutputConfigEntries.data(), + sharedOutputConfigEntries.size()); + } + return res; +} + status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys( CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) { status_t res = OK;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h index b686a58..3092d58 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.h +++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -44,6 +44,8 @@ #include <binder/IServiceManager.h> #include <camera/VendorTagDescriptor.h> +#include "config/SharedSessionConfigUtils.h" + namespace android { using hardware::camera2::utils::CameraIdAndSessionConfiguration; @@ -762,6 +764,8 @@ status_t addPreCorrectionActiveArraySize(); status_t addReadoutTimestampTag(bool readoutTimestampSupported = true); status_t addSessionConfigQueryVersionTag(); + status_t addSharedSessionConfigurationTags(const std::string &cameraId); + bool isAutomotiveDevice(); static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag, android_pixel_format_t format,
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp index 4bfe11d..a51f156 100644 --- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp +++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -30,6 +30,8 @@ #include "device3/DistortionMapper.h" #include "device3/ZoomRatioMapper.h" +#include <filesystem> +#include <utils/AttributionAndPermissionUtils.h> #include <utils/SessionConfigurationUtils.h> #include <utils/Trace.h> @@ -694,6 +696,13 @@ {ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, ANDROID_CONTROL_AE_TARGET_FPS_RANGE}); } + std::filesystem::path sharedSessionConfigFilePath = + std::string(SHARED_SESSION_FILE_PATH) + std::string(SHARED_SESSION_FILE_NAME); + if (std::filesystem::exists(sharedSessionConfigFilePath) + && mSystemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) { + addSharedSessionConfigurationTags(id); + } + if (!kEnableLazyHal) { // Save HAL reference indefinitely mSavedInterface = interface;
diff --git a/services/camera/libcameraservice/config/SharedSessionConfigReader.cpp b/services/camera/libcameraservice/config/SharedSessionConfigReader.cpp new file mode 100644 index 0000000..2ea5ffa --- /dev/null +++ b/services/camera/libcameraservice/config/SharedSessionConfigReader.cpp
@@ -0,0 +1,239 @@ +// +// Copyright 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#define LOG_TAG "SharedSessionConfigReader" + +#include "SharedSessionConfigReader.h" + +#include <fstream> +#include <utils/Log.h> + +using tinyxml2::XML_SUCCESS; +using tinyxml2::XMLDocument; +namespace android { + +ErrorCode SharedSessionConfigReader::parseSharedSessionConfig( + const char* sharedSessionConfigFilePath) { + if (!mCameraIdToSharedSessionConfigs.empty()) { + ALOGV("mCameraIdToSharedSessionConfigs already initialized."); + return ErrorCode::STATUS_OK; + } + + XMLDocument xmlDoc; + + // load and parse the configuration file + xmlDoc.LoadFile(sharedSessionConfigFilePath); + if (xmlDoc.ErrorID() != XML_SUCCESS) { + ALOGE("%s: Failed to load/parse the configuration file: %s, with error: %s", __FUNCTION__, + sharedSessionConfigFilePath, xmlDoc.ErrorStr()); + return ErrorCode::ERROR_READ_CONFIG_FILE; + } + + ErrorCode status = parseSharedSessionConfigFromXMLDocument(xmlDoc); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: Error while parsing XML elements of file at: %s", __FUNCTION__, + sharedSessionConfigFilePath); + return status; + } + + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigReader::parseSharedSessionConfigFromXMLDocument( + const XMLDocument& xmlDoc) { + const XMLElement* rootElem = xmlDoc.RootElement(); + if (strcmp(rootElem->Name(), "SharedCameraSessionConfigurations")) { + ALOGE("%s: Expected root element to be 'SharedCameraSessionConfigurations'. Instead got %s", + __FUNCTION__, rootElem->Name()); + return ErrorCode::ERROR_READ_CONFIG_FILE; + } + + ErrorCode status; + const char* colorSpaceStr = rootElem->Attribute("colorSpace"); + status = SharedSessionConfigUtils::getColorSpaceFromStr(colorSpaceStr, &mColorSpace); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getColorSpaceFromStr has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + std::unordered_map<std::string, std::vector<SharedSessionConfig>> + cameraIdToSharedSessionConfigs; + + for (const XMLElement* sharedConfigElem = + rootElem->FirstChildElement("SharedCameraSessionConfiguration"); + sharedConfigElem != nullptr; + sharedConfigElem = + sharedConfigElem->NextSiblingElement("SharedCameraSessionConfiguration")) { + + const char* cameraId = sharedConfigElem->Attribute("cameraId"); + if (cameraId == nullptr || !strcmp(cameraId, "")) { + ALOGE("%s: cameraId attribute is empty", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + for (const XMLElement* outputConfigElem = + sharedConfigElem->FirstChildElement("OutputConfiguration"); + outputConfigElem != nullptr; + outputConfigElem = outputConfigElem->NextSiblingElement("OutputConfiguration")) { + int64_t surfaceType; + const XMLElement* surfaceTypeXml = outputConfigElem->FirstChildElement("surfaceType"); + status = SharedSessionConfigUtils::getSurfaceTypeFromXml(surfaceTypeXml, &surfaceType); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getSurfaceTypeFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t width; + const XMLElement* widthXml = outputConfigElem->FirstChildElement("width"); + status = SharedSessionConfigUtils::getWidthFromXml(widthXml, &width); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getWidthFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t height; + const XMLElement* heightXml = outputConfigElem->FirstChildElement("height"); + status = SharedSessionConfigUtils::getHeightFromXml(heightXml, &height); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getHeightFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + std::string physicalCameraId; + const XMLElement* physicalCameraIdXml = + outputConfigElem->FirstChildElement("physicalCameraId"); + status = SharedSessionConfigUtils::getPhysicalCameraIdFromXml(physicalCameraIdXml, + &physicalCameraId); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getPhysicalCameraIdFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t streamUseCase; + const XMLElement* streamUseCaseXml = + outputConfigElem->FirstChildElement("streamUseCase"); + status = SharedSessionConfigUtils::getStreamUseCaseFromXml(streamUseCaseXml, + &streamUseCase); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getStreamUseCaseFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t timestampBase; + const XMLElement* timestampBaseXml = + outputConfigElem->FirstChildElement("timestampBase"); + status = SharedSessionConfigUtils::getTimestampBaseFromXml(timestampBaseXml, + ×tampBase); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getTimestampBaseFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t mirrorMode; + const XMLElement* mirrorModeXml = outputConfigElem->FirstChildElement("mirrorMode"); + status = SharedSessionConfigUtils::getMirrorModeFromXml(mirrorModeXml, &mirrorMode); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getMirrorModeFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + bool useReadoutTimestamp; + const XMLElement* useReadoutTimestampXml = + outputConfigElem->FirstChildElement("useReadoutTimestamp"); + status = SharedSessionConfigUtils::getUseReadoutTimestampFromXml(useReadoutTimestampXml, + &useReadoutTimestamp); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getUseReadoutTimestampFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t format; + const XMLElement* formatXml = outputConfigElem->FirstChildElement("format"); + status = SharedSessionConfigUtils::getFormatFromXml(formatXml, &format, surfaceType); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getFormatFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t usage; + const XMLElement* usageXml = outputConfigElem->FirstChildElement("usage"); + status = SharedSessionConfigUtils::getUsageFromXml(usageXml, &usage, surfaceType); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getUsageFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + int64_t dataSpace; + const XMLElement* dataSpaceXml = outputConfigElem->FirstChildElement("dataSpace"); + status = SharedSessionConfigUtils::getDataSpaceFromXml(dataSpaceXml, &dataSpace); + if (status != ErrorCode::STATUS_OK) { + ALOGE("%s: getUsageFromXml has returned an error: %s", __FUNCTION__, + SharedSessionConfigUtils::toString(status)); + return status; + } + + cameraIdToSharedSessionConfigs[cameraId].push_back( + SharedSessionConfig{surfaceType, width, height, physicalCameraId, streamUseCase, + timestampBase, mirrorMode, useReadoutTimestamp, format, + usage, dataSpace}); + } + } + + if (cameraIdToSharedSessionConfigs.empty()) { + ALOGE("%s: No elements with tag 'SharedCameraSessionConfiguration' in file", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + mCameraIdToSharedSessionConfigs = cameraIdToSharedSessionConfigs; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigReader::getColorSpace(/* out */ int32_t* colorSpace) { + *colorSpace = mColorSpace; + return ErrorCode::STATUS_OK; +} + +// Returns the cameraConfig parameters. +ErrorCode SharedSessionConfigReader::getAvailableSharedSessionConfigs( + const char* cameraId, /* out */ std::vector<SharedSessionConfig>* availableConfigurations) { + if (mCameraIdToSharedSessionConfigs.empty()) { + ALOGE("%s: mCameraIdToSharedSessionConfigs is empty. Call initialize() first.", + __FUNCTION__); + return ErrorCode::ERROR_CONFIG_READER_UNINITIALIZED; + } + + if (!mCameraIdToSharedSessionConfigs.contains(cameraId)) { + ALOGE("%s: cameraId: %s not found in mCameraIdToSharedSessionConfigs.", __FUNCTION__, + cameraId); + return ErrorCode::ERROR_BAD_PARAMETER; + } + + *availableConfigurations = mCameraIdToSharedSessionConfigs[cameraId]; + return ErrorCode::STATUS_OK; +} + +} // namespace android
diff --git a/services/camera/libcameraservice/config/SharedSessionConfigReader.h b/services/camera/libcameraservice/config/SharedSessionConfigReader.h new file mode 100644 index 0000000..aa52236 --- /dev/null +++ b/services/camera/libcameraservice/config/SharedSessionConfigReader.h
@@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGREADER_H_ +#define ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGREADER_H_ + +#include "SharedSessionConfigUtils.h" + +#include <string> +#include "tinyxml2.h" +#include <vector> +#include <unordered_map> + +using tinyxml2::XMLDocument; +using tinyxml2::XMLElement; +namespace android { + +class SharedSessionConfigReader { +public: + + // Struct for shared session configurations. + struct SharedSessionConfig { + // TODO: add documentation for each field. + int64_t surfaceType; + int64_t width; + int64_t height; + std::string physicalCameraId; + int64_t streamUseCase; + int64_t timestampBase; + int64_t mirrorMode; + bool useReadoutTimestamp; + int64_t format; + int64_t usage; + int64_t dataSpace; + }; + + // Reads shared session config files and stores parsed results in mColorSpace and + // mCameraIdToSharedSessionConfigs. + ErrorCode parseSharedSessionConfig(const char* sharedSessionConfigFilePath); + + // Reads shared session config files and stores parsed results in mColorSpace and + // mCameraIdToSharedSessionConfigs. + ErrorCode parseSharedSessionConfigFromXMLDocument(const XMLDocument& xmlDoc); + + // Return color space of a camera device. + ErrorCode getColorSpace(int32_t* colorSpace); + + // Return all available shared configs for a cameraId. + ErrorCode getAvailableSharedSessionConfigs( + const char* cameraId, std::vector<SharedSessionConfig>* availableConfigurations); + +private: + + // shared color space of devices + int32_t mColorSpace; + + // stores parsed configs, mapped from cameraId to available session configs. + std::unordered_map<std::string, std::vector<SharedSessionConfig>> + mCameraIdToSharedSessionConfigs; + + // processes xml and populates mCameraIdToColorSpace and mCameraIdToSharedSessionConfigs. Called + // by initialize(). + ErrorCode readConfig(const XMLElement* rootElem); +}; + +} // namespace android + +#endif // ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGREADER_H_
diff --git a/services/camera/libcameraservice/config/SharedSessionConfigUtils.cpp b/services/camera/libcameraservice/config/SharedSessionConfigUtils.cpp new file mode 100644 index 0000000..a9ccdc9 --- /dev/null +++ b/services/camera/libcameraservice/config/SharedSessionConfigUtils.cpp
@@ -0,0 +1,324 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SharedSessionConfigUtils" + +#include "SharedSessionConfigUtils.h" + +#include <inttypes.h> +#include <sstream> +#include <utils/Log.h> + +namespace android { + +const char* SharedSessionConfigUtils::toString(ErrorCode errorCode) { + switch (errorCode) { + case ErrorCode::STATUS_OK: + return "STATUS_OK"; + case ErrorCode::ERROR_READ_CONFIG_FILE: + return "ERROR_READ_CONFIG_FILE"; + case ErrorCode::ERROR_CONFIG_FILE_FORMAT: + return "ERROR_CONFIG_FILE_FORMAT"; + case ErrorCode::ERROR_CONFIG_READER_UNINITIALIZED: + return "ERROR_CONFIG_READER_UNINITIALIZED"; + case ErrorCode::ERROR_BAD_PARAMETER: + return "ERROR_BAD_PARAMETER"; + default: + ALOGE("%s: Called toString on an unknown ErrorCode. This should never happen", + __FUNCTION__); + return ""; + } +} + +ErrorCode SharedSessionConfigUtils::getColorSpaceFromStr(const char* colorSpaceStr, + /* out */ int32_t* colorSpace) { + if (colorSpaceStr == nullptr || !strcmp(colorSpaceStr, "")) { + *colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED; + return ErrorCode::STATUS_OK; + } + + int32_t colorSpaceInt = (int32_t) std::strtol(colorSpaceStr, nullptr, 0); + if (VALID_COLOR_SPACES.find(colorSpaceInt) == VALID_COLOR_SPACES.end()) { + ALOGE("%s: colorSpace %" PRId32 " is invalid: ", __FUNCTION__, colorSpaceInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_COLOR_SPACES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *colorSpace = colorSpaceInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getSurfaceTypeFromXml(const XMLElement* surfaceTypeXml, + /* out */ int64_t* surfaceType) { + if (surfaceTypeXml == nullptr || surfaceTypeXml->GetText() == nullptr + || !strcmp(surfaceTypeXml->GetText(), "")) { + ALOGE("%s: surface type field must be populated", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + int64_t surfaceTypeInt = std::strtol(surfaceTypeXml->GetText(), nullptr, 0); + if (VALID_SURFACE_TYPES.find(surfaceTypeInt) == VALID_SURFACE_TYPES.end()) { + ALOGE("%s: surfaceType %" PRId64 " is invalid: ", __FUNCTION__, surfaceTypeInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_SURFACE_TYPES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *surfaceType = surfaceTypeInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getWidthFromXml(const XMLElement* widthXml, + /* out */ int64_t* width) { + if (widthXml == nullptr || widthXml->GetText() == nullptr + || !strcmp(widthXml->GetText(), "")) { + ALOGE("%s: width field must be populated", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + const char* widthStr = widthXml->GetText(); + *width = std::strtol(widthStr, nullptr, 0); + if (*width <= 0) { + ALOGE("%s: width value is invalid", __FUNCTION__); + } + + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getHeightFromXml(const XMLElement* heightXml, + /* out */ int64_t* height) { + if (heightXml == nullptr || heightXml->GetText() == nullptr + || !strcmp(heightXml->GetText(), "")) { + ALOGE("%s: height field must be populated", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + const char* heightStr = heightXml->GetText(); + *height = std::strtol(heightStr, nullptr, 0); + if (*height <= 0) { + ALOGE("%s: height value is invalid", __FUNCTION__); + } + + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getPhysicalCameraIdFromXml( + const XMLElement* physicalCameraIdXml, /* out */ std::string* physicalCameraId) { + *physicalCameraId = + (physicalCameraIdXml == nullptr || physicalCameraIdXml->GetText() == nullptr) + ? "": physicalCameraIdXml->GetText(); + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getStreamUseCaseFromXml(const XMLElement* streamUseCaseXml, + /* out */ int64_t* streamUseCase) { + if (streamUseCaseXml == nullptr || streamUseCaseXml->GetText() == nullptr + || !strcmp(streamUseCaseXml->GetText(), "")) { + *streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; + return ErrorCode::STATUS_OK; + } + + int64_t streamUseCaseInt = std::strtol(streamUseCaseXml->GetText(), nullptr, 0); + if (VALID_STREAM_USE_CASES.find(streamUseCaseInt) == VALID_STREAM_USE_CASES.end()) { + ALOGE("%s: streamUseCase %" PRId64 " is invalid: ", __FUNCTION__, streamUseCaseInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_STREAM_USE_CASES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *streamUseCase = streamUseCaseInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getTimestampBaseFromXml(const XMLElement* timestampBaseXml, + /* out */ int64_t* timestampBase) { + if (timestampBaseXml == nullptr || timestampBaseXml->GetText() == nullptr + || !strcmp(timestampBaseXml->GetText(), "")) { + *timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT; + return ErrorCode::STATUS_OK; + } + + int64_t timestampBaseInt = std::strtol(timestampBaseXml->GetText(), nullptr, 0); + if (VALID_TIMESTAMP_BASES.find(timestampBaseInt) == VALID_TIMESTAMP_BASES.end()) { + ALOGE("%s: timestampBase %" PRId64 " is invalid: ", __FUNCTION__, timestampBaseInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_TIMESTAMP_BASES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *timestampBase = timestampBaseInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getMirrorModeFromXml(const XMLElement* mirrorModeXml, + /* out */ int64_t* mirrorMode) { + if (mirrorModeXml == nullptr || mirrorModeXml->GetText() == nullptr + || !strcmp(mirrorModeXml->GetText(), "")) { + *mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO; + return ErrorCode::STATUS_OK; + } + + int64_t mirrorModeInt = std::strtol(mirrorModeXml->GetText(), nullptr, 0); + if (VALID_MIRROR_MODES.find(mirrorModeInt) == VALID_MIRROR_MODES.end()) { + ALOGE("%s: mirrorMode %" PRId64 " is invalid: ", __FUNCTION__, mirrorModeInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_MIRROR_MODES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *mirrorMode = mirrorModeInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getUseReadoutTimestampFromXml( + const XMLElement* useReadoutTimestampXml, /* out */ bool* useReadoutTimestamp) { + if (useReadoutTimestampXml != nullptr && useReadoutTimestampXml->GetText() != nullptr + && strcmp(useReadoutTimestampXml->GetText(), "")) { + const char* useReadoutTimestampStr = useReadoutTimestampXml->GetText(); + if (!strcmp(useReadoutTimestampStr, "1")) { + *useReadoutTimestamp = true; + return ErrorCode::STATUS_OK; + } else if (strcmp(useReadoutTimestampStr, "0")) { + ALOGE("%s: useReadoutTimestamp string %s is invalid: ", __FUNCTION__, + useReadoutTimestampStr); + ALOGE("%s: Expected one of: {0, 1}", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + } + + *useReadoutTimestamp = false; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getFormatFromXml(const XMLElement* formatXml, + /* out */ int64_t* format, + int64_t surfaceType) { + if (surfaceType != OutputConfiguration::SURFACE_TYPE_IMAGE_READER) { + // if surface type is not image reader, format must default to impl defined enum. + *format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + return ErrorCode::STATUS_OK; + } + + if (formatXml == nullptr || formatXml->GetText() == nullptr + || !strcmp(formatXml->GetText(), "")) { + ALOGE("%s: format field must be populated", __FUNCTION__); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + int64_t formatInt = std::strtol(formatXml->GetText(), nullptr, 0); + if (VALID_FORMATS.find(formatInt) == VALID_FORMATS.end()) { + ALOGE("%s: format %" PRId64 " is invalid: ", __FUNCTION__, formatInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_FORMATS).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *format = formatInt; + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getUsageFromXml(const XMLElement* usageXml, + /* out */ int64_t* usage, + int64_t surfaceType) { + if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE) { + // if surface type is SURFACE_TYPE_SURFACE_TEXTURE, usage must default to + // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE. + *usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + return ErrorCode::STATUS_OK; + } + + if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) { + // if surface type is SURFACE_TYPE_SURFACE_VIEW, usage must default to + // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY. + *usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY; + return ErrorCode::STATUS_OK; + } + + if (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER + || surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC) { + // if surface type is SURFACE_TYPE_MEDIA_RECORDER or SURFACE_TYPE_MEDIA_CODEC, usage must + // default to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE + *usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE; + return ErrorCode::STATUS_OK; + } + + if (usageXml == nullptr || usageXml->GetText() == nullptr + || !strcmp(usageXml->GetText(), "")) { + *usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER; + return ErrorCode::STATUS_OK; + } + + const char* usageStr = usageXml->GetText(); + std::vector<std::string> usageFlags = splitString(usageStr, '|'); + + for (std::string usageFlagStr : usageFlags) { + int64_t usageFlag = std::strtol(usageFlagStr.c_str(), nullptr, 0); + if (VALID_USAGES.find(usageFlag) == VALID_USAGES.end()) { + ALOGE("%s: usage %" PRId64 " is invalid: ", __FUNCTION__, usageFlag); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_USAGES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *usage |= usageFlag; + } + + return ErrorCode::STATUS_OK; +} + +ErrorCode SharedSessionConfigUtils::getDataSpaceFromXml(const XMLElement* dataSpaceXml, + /* out */ int64_t* dataSpace) { + if (dataSpaceXml == nullptr || dataSpaceXml->GetText() == nullptr + || !strcmp(dataSpaceXml->GetText(), "")) { + *dataSpace = HAL_DATASPACE_UNKNOWN; + return ErrorCode::STATUS_OK; + } + + int64_t dataSpaceInt = std::strtol(dataSpaceXml->GetText(), nullptr, 0); + if (VALID_DATA_SPACES.find(dataSpaceInt) == VALID_DATA_SPACES.end()) { + ALOGE("%s: dataSpace %" PRId64 " is invalid: ", __FUNCTION__, dataSpaceInt); + ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_DATA_SPACES).c_str()); + return ErrorCode::ERROR_CONFIG_FILE_FORMAT; + } + + *dataSpace = dataSpaceInt; + return ErrorCode::STATUS_OK; +} + +std::vector<std::string> SharedSessionConfigUtils::splitString(std::string inputString, + char delimiter) { + std::vector<std::string> tokens; + std::istringstream iss(inputString); + std::string token; + + while (std::getline(iss, token, delimiter)) { + tokens.push_back(token); + } + + return tokens; +} + +std::string SharedSessionConfigUtils::setToString(const std::set<int64_t>& s) { + std::ostringstream oss; + oss << "{"; + + for (auto it = s.begin(); it != s.end();) { + oss << *it; + + if (++it != s.end()) { + oss << ", "; + } + } + + oss << "}"; + return oss.str(); +} + +} // namespace android
diff --git a/services/camera/libcameraservice/config/SharedSessionConfigUtils.h b/services/camera/libcameraservice/config/SharedSessionConfigUtils.h new file mode 100644 index 0000000..2efe1dd --- /dev/null +++ b/services/camera/libcameraservice/config/SharedSessionConfigUtils.h
@@ -0,0 +1,274 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGUTILS_H_ +#define ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGUTILS_H_ + +#define SHARED_SESSION_FILE_PATH "system_ext/etc/" +#define SHARED_SESSION_FILE_NAME "shared_session_config.xml" + +#include <android/hardware_buffer.h> +#include <camera/camera2/OutputConfiguration.h> +#include <system/camera_metadata.h> +#include <system/graphics.h> + +#include <set> +#include <string> +#include "tinyxml2.h" +#include <vector> + +using tinyxml2::XMLElement; +namespace android { + +enum ErrorCode : uint8_t { + // OK status. + STATUS_OK = 0, + + // Error status. Cannot read the config file (config file missing or not + // accessible) + ERROR_READ_CONFIG_FILE = 1, + + // Error status. Config file format doesn't match. + ERROR_CONFIG_FILE_FORMAT = 2, + + // Error status. Config reader hasn't been initialized. + ERROR_CONFIG_READER_UNINITIALIZED = 3, + + // Error status. Bad parameter. + ERROR_BAD_PARAMETER = 4, +}; + +inline const std::set<int64_t> VALID_COLOR_SPACES = { + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED, + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB, + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3, + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020_HLG, +}; + +inline const std::set<int64_t> VALID_SURFACE_TYPES = { + OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW, + OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE, + OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER, + OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC, + OutputConfiguration::SURFACE_TYPE_IMAGE_READER, +}; + +inline const std::set<int64_t> VALID_STREAM_USE_CASES = { + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW, + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START, +}; + +inline const std::set<int64_t> VALID_TIMESTAMP_BASES = { + OutputConfiguration::TIMESTAMP_BASE_DEFAULT, + OutputConfiguration::TIMESTAMP_BASE_SENSOR, + OutputConfiguration::TIMESTAMP_BASE_MONOTONIC, + OutputConfiguration::TIMESTAMP_BASE_REALTIME, + OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED, + OutputConfiguration::TIMESTAMP_BASE_MAX, +}; + +inline const std::set<int64_t> VALID_MIRROR_MODES = { + OutputConfiguration::MIRROR_MODE_AUTO, + OutputConfiguration::MIRROR_MODE_NONE, + OutputConfiguration::MIRROR_MODE_H, + OutputConfiguration::MIRROR_MODE_V, +}; + +inline const std::set<int64_t> VALID_FORMATS = { + HAL_PIXEL_FORMAT_RGBA_8888, + HAL_PIXEL_FORMAT_RGBX_8888, + HAL_PIXEL_FORMAT_RGB_888, + HAL_PIXEL_FORMAT_RGB_565, + HAL_PIXEL_FORMAT_BGRA_8888, + HAL_PIXEL_FORMAT_YCBCR_422_SP, + HAL_PIXEL_FORMAT_YCRCB_420_SP, + HAL_PIXEL_FORMAT_YCBCR_422_I, + HAL_PIXEL_FORMAT_RGBA_FP16, + HAL_PIXEL_FORMAT_RAW16, + HAL_PIXEL_FORMAT_BLOB, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + HAL_PIXEL_FORMAT_YCBCR_420_888, + HAL_PIXEL_FORMAT_RAW_OPAQUE, + HAL_PIXEL_FORMAT_RAW10, + HAL_PIXEL_FORMAT_RAW12, + HAL_PIXEL_FORMAT_RGBA_1010102, + HAL_PIXEL_FORMAT_Y8, + HAL_PIXEL_FORMAT_Y16, + HAL_PIXEL_FORMAT_YV12, + HAL_PIXEL_FORMAT_DEPTH_16, + HAL_PIXEL_FORMAT_DEPTH_24, + HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8, + HAL_PIXEL_FORMAT_DEPTH_32F, + HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8, + HAL_PIXEL_FORMAT_STENCIL_8, + HAL_PIXEL_FORMAT_YCBCR_P010, + HAL_PIXEL_FORMAT_HSV_888, +}; + +inline const std::set<int64_t> VALID_USAGES = { + AHARDWAREBUFFER_USAGE_CPU_READ_NEVER, + AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER, + AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY, + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT, + AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY, + AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT, + AHARDWAREBUFFER_USAGE_VIDEO_ENCODE, + AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA, + AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER, + AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP, + AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, + AHARDWAREBUFFER_USAGE_FRONT_BUFFER, + AHARDWAREBUFFER_USAGE_VENDOR_0, + AHARDWAREBUFFER_USAGE_VENDOR_1, + AHARDWAREBUFFER_USAGE_VENDOR_2, + AHARDWAREBUFFER_USAGE_VENDOR_3, + AHARDWAREBUFFER_USAGE_VENDOR_4, + AHARDWAREBUFFER_USAGE_VENDOR_5, + AHARDWAREBUFFER_USAGE_VENDOR_6, + AHARDWAREBUFFER_USAGE_VENDOR_7, + AHARDWAREBUFFER_USAGE_VENDOR_8, + AHARDWAREBUFFER_USAGE_VENDOR_9, + AHARDWAREBUFFER_USAGE_VENDOR_10, + AHARDWAREBUFFER_USAGE_VENDOR_11, + AHARDWAREBUFFER_USAGE_VENDOR_12, + AHARDWAREBUFFER_USAGE_VENDOR_13, + AHARDWAREBUFFER_USAGE_VENDOR_14, + AHARDWAREBUFFER_USAGE_VENDOR_15, + AHARDWAREBUFFER_USAGE_VENDOR_16, + AHARDWAREBUFFER_USAGE_VENDOR_17, + AHARDWAREBUFFER_USAGE_VENDOR_18, +}; + +inline const std::set<int64_t> VALID_DATA_SPACES = { + HAL_DATASPACE_UNKNOWN, + HAL_DATASPACE_ARBITRARY, + HAL_DATASPACE_STANDARD_UNSPECIFIED, + HAL_DATASPACE_STANDARD_BT709, + HAL_DATASPACE_STANDARD_BT601_625, + HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED, + HAL_DATASPACE_STANDARD_BT601_525, + HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED, + HAL_DATASPACE_STANDARD_BT2020, + HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE, + HAL_DATASPACE_STANDARD_BT470M, + HAL_DATASPACE_STANDARD_FILM, + HAL_DATASPACE_STANDARD_DCI_P3, + HAL_DATASPACE_STANDARD_ADOBE_RGB, + HAL_DATASPACE_TRANSFER_UNSPECIFIED, + HAL_DATASPACE_TRANSFER_LINEAR, + HAL_DATASPACE_TRANSFER_SRGB, + HAL_DATASPACE_TRANSFER_SMPTE_170M, + HAL_DATASPACE_TRANSFER_GAMMA2_2, + HAL_DATASPACE_TRANSFER_GAMMA2_6, + HAL_DATASPACE_TRANSFER_GAMMA2_8, + HAL_DATASPACE_TRANSFER_ST2084, + HAL_DATASPACE_TRANSFER_HLG, + HAL_DATASPACE_RANGE_UNSPECIFIED, + HAL_DATASPACE_RANGE_FULL, + HAL_DATASPACE_RANGE_LIMITED, + HAL_DATASPACE_RANGE_EXTENDED, + HAL_DATASPACE_SRGB_LINEAR, + HAL_DATASPACE_V0_SRGB_LINEAR, + HAL_DATASPACE_V0_SCRGB_LINEAR, + HAL_DATASPACE_SRGB, + HAL_DATASPACE_V0_SRGB, + HAL_DATASPACE_V0_SCRGB, + HAL_DATASPACE_JFIF, + HAL_DATASPACE_V0_JFIF, + HAL_DATASPACE_BT601_625, + HAL_DATASPACE_V0_BT601_625, + HAL_DATASPACE_BT601_525, + HAL_DATASPACE_V0_BT601_525, + HAL_DATASPACE_BT709, + HAL_DATASPACE_V0_BT709, + HAL_DATASPACE_DCI_P3_LINEAR, + HAL_DATASPACE_DCI_P3, + HAL_DATASPACE_DISPLAY_P3_LINEAR, + HAL_DATASPACE_DISPLAY_P3, + HAL_DATASPACE_ADOBE_RGB, + HAL_DATASPACE_BT2020_LINEAR, + HAL_DATASPACE_BT2020, + HAL_DATASPACE_BT2020_PQ, + HAL_DATASPACE_DEPTH, + HAL_DATASPACE_SENSOR, +}; + +class SharedSessionConfigUtils { +public: + + // toString function for ErrorCode enum. + static const char* toString(ErrorCode errorCode); + + // Convert string representation of colorspace to its int value. + static ErrorCode getColorSpaceFromStr(const char* colorSpaceStr, int32_t* colorSpace); + + // Convert string representation of surface type to its int value. + static ErrorCode getSurfaceTypeFromXml(const XMLElement* surfaceTypeXml, int64_t* surfaceType); + + // Convert string representation of width to its int value. + static ErrorCode getWidthFromXml(const XMLElement* widthXml, int64_t* width); + + // Convert string representation of height to its int value. + static ErrorCode getHeightFromXml(const XMLElement* heightXml, int64_t* height); + + // Convert string representation of physical cameraId to its std::string value. + static ErrorCode getPhysicalCameraIdFromXml(const XMLElement* physicalCameraIdXml, + std::string* physicalCameraId); + + // Convert string representation of stream use case to its int64 value. + static ErrorCode getStreamUseCaseFromXml(const XMLElement* streamUseCaseXml, + int64_t* streamUseCase); + + // Convert string representation of timestamp base to its int value. + static ErrorCode getTimestampBaseFromXml(const XMLElement* timestampBaseXml, + int64_t* timestampBase); + + // Convert string representation of mirror mode to its int value. + static ErrorCode getMirrorModeFromXml(const XMLElement* mirrorModeXml, int64_t* mirrorMode); + + // Convert string representation of use readout timestamp to its bool value. + static ErrorCode getUseReadoutTimestampFromXml(const XMLElement* useReadoutTimestampXml, + bool* useReadoutTimestamp); + + // Convert string representation of format to its int value. + static ErrorCode getFormatFromXml(const XMLElement* formatXml, int64_t* format, + int64_t surfaceType); + + // Convert string representation of usage to its int64 value. + static ErrorCode getUsageFromXml(const XMLElement* usageXml, int64_t* usage, + int64_t surfaceType); + + // Convert string representation of data space to its int value. + static ErrorCode getDataSpaceFromXml(const XMLElement* dataSpaceXml, int64_t* dataSpace); + + static std::vector<std::string> splitString(std::string inputString, char delimiter); + + static std::string setToString(const std::set<int64_t>& s); +}; + +} // namespace android + +#endif // ANDROID_SERVERS_CAMERA_SHAREDSESSIONCONFIGUTILS_H_
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index bb54f25..e8de931 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2962,6 +2962,36 @@ return retVal; } +const sp<Camera3Device::CaptureRequest> Camera3Device::getOngoingRepeatingRequestLocked() { + ALOGV("%s", __FUNCTION__); + + if (mRequestThread != NULL) { + return mRequestThread->getOngoingRepeatingRequest(); + } + + return nullptr; +} + +status_t Camera3Device::updateOngoingRepeatingRequestLocked(const SurfaceMap& surfaceMap) { + ALOGV("%s", __FUNCTION__); + + if (mRequestThread != NULL) { + return mRequestThread->updateOngoingRepeatingRequest(surfaceMap); + } + + return INVALID_OPERATION; +} + +int64_t Camera3Device::getRepeatingRequestLastFrameNumberLocked() { + ALOGV("%s", __FUNCTION__); + + if (mRequestThread != NULL) { + return mRequestThread->getRepeatingRequestLastFrameNumber(); + } + + return hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES; +} + void Camera3Device::monitorMetadata(TagMonitor::eventSource source, int64_t frameNumber, nsecs_t timestamp, const CameraMetadata& metadata, const std::unordered_map<std::string, CameraMetadata>& physicalMetadata, @@ -4228,6 +4258,60 @@ return mLatestRequestInfo; } +const sp<Camera3Device::CaptureRequest> Camera3Device::RequestThread::getOngoingRepeatingRequest() { + ATRACE_CALL(); + Mutex::Autolock l(mRequestLock); + + ALOGV("RequestThread::%s", __FUNCTION__); + if (mRepeatingRequests.empty()) { + return nullptr; + } + + return *mRepeatingRequests.begin(); +} + +status_t Camera3Device::RequestThread::updateOngoingRepeatingRequest(const SurfaceMap& surfaceMap) { + ATRACE_CALL(); + Mutex::Autolock l(mRequestLock); + if (mRepeatingRequests.empty()) { + return INVALID_OPERATION; + } + + sp<CaptureRequest> curRequest = *mRepeatingRequests.begin(); + std::vector<int32_t> outputStreamIds; + Vector<sp<camera3::Camera3OutputStreamInterface>> outputStreams; + for (const auto& [key, value] : surfaceMap) { + outputStreamIds.push_back(key); + } + for (auto id : outputStreamIds) { + sp<Camera3Device> parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: parent does not exist!", __FUNCTION__); + return INVALID_OPERATION; + } + sp<Camera3OutputStreamInterface> stream = parent->mOutputStreams.get(id); + if (stream == nullptr) { + CLOGE("Request references unknown stream %d",id); + return BAD_VALUE; + } + outputStreams.push(stream); + } + curRequest->mOutputStreams = outputStreams; + curRequest->mOutputSurfaces = surfaceMap; + + ALOGV("RequestThread::%s", __FUNCTION__); + return OK; + +} + +int64_t Camera3Device::RequestThread::getRepeatingRequestLastFrameNumber() { + ATRACE_CALL(); + Mutex::Autolock l(mRequestLock); + + ALOGV("RequestThread::%s", __FUNCTION__); + return mRepeatingLastFrameNumber; +} + bool Camera3Device::RequestThread::isStreamPending( sp<Camera3StreamInterface>& stream) { ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 3c45c1a..cdaaa4c 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -38,6 +38,7 @@ #include "common/CameraDeviceBase.h" #include "common/DepthPhotoProcessor.h" +#include "common/FrameProcessorBase.h" #include "device3/BufferUtils.h" #include "device3/StatusTracker.h" #include "device3/Camera3BufferManager.h" @@ -195,6 +196,40 @@ status_t deleteStream(int id) override; + virtual status_t beginConfigure() override {return OK;}; + + virtual status_t getSharedStreamIds(const OutputStreamInfo& /*config*/, + std::vector< int>& /*streamIds*/) override {return INVALID_OPERATION;}; + + virtual status_t addSharedSurfaces(int /*streamId*/, + const std::vector<android::camera3::OutputStreamInfo>& /*outputInfo*/, + const std::vector<sp<Surface>>& /*surfaces*/, + std::vector<int>* /*surfaceIds*/) override {return INVALID_OPERATION;}; + + virtual status_t removeSharedSurfaces(int /*streamId*/, + const std::vector<size_t>& /*surfaceIds*/) override {return INVALID_OPERATION;}; + + virtual status_t setSharedStreamingRequest( + const PhysicalCameraSettingsList& /*request*/, const SurfaceMap& /*surfaceMap*/, + int32_t* /*sharedReqID*/, int64_t* /*lastFrameNumber = NULL*/) override { + return INVALID_OPERATION; + }; + + virtual status_t clearSharedStreamingRequest(int64_t* /*lastFrameNumber = NULL*/) override { + return INVALID_OPERATION; + }; + + virtual status_t setSharedCaptureRequest(const PhysicalCameraSettingsList& /*request*/, + const SurfaceMap& /*surfaceMap*/, int32_t* /*sharedReqID*/, + int64_t* /*lastFrameNumber = NULL*/) override {return INVALID_OPERATION;}; + + virtual sp<camera2::FrameProcessorBase> getSharedFrameProcessor() override {return nullptr;}; + + virtual status_t startStreaming(const int32_t /*reqId*/, const SurfaceMap& /*surfaceMap*/, + int32_t* /*sharedReqID*/, int64_t* /*lastFrameNumber = NULL*/) + override {return INVALID_OPERATION;}; + + status_t configureStreams(const CameraMetadata& sessionParams, int operatingMode = camera_stream_configuration_mode_t::CAMERA_STREAM_CONFIGURATION_NORMAL_MODE) override; @@ -213,7 +248,7 @@ // Transitions to the idle state on success status_t waitUntilDrained() override; - status_t setNotifyCallback(wp<NotificationListener> listener) override; + virtual status_t setNotifyCallback(wp<NotificationListener> listener) override; bool willNotify3A() override; status_t waitForNextFrame(nsecs_t timeout) override; status_t getNextResult(CaptureResult *frame) override; @@ -750,6 +785,22 @@ }; /** + * Get the first repeating request in the ongoing repeating request list. + */ + const sp<CaptureRequest> getOngoingRepeatingRequestLocked(); + + /** + * Update the first repeating request in the ongoing repeating request list + * with the surface map provided. + */ + status_t updateOngoingRepeatingRequestLocked(const SurfaceMap& surfaceMap); + + /** + * Get the repeating request last frame number. + */ + int64_t getRepeatingRequestLastFrameNumberLocked(); + + /** * Get the last request submitted to the hal by the request thread. * * Must be called with mLock held. @@ -1054,6 +1105,20 @@ **/ void wakeupLatestRequest(bool latestRequestFailed, int32_t latestRequestId); + /** + * Get the first repeating request in the ongoing repeating request list. + */ + const sp<CaptureRequest> getOngoingRepeatingRequest(); + + /** + * Update the first repeating request in the ongoing repeating request list + * with the surface map provided. + */ + status_t updateOngoingRepeatingRequest(const SurfaceMap& surfaceMap); + + // Get the repeating request last frame number. + int64_t getRepeatingRequestLastFrameNumber(); + protected: virtual bool threadLoop();
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 0786622..f8d749a 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -134,6 +134,18 @@ sensorPixelModesUsed(_sensorPixelModesUsed), dynamicRangeProfile(_dynamicRangeProfile), streamUseCase(_streamUseCase), timestampBase(_timestampBase), mirrorMode(_mirrorMode), colorSpace(_colorSpace) {} + bool operator == (const OutputStreamInfo& other) const { + return (width == other.width && + height == other.height && + format == other.format && + (other.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || + (dataSpace == other.dataSpace && consumerUsage == other.consumerUsage)) && + sensorPixelModesUsed == other.sensorPixelModesUsed && + dynamicRangeProfile == other.dynamicRangeProfile && + colorSpace == other.colorSpace && + streamUseCase == other.streamUseCase && + timestampBase == other.timestampBase); + } }; // Utility class to lock and unlock a GraphicBuffer
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h index abc3f9c..474dfc7 100644 --- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h +++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -72,7 +72,8 @@ virtual status_t switchToOffline(const std::vector<int32_t>& /*streamsToKeep*/, /*out*/ sp<CameraOfflineSessionBase>* /*session*/) override; - status_t initialize(sp<CameraProviderManager> manager, const std::string& monitorTags) override; + virtual status_t initialize(sp<CameraProviderManager> manager, const std::string& monitorTags) + override; class AidlHalInterface : public Camera3Device::HalInterface { public:
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.cpp new file mode 100644 index 0000000..26dbe2d --- /dev/null +++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.cpp
@@ -0,0 +1,630 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "AidlCamera3-SharedDevice" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 +//#define LOG_NNDEBUG 0 // Per-frame verbose logging + +#ifdef LOG_NNDEBUG +#define ALOGVV(...) ALOGV(__VA_ARGS__) +#else +#define ALOGVV(...) ((void)0) +#endif + +// Convenience macro for transient errors +#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.c_str(), __FUNCTION__, \ + ##__VA_ARGS__) + +#define CLOGW(fmt, ...) ALOGW("Camera %s: %s: " fmt, mId.c_str(), __FUNCTION__, \ + ##__VA_ARGS__) + +// Convenience macros for transitioning to the error state +#define SET_ERR(fmt, ...) setErrorState( \ + "%s: " fmt, __FUNCTION__, \ + ##__VA_ARGS__) +#define SET_ERR_L(fmt, ...) setErrorStateLocked( \ + "%s: " fmt, __FUNCTION__, \ + ##__VA_ARGS__) +#define DECODE_VALUE(decoder, type, var) \ + do { \ + if (decoder.get##type(var) != OK) { \ + return NOT_ENOUGH_DATA; \ + } \ + } while (0) + +#include <utils/Log.h> +#include <utils/Trace.h> +#include <cstring> +#include "../../common/aidl/AidlProviderInfo.h" +#include "utils/SessionConfigurationUtils.h" +#include "AidlCamera3SharedDevice.h" + +using namespace android::camera3; +using namespace android::camera3::SessionConfigurationUtils; + +namespace android { + +class OpaqueConsumerListener : public BufferItemConsumer::FrameAvailableListener { +public: + OpaqueConsumerListener(const wp<BufferItemConsumer>& consumer) : mConsumer(consumer) {} + + virtual void onFrameAvailable(const BufferItem&) { + sp<BufferItemConsumer> consumer = mConsumer.promote(); + if (consumer == nullptr) { + return; + } + BufferItem item; + consumer->acquireBuffer(&item, 0); + consumer->releaseBuffer(item, Fence::NO_FENCE); + } + virtual void onFrameReplaced(const BufferItem&) {} + virtual void onFrameDequeued(const uint64_t) {} + virtual void onFrameCancelled(const uint64_t) {} + virtual void onFrameDetached(const uint64_t) {} + + wp<BufferItemConsumer> mConsumer; +}; + +// Metadata android.info.availableSharedOutputConfigurations has list of shared output +// configurations. Each output configuration has minimum of 11 entries of size long +// followed by the physical camera id if present. +// See android.info.availableSharedOutputConfigurations for details. +static const int SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES = 11; +std::map<std::string, sp<AidlCamera3SharedDevice>> AidlCamera3SharedDevice::sSharedDevices; +std::map<std::string, std::unordered_set<int>> AidlCamera3SharedDevice::sClientsPid; +Mutex AidlCamera3SharedDevice::sSharedClientsLock; +sp<AidlCamera3SharedDevice> AidlCamera3SharedDevice::getInstance( + std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper, + std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils, + const std::string& id, bool overrideForPerfClass, int rotationOverride, + bool legacyClient) { + Mutex::Autolock l(sSharedClientsLock); + if (sClientsPid[id].empty()) { + AidlCamera3SharedDevice* sharedDevice = new AidlCamera3SharedDevice( + cameraServiceProxyWrapper, attributionAndPermissionUtils, id, overrideForPerfClass, + rotationOverride, legacyClient); + sSharedDevices[id] = sharedDevice; + } + if (attributionAndPermissionUtils != nullptr) { + sClientsPid[id].insert(attributionAndPermissionUtils->getCallingPid()); + } + return sSharedDevices[id]; +} + +status_t AidlCamera3SharedDevice::initialize(sp<CameraProviderManager> manager, + const std::string& monitorTags) { + ATRACE_CALL(); + status_t res = OK; + Mutex::Autolock l(mSharedDeviceLock); + if (mStatus == STATUS_UNINITIALIZED) { + res = AidlCamera3Device::initialize(manager, monitorTags); + if (res == OK) { + mSharedOutputConfigurations = getSharedOutputConfiguration(); + wp<NotificationListener> weakThis(this); + res = AidlCamera3Device::setNotifyCallback(weakThis); + if (res != OK) { + ALOGE("%s: Camera %s: Unable to set notify callback: %s (%d)", + __FUNCTION__, mId.c_str(), strerror(-res), res); + return res; + } + mFrameProcessor = new camera2::FrameProcessorBase(this); + std::string threadName = std::string("CDU-") + mId + "-FrameProc"; + res = mFrameProcessor->run(threadName.c_str()); + if (res != OK) { + ALOGE("%s: Unable to start frame processor thread: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + } + } + return res; +} + +status_t AidlCamera3SharedDevice::disconnectClient(int clientPid) { + Mutex::Autolock l(mSharedDeviceLock); + if (sClientsPid[mId].erase(clientPid) == 0) { + ALOGW("%s: Camera %s: Client %d is not connected to shared device", __FUNCTION__, + mId.c_str(), clientPid); + } + + if (sClientsPid[mId].empty()) { + return Camera3Device::disconnect(); + } + return OK; +} + +std::vector<OutputConfiguration> AidlCamera3SharedDevice::getSharedOutputConfiguration() { + std::vector<OutputConfiguration> sharedConfigs; + int32_t colorspace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED; + camera_metadata_entry sharedSessionColorSpace = mDeviceInfo.find( + ANDROID_SHARED_SESSION_COLOR_SPACE); + if (sharedSessionColorSpace.count > 0) { + colorspace = *sharedSessionColorSpace.data.i32; + } + camera_metadata_entry sharedSessionConfigs = mDeviceInfo.find( + ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS); + if (sharedSessionConfigs.count > 0) { + int numOfEntries = sharedSessionConfigs.count; + int i = 0; + uint8_t physicalCameraIdLen; + int surfaceType, width, height, format, mirrorMode, timestampBase, dataspace; + long usage, streamUseCase; + bool isReadOutTimestampEnabled; + while (numOfEntries >= SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES) { + surfaceType = (int)sharedSessionConfigs.data.i64[i]; + width = (int)sharedSessionConfigs.data.i64[i+1]; + height = (int)sharedSessionConfigs.data.i64[i+2]; + format = (int)sharedSessionConfigs.data.i64[i+3]; + mirrorMode = (int)sharedSessionConfigs.data.i64[i+4]; + isReadOutTimestampEnabled = (sharedSessionConfigs.data.i64[i+5] != 0); + timestampBase = (int)sharedSessionConfigs.data.i64[i+6]; + dataspace = (int)sharedSessionConfigs.data.i64[i+7]; + usage = sharedSessionConfigs.data.i64[i+8]; + streamUseCase = sharedSessionConfigs.data.i64[i+9]; + physicalCameraIdLen = sharedSessionConfigs.data.i64[i+10]; + numOfEntries -= SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES; + i += SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES; + if (numOfEntries < physicalCameraIdLen) { + ALOGE("%s: Camera %s: Number of remaining data (%d entries) in shared configuration" + " is less than physical camera id length %d. Malformed metadata" + " android.info.availableSharedOutputConfigurations.", __FUNCTION__, + mId.c_str(), numOfEntries, physicalCameraIdLen); + break; + } + std::string physicalCameraId; + long asciiValue; + for (int j = 0; j < physicalCameraIdLen; j++) { + asciiValue = sharedSessionConfigs.data.i64[i+j]; + if (asciiValue == 0) { // Check for null terminator + break; + } + physicalCameraId += static_cast<char>(asciiValue); + } + OutputConfiguration* outConfig = new OutputConfiguration(surfaceType, width, height, + format, colorspace, mirrorMode, isReadOutTimestampEnabled, timestampBase, + dataspace, usage, streamUseCase, physicalCameraId); + sharedConfigs.push_back(*outConfig); + i += physicalCameraIdLen; + numOfEntries -= physicalCameraIdLen; + } + if (numOfEntries != 0) { + ALOGE("%s: Camera %s: there are still %d entries left in shared output configuration." + " Malformed metadata android.info.availableSharedOutputConfigurations.", + __FUNCTION__, mId.c_str(), numOfEntries); + } + } + return sharedConfigs; +} + +status_t AidlCamera3SharedDevice::beginConfigure() { + Mutex::Autolock l(mSharedDeviceLock); + status_t res; + int i = 0; + + if (mStatus != STATUS_UNCONFIGURED) { + return OK; + } + + mSharedSurfaces.clear(); + mOpaqueConsumers.clear(); + mSharedSurfaceIds.clear(); + mStreamInfoMap.clear(); + + for (auto config : mSharedOutputConfigurations) { + std::vector<sp<Surface>> consumers; + android_dataspace dataspace = (android_dataspace)config.getDataspace(); + + if (config.getColorSpace() + != ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED + && config.getFormat() != HAL_PIXEL_FORMAT_BLOB) { + if (!dataSpaceFromColorSpace(&dataspace, config.getColorSpace())) { + std::string msg = fmt::sprintf("Camera %s: color space %d not supported, " + " failed to convert to data space", mId.c_str(), config.getColorSpace()); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); + return INVALID_OPERATION; + } + } + std::unordered_set<int32_t> overriddenSensorPixelModes; + if (checkAndOverrideSensorPixelModesUsed(config.getSensorPixelModesUsed(), + config.getFormat(), config.getWidth(), config.getHeight(), + mDeviceInfo, &overriddenSensorPixelModes) != OK) { + std::string msg = fmt::sprintf("Camera %s: sensor pixel modes for stream with " + "format %#x are not valid",mId.c_str(), config.getFormat()); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); + return INVALID_OPERATION; + } + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make( + AHARDWAREBUFFER_USAGE_CAMERA_READ); + mOpaqueConsumers.push_back(consumer); + mSharedSurfaces.push_back(consumer->getSurface()); + #else + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<BufferItemConsumer> opaqueConsumer = sp<BufferItemConsumer>::make(consumer, + AHARDWAREBUFFER_USAGE_CAMERA_READ); + mOpaqueConsumers.push_back(opaqueConsumer); + mSharedSurfaces.push_back(new Surface(producer)); + #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<OpaqueConsumerListener> consumerListener = sp<OpaqueConsumerListener>::make( + mOpaqueConsumers[i]); + mOpaqueConsumers[i]->setFrameAvailableListener(consumerListener); + consumers.push_back(mSharedSurfaces[i]); + sp<Camera3SharedOutputStream> newStream = new Camera3SharedOutputStream(mNextStreamId, consumers, + config.getWidth(),config.getHeight(), config.getFormat(), config.getUsage(), + dataspace, static_cast<camera_stream_rotation_t>(config.getRotation()), + mTimestampOffset, config.getPhysicalCameraId(), overriddenSensorPixelModes, + getTransportType(), config.getSurfaceSetID(), mUseHalBufManager, + config.getDynamicRangeProfile(), config.getStreamUseCase(), + mDeviceTimeBaseIsRealtime, config.getTimestampBase(), + config.getColorSpace(), config.useReadoutTimestamp()); + int id = newStream->getSurfaceId(consumers[0]); + if (id < 0) { + SET_ERR_L("Invalid surface id"); + return BAD_VALUE; + } + mSharedSurfaceIds.push_back(id); + newStream->setStatusTracker(mStatusTracker); + newStream->setBufferManager(mBufferManager); + newStream->setImageDumpMask(mImageDumpMask); + res = mOutputStreams.add(mNextStreamId, newStream); + if (res < 0) { + SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res); + return res; + } + mSessionStatsBuilder.addStream(mNextStreamId); + OutputStreamInfo streamInfo(config.getWidth(),config.getHeight(), config.getFormat(), + dataspace, config.getUsage(), overriddenSensorPixelModes, + config.getDynamicRangeProfile(), config.getStreamUseCase(), + config.getTimestampBase(), config.getMirrorMode(), config.getColorSpace()); + mStreamInfoMap[mNextStreamId++] = streamInfo; + i++; + } + CameraMetadata sessionParams; + res = configureStreams(sessionParams, CAMERA_STREAM_CONFIGURATION_NORMAL_MODE); + if (res != OK) { + std::string msg = fmt::sprintf("Camera %s: Error configuring streams: %s (%d)", + mId.c_str(), strerror(-res), res); + ALOGE("%s: %s", __FUNCTION__, msg.c_str()); + return res; + } + return OK; +} + +status_t AidlCamera3SharedDevice::getSharedStreamIds(const OutputStreamInfo &config, + std::vector<int>& streamIds) { + Mutex::Autolock l(mSharedDeviceLock); + streamIds.clear(); + + for (const auto& streamInfo : mStreamInfoMap) { + OutputStreamInfo info = streamInfo.second; + if (info == config) { + streamIds.push_back(streamInfo.first); + } + } + + if (streamIds.empty()) { + return NAME_NOT_FOUND; + } else { + return OK; + } +} + +status_t AidlCamera3SharedDevice::addSharedSurfaces(int streamId, + const std::vector<android::camera3::OutputStreamInfo> &outputInfo, + const std::vector<sp<Surface>> &surfaces, std::vector<int> *surfaceIds) { + Mutex::Autolock l(mSharedDeviceLock); + KeyedVector<sp<Surface>, size_t> outputMap; + std::vector<size_t> removedSurfaceIds; + status_t res; + sp<Camera3OutputStreamInterface> stream = mOutputStreams.get(streamId); + if (stream == nullptr) { + CLOGE("Stream %d is unknown", streamId); + return BAD_VALUE; + } + + res = updateStream(streamId, surfaces, outputInfo, removedSurfaceIds, &outputMap); + if (res != OK) { + CLOGE("Stream %d failed to update stream (error %d %s) ", + streamId, res, strerror(-res)); + return res; + } + for (size_t i = 0 ; i < outputMap.size(); i++){ + if (surfaceIds != nullptr) { + surfaceIds->push_back(outputMap.valueAt(i)); + } + } + return OK; +} + +status_t AidlCamera3SharedDevice::removeSharedSurfaces(int streamId, + const std::vector<size_t> &removedSurfaceIds) { + Mutex::Autolock l(mSharedDeviceLock); + KeyedVector<sp<Surface>, size_t> outputMap; + std::vector<sp<Surface>> surfaces; + std::vector<OutputStreamInfo> outputInfo; + status_t res; + sp<Camera3OutputStreamInterface> stream = mOutputStreams.get(streamId); + if (stream == nullptr) { + CLOGE("Stream %d is unknown", streamId); + return BAD_VALUE; + } + + res = updateStream(streamId, surfaces, outputInfo, removedSurfaceIds, &outputMap); + if (res != OK) { + CLOGE("Stream %d failed to update stream (error %d %s) ", + streamId, res, strerror(-res)); + return res; + } + return OK; +} + +SurfaceMap AidlCamera3SharedDevice::mergeSurfaceMaps(const SurfaceMap& map1, + const SurfaceMap& map2) { + SurfaceMap mergedMap = map1; + + for (const auto& [key, value] : map2) { + // If the key exists in map1, append the values + if (mergedMap.count(key) > 0) { + mergedMap[key].insert(mergedMap[key].end(), value.begin(), value.end()); + } else { + // Otherwise, insert the key-value pair from map2 + mergedMap[key] = value; + } + } + return mergedMap; +} + +SurfaceMap AidlCamera3SharedDevice::removeClientSurfaceMap(const SurfaceMap& map1, + const SurfaceMap& map2) { + SurfaceMap resultMap = map1; + + for (const auto& [key, value2] : map2) { + auto it1 = resultMap.find(key); + if (it1 != resultMap.end()) { + // Key exists in both maps, remove matching values + std::vector<size_t>& value1 = it1->second; + for (size_t val2 : value2) { + value1.erase(std::remove(value1.begin(), value1.end(), val2), value1.end()); + } + + // If the vector is empty after removing, remove the key + if (value1.empty()) { + resultMap.erase(it1); + } + } + } + return resultMap; +} + +status_t AidlCamera3SharedDevice::setSharedStreamingRequest( + const CameraDeviceBase::PhysicalCameraSettingsList &clientSettings, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, + int64_t *lastFrameNumber) { + if ((sharedReqID == nullptr) || (lastFrameNumber == nullptr)) { + return BAD_VALUE; + } + + Mutex::Autolock l(mSharedDeviceLock); + auto requestIdEntry = clientSettings.begin()->metadata.find(ANDROID_REQUEST_ID); + if (requestIdEntry.count == 0) { + CLOGE("RequestID does not exist in metadata"); + return BAD_VALUE; + } + int clientRequestId = requestIdEntry.data.i32[0]; + CameraDeviceBase::PhysicalCameraSettingsList newSettings = clientSettings; + SurfaceMap newSurfaceMap = surfaceMap; + List<const CameraDeviceBase::PhysicalCameraSettingsList> settingsList; + std::list<SurfaceMap> surfaceMaps; + int32_t requestID = mRequestIdCounter; + const sp<CaptureRequest> curRequest = getOngoingRepeatingRequestLocked(); + + if (curRequest != nullptr) { + // If there is ongoing streaming going by secondary clients, then + // merge their surface map in the new repeating request. + newSurfaceMap = mergeSurfaceMaps(surfaceMap, curRequest->mOutputSurfaces); + } + + std::vector<int32_t> outputStreamIds; + for (const auto& [key, value] : newSurfaceMap) { + outputStreamIds.push_back(key); + } + surfaceMaps.push_back(newSurfaceMap); + newSettings.begin()->metadata.update(ANDROID_REQUEST_ID, &requestID, /*size*/1); + mRequestIdCounter++; + newSettings.begin()->metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, + &outputStreamIds[0], outputStreamIds.size()); + settingsList.push_back(newSettings); + status_t err = setStreamingRequestList(settingsList, surfaceMaps, lastFrameNumber); + if (err != OK) { + CLOGE("Cannot start shared streaming request"); + return err; + } + mStreamingRequestId = requestID; + int clientPid = mAttributionAndPermissionUtils->getCallingPid(); + mClientRequestIds[clientPid] = clientRequestId; + mClientSurfaces[clientPid] = surfaceMap; + *sharedReqID = mStreamingRequestId; + + return err; +} + +status_t AidlCamera3SharedDevice::clearSharedStreamingRequest(int64_t *lastFrameNumber) { + Mutex::Autolock l(mSharedDeviceLock); + int clientPid = mAttributionAndPermissionUtils->getCallingPid(); + const sp<CaptureRequest> curRequest = getOngoingRepeatingRequestLocked(); + if (curRequest == nullptr) { + CLOGE("No streaming ongoing"); + return INVALID_OPERATION; + } + + SurfaceMap newSurfaceMap; + newSurfaceMap = removeClientSurfaceMap(curRequest->mOutputSurfaces, mClientSurfaces[clientPid]); + mClientRequestIds.erase(clientPid); + mClientSurfaces.erase(clientPid); + if (newSurfaceMap.empty()) { + status_t err = clearStreamingRequest(lastFrameNumber); + if (err != OK) { + CLOGE("Error clearing streaming request"); + } + return err; + } + *lastFrameNumber = getRepeatingRequestLastFrameNumberLocked(); + return updateOngoingRepeatingRequestLocked(newSurfaceMap); +} + +status_t AidlCamera3SharedDevice::setSharedCaptureRequest(const PhysicalCameraSettingsList &request, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, int64_t *lastFrameNumber) { + Mutex::Autolock l(mSharedDeviceLock); + if (sharedReqID == nullptr) { + return BAD_VALUE; + } + CameraDeviceBase::PhysicalCameraSettingsList newRequest = request; + int newReqID = mRequestIdCounter; + List<const CameraDeviceBase::PhysicalCameraSettingsList> settingsList; + std::list<SurfaceMap> surfaceMaps; + surfaceMaps.push_back(surfaceMap); + newRequest.begin()->metadata.update(ANDROID_REQUEST_ID, &newReqID, /*size*/1); + settingsList.push_back(newRequest); + mRequestIdCounter++; + status_t err = captureList(settingsList, surfaceMaps, lastFrameNumber); + if (err != OK) { + CLOGE("Cannot start shared capture request"); + return err; + } + *sharedReqID = newReqID; + + return err; +} + +status_t AidlCamera3SharedDevice::startStreaming(const int32_t reqId, const SurfaceMap& surfaceMap, + int32_t* sharedReqID, int64_t* lastFrameNumber) { + ATRACE_CALL(); + + if ((sharedReqID == nullptr) || (lastFrameNumber == nullptr)) { + return BAD_VALUE; + } + + Mutex::Autolock l(mSharedDeviceLock); + const sp<CaptureRequest> curRequest = getOngoingRepeatingRequestLocked(); + if (curRequest != nullptr) { + // If there is already repeating request ongoing, attach the surfaces to + // the request. + SurfaceMap newSurfaceMap = mergeSurfaceMaps(surfaceMap, curRequest->mOutputSurfaces); + updateOngoingRepeatingRequestLocked(newSurfaceMap); + *lastFrameNumber = getRepeatingRequestLastFrameNumberLocked(); + } else { + // If there is no ongoing repeating request, then send a default + // request with template preview. + std::vector<int32_t> outputStreamIds; + for (const auto& [key, value] : surfaceMap) { + outputStreamIds.push_back(key); + } + + CameraMetadata previewTemplate; + status_t err = createDefaultRequest(CAMERA_TEMPLATE_PREVIEW, &previewTemplate); + if (err != OK) { + ALOGE("%s: Failed to create default PREVIEW request: %s (%d)", + __FUNCTION__, strerror(-err), err); + return err; + } + int32_t requestID = mRequestIdCounter; + previewTemplate.update(ANDROID_REQUEST_ID, &requestID, /*size*/1); + mRequestIdCounter++; + previewTemplate.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0], + outputStreamIds.size()); + CameraDeviceBase::PhysicalCameraSettingsList previewSettings; + previewSettings.push_back({mId, previewTemplate}); + + List<const CameraDeviceBase::PhysicalCameraSettingsList> settingsList; + std::list<SurfaceMap> surfaceMaps; + settingsList.push_back(previewSettings); + surfaceMaps.push_back(surfaceMap); + err = setStreamingRequestList(settingsList, surfaceMaps, lastFrameNumber); + if (err != OK) { + CLOGE("Cannot start shared streaming request"); + return err; + } + mStreamingRequestId = requestID; + } + + int clientPid = mAttributionAndPermissionUtils->getCallingPid(); + mClientRequestIds[clientPid] = reqId; + mClientSurfaces[clientPid] = surfaceMap; + *sharedReqID = mStreamingRequestId; + return OK; +} + +status_t AidlCamera3SharedDevice::setNotifyCallback(wp<NotificationListener> listener) { + ATRACE_CALL(); + Mutex::Autolock l(mSharedDeviceLock); + + if (listener == NULL) { + return BAD_VALUE; + } + mClientListeners[mAttributionAndPermissionUtils->getCallingPid()] = listener; + return OK; +} + +void AidlCamera3SharedDevice::notifyError( + int32_t errorCode, + const CaptureResultExtras& resultExtras) { + for (auto clientListener : mClientListeners) { + sp<NotificationListener> listener = clientListener.second.promote(); + if (listener != NULL) { + listener->notifyError(errorCode, resultExtras); + } + } +} + +status_t AidlCamera3SharedDevice::notifyActive(float maxPreviewFps) { + Mutex::Autolock l(mSharedDeviceActiveLock); + for (auto activeClient : mClientRequestIds) { + sp<NotificationListener> listener = mClientListeners[activeClient.first].promote(); + if (listener != NULL) { + listener->notifyActive(maxPreviewFps); + } + } + + return OK; +} + +void AidlCamera3SharedDevice::notifyIdle(int64_t requestCount, int64_t resultErrorCount, + bool deviceError, + std::pair<int32_t, int32_t> mostRequestedFpsRange, + const std::vector<hardware::CameraStreamStats>& stats) { + Mutex::Autolock l(mSharedDeviceActiveLock); + for (auto clientListener : mClientListeners) { + sp<NotificationListener> listener = clientListener.second.promote(); + if (listener != NULL) { + listener->notifyIdle(requestCount, resultErrorCount, deviceError, mostRequestedFpsRange, + stats); + } + } +} + +void AidlCamera3SharedDevice::notifyShutter(const CaptureResultExtras& resultExtras, + nsecs_t timestamp) { + for (auto clientListener : mClientListeners) { + sp<NotificationListener> listener = clientListener.second.promote(); + if (listener != NULL) { + listener->notifyShutter(resultExtras, timestamp); + } + } +} + +}
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.h new file mode 100644 index 0000000..3886f59 --- /dev/null +++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3SharedDevice.h
@@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_AIDLCAMERA3SHAREDDEVICE_H +#define ANDROID_SERVERS_AIDLCAMERA3SHAREDDEVICE_H + +#include <camera/camera2/OutputConfiguration.h> +#include "common/FrameProcessorBase.h" +#include "../Camera3SharedOutputStream.h" +#include "AidlCamera3Device.h" +namespace android { + +/** + * Shared CameraDevice for AIDL HAL devices. + */ +using ::android::camera3::Camera3SharedOutputStream; +class AidlCamera3SharedDevice : + public AidlCamera3Device, + public NotificationListener { + public: + static sp<AidlCamera3SharedDevice> getInstance( + std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper, + std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils, + const std::string& id, bool overrideForPerfClass, int rotationOverride, + bool legacyClient = false); + status_t initialize(sp<CameraProviderManager> manager, + const std::string& monitorTags) override; + status_t disconnectClient(int clientPid) override; + status_t beginConfigure() override; + status_t getSharedStreamIds(const OutputStreamInfo &config, + std::vector<int>& streamIds) override; + status_t addSharedSurfaces(int streamId, + const std::vector<android::camera3::OutputStreamInfo> &outputInfo, + const std::vector<sp<Surface>>& surfaces, + std::vector<int> *surfaceIds = nullptr) override; + status_t removeSharedSurfaces(int streamId, + const std::vector<size_t> &surfaceIds) override; + status_t setSharedStreamingRequest(const PhysicalCameraSettingsList &request, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, int64_t *lastFrameNumber = NULL) + override; + status_t clearSharedStreamingRequest(int64_t *lastFrameNumber = NULL) override; + status_t setSharedCaptureRequest(const PhysicalCameraSettingsList &request, + const SurfaceMap &surfaceMap, int32_t *sharedReqID, int64_t *lastFrameNumber = NULL) + override; + sp<camera2::FrameProcessorBase> getSharedFrameProcessor() override {return mFrameProcessor;}; + status_t startStreaming(const int32_t reqId, const SurfaceMap &surfaceMap, + int32_t *sharedReqID, int64_t *lastFrameNumber = NULL); + + status_t setNotifyCallback(wp<NotificationListener> listener) override; + virtual void notifyError(int32_t errorCode, + const CaptureResultExtras &resultExtras) override; + virtual status_t notifyActive(float maxPreviewFps) override; + virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError, + std::pair<int32_t, int32_t> mostRequestedFpsRange, + const std::vector<hardware::CameraStreamStats>& streamStats) override; + virtual void notifyShutter(const CaptureResultExtras &resultExtras, + nsecs_t timestamp) override; + virtual void notifyRequestQueueEmpty() {}; + // Prepare api not supported for shared session + virtual void notifyPrepared(int /*streamId*/) {}; + // Required only for API1 + virtual void notifyAutoFocus(uint8_t /*newState*/, int /*triggerId*/) {}; + virtual void notifyAutoExposure(uint8_t /*newState*/, int /*triggerId*/) {}; + virtual void notifyAutoWhitebalance(uint8_t /*newState*/, + int /*triggerId*/) {}; + virtual void notifyRepeatingRequestError(long /*lastFrameNumber*/) {}; + private: + static std::map<std::string, sp<AidlCamera3SharedDevice>> sSharedDevices; + static std::map<std::string, std::unordered_set<int>> sClientsPid; + static Mutex sSharedClientsLock; + AidlCamera3SharedDevice( + std::shared_ptr<CameraServiceProxyWrapper>& cameraServiceProxyWrapper, + std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils, + const std::string& id, bool overrideForPerfClass, int rotationOverride, + bool legacyClient) + : AidlCamera3Device(cameraServiceProxyWrapper, attributionAndPermissionUtils, id, + overrideForPerfClass, rotationOverride, legacyClient), + mStreamingRequestId(REQUEST_ID_NONE), + mRequestIdCounter(0) {} + std::vector<OutputConfiguration> getSharedOutputConfiguration(); + std::vector<OutputConfiguration> mSharedOutputConfigurations; + std::vector<int> mSharedSurfaceIds; + std::vector<sp<Surface>> mSharedSurfaces; + std::vector<sp<BufferItemConsumer>> mOpaqueConsumers; + std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap; + // Streaming request ID + int32_t mStreamingRequestId; + static const int32_t REQUEST_ID_NONE = -1; + int32_t mRequestIdCounter; + std::unordered_map<int, int32_t> mClientRequestIds; + std::unordered_map<int, SurfaceMap> mClientSurfaces; + std::unordered_map<int, wp<NotificationListener>> mClientListeners; + SurfaceMap mergeSurfaceMaps(const SurfaceMap& map1, const SurfaceMap& map2); + SurfaceMap removeClientSurfaceMap(const SurfaceMap& map1, const SurfaceMap& map2); + Mutex mSharedDeviceLock; + sp<camera2::FrameProcessorBase> mFrameProcessor; +}; // class AidlCamera3SharedDevice +}; // namespace android +#endif
diff --git a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp index c1113e5..445db13 100644 --- a/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp +++ b/services/camera/libcameraservice/device3/deprecated/DeprecatedCamera3StreamSplitter.cpp
@@ -511,7 +511,8 @@ uint64_t bufferId; if (bufferItem.mGraphicBuffer != nullptr) { mInputSlots[bufferItem.mSlot] = bufferItem; - } else if (bufferItem.mAcquireCalled) { + } else if (bufferItem.mAcquireCalled + && (mInputSlots[bufferItem.mSlot].mGraphicBuffer != nullptr)) { bufferItem.mGraphicBuffer = mInputSlots[bufferItem.mSlot].mGraphicBuffer; mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber; } else {
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h index 152002b..98a0dbb 100644 --- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h +++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -86,6 +86,10 @@ mCaptureResultMetadataQueue = metadataQueue; } + virtual binder::Status onClientSharedAccessPriorityChanged(bool /*primaryClient*/) { + return binder::Status::ok(); + } + private: // Wrapper struct so that parameters to onResultReceived callback may be // sent through an AMessage.
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h index 78fca4e..b31ccc6 100644 --- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h +++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -72,6 +72,10 @@ // empty implementation return binder::Status::ok(); } + virtual binder::Status onCameraOpenedInSharedMode(const std::string& /*cameraId*/, + const std::string& /*clientPackageId*/, int32_t /*deviceId*/, bool /*primaryClient*/) { + return binder::Status::ok(); + } }; } // implementation
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp index 59e892f..9d140f2 100644 --- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp +++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -135,7 +135,7 @@ binder::Status serviceRet = mAidlICameraService->connectDevice( callbacks, cameraId, 0/*oomScoreOffset*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, /*out*/&deviceRemote); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, /*out*/&deviceRemote); HStatus status = HStatus::NO_ERROR; if (!serviceRet.isOk()) { ALOGE("%s: Unable to connect to camera device", __FUNCTION__);
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp index 12ac33f..c0c9182 100644 --- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp +++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -740,6 +740,13 @@ // No op return binder::Status::ok(); } + + virtual binder::Status onCameraOpenedInSharedMode(const std::string& /*cameraId*/, + const std::string& /*clientPackageName*/, int32_t /*deviceId*/, + bool /*isPrimaryClient*/) { + // No op + return binder::Status::ok(); + } }; class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks { @@ -780,6 +787,11 @@ virtual binder::Status onRequestQueueEmpty() { return binder::Status::ok(); } + + virtual binder::Status onClientSharedAccessPriorityChanged(bool /*isPrimaryClient*/) { + return binder::Status::ok(); + } + }; class Camera2Fuzzer { @@ -808,7 +820,7 @@ mCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT, - clientAttribution, /*devicePolicy*/0, &device); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &device); if (device == nullptr) { continue; }
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp index bbc10dc..50e43e6 100644 --- a/services/camera/libcameraservice/tests/Android.bp +++ b/services/camera/libcameraservice/tests/Android.bp
@@ -112,6 +112,7 @@ "Camera3StreamSplitterTest.cpp", "CameraPermissionsTest.cpp", "CameraProviderManagerTest.cpp", + "SharedSessionConfigUtilsTest.cpp", ], }
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp index 50aeaca..ff58c4a 100644 --- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp +++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -77,6 +77,13 @@ // No op return binder::Status::ok(); } + + virtual binder::Status onCameraOpenedInSharedMode(const std::string& /*cameraId*/, + const std::string& /*clientPackageName*/, int32_t /*deviceId*/, + bool /*isPrimaryClient*/) { + // No op + return binder::Status::ok(); + } }; // Empty device callback. @@ -118,6 +125,10 @@ virtual binder::Status onRequestQueueEmpty() { return binder::Status::ok(); } + + virtual binder::Status onClientSharedAccessPriorityChanged(bool /*isPrimaryClient*/) { + return binder::Status::ok(); + } }; // Override isCameraDisabled from the CameraServiceProxy with a flag. @@ -242,7 +253,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &device); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &device); AutoDisconnectDevice autoDisconnect(device); ASSERT_TRUE(!status.isOk()) << "connectDevice returned OK status"; ASSERT_EQ(status.serviceSpecificErrorCode(), hardware::ICameraService::ERROR_DISABLED) @@ -257,7 +268,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &device); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &device); AutoDisconnectDevice autoDisconnect(device); ASSERT_TRUE(status.isOk()); } @@ -281,7 +292,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &deviceA); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &deviceA); AutoDisconnectDevice autoDisconnectA(deviceA); ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() << " service specific error code " << status.serviceSpecificErrorCode(); @@ -289,7 +300,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &deviceB); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &deviceB); AutoDisconnectDevice autoDisconnectB(deviceB); ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() << " service specific error code " << status.serviceSpecificErrorCode(); @@ -315,7 +326,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 0/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &deviceA); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &deviceA); AutoDisconnectDevice autoDisconnectA(deviceA); ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() << " service specific error code " << status.serviceSpecificErrorCode(); @@ -323,7 +334,7 @@ sCameraService->connectDevice(callbacks, s.cameraId, 1/*oomScoreDiff*/, /*targetSdkVersion*/__ANDROID_API_FUTURE__, hardware::ICameraService::ROTATION_OVERRIDE_NONE, - clientAttribution, /*devicePolicy*/0, &deviceB); + clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, &deviceB); AutoDisconnectDevice autoDisconnectB(deviceB); ASSERT_TRUE(status.isOk()) << "Exception code " << status.exceptionCode() << " service specific error code " << status.serviceSpecificErrorCode();
diff --git a/services/camera/libcameraservice/tests/SharedSessionConfigUtilsTest.cpp b/services/camera/libcameraservice/tests/SharedSessionConfigUtilsTest.cpp new file mode 100644 index 0000000..b763e23 --- /dev/null +++ b/services/camera/libcameraservice/tests/SharedSessionConfigUtilsTest.cpp
@@ -0,0 +1,672 @@ +/* +* Copyright 2024 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#define LOG_TAG "SharedSessionConfigUtilsTest" + +#include <android/hardware_buffer.h> +#include <camera/camera2/OutputConfiguration.h> +#include <system/camera_metadata.h> +#include <system/graphics.h> + +#include <gtest/gtest.h> +#include "../config/SharedSessionConfigUtils.h" +#include <tinyxml2.h> + +using namespace android; +using namespace tinyxml2; + +// Helper function to create an XML element with text +XMLElement* CreateXMLElement(XMLDocument& doc, const char* elementName, const char* text) { + XMLElement* elem = doc.NewElement(elementName); + if (text != nullptr) { + elem->SetText(text); + } + doc.InsertEndChild(elem); + return elem; +} + +// Test for SharedSessionConfigUtils::toString +TEST(SharedSessionConfigUtilsTest, ToStringTest) { + EXPECT_STREQ(SharedSessionConfigUtils::toString(ErrorCode::STATUS_OK), "STATUS_OK"); + EXPECT_STREQ(SharedSessionConfigUtils::toString(ErrorCode::ERROR_READ_CONFIG_FILE), + "ERROR_READ_CONFIG_FILE"); + EXPECT_STREQ(SharedSessionConfigUtils::toString(ErrorCode::ERROR_CONFIG_FILE_FORMAT), + "ERROR_CONFIG_FILE_FORMAT"); + EXPECT_STREQ(SharedSessionConfigUtils::toString( + ErrorCode::ERROR_CONFIG_READER_UNINITIALIZED), + "ERROR_CONFIG_READER_UNINITIALIZED"); + EXPECT_STREQ(SharedSessionConfigUtils::toString(ErrorCode::ERROR_BAD_PARAMETER), + "ERROR_BAD_PARAMETER"); + + // Test default case (unknown ErrorCode) + EXPECT_STREQ(SharedSessionConfigUtils::toString(static_cast<ErrorCode>(999)), ""); +} + +// Test for SharedSessionConfigUtils::getColorSpaceFromStr +TEST(SharedSessionConfigUtilsTest, GetColorSpaceFromStrTest) { + int32_t colorSpace; + // Test with nullptr + EXPECT_EQ(SharedSessionConfigUtils::getColorSpaceFromStr(nullptr, &colorSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(colorSpace, ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED); + + // Test with empty string + EXPECT_EQ(SharedSessionConfigUtils::getColorSpaceFromStr("", &colorSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(colorSpace, ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED); + + // Test with valid strings + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED), + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED}, + {std::to_string(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB), + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB}, + {std::to_string(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3), + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3}, + {std::to_string(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020_HLG), + ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020_HLG} + }; + + for (const auto& testCase : testCases) { + EXPECT_EQ(SharedSessionConfigUtils::getColorSpaceFromStr(testCase.input.c_str(), + &colorSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(colorSpace, testCase.expected); + } + + // Test with invalid string + EXPECT_EQ(SharedSessionConfigUtils::getColorSpaceFromStr("-99", &colorSpace), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getSurfaceTypeFromXml +TEST(SharedSessionConfigUtilsTest, GetSurfaceTypeFromXmlTest) { + int64_t surfaceType; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getSurfaceTypeFromXml(nullptr, &surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with empty text + XMLDocument doc; + XMLElement* emptyElem = CreateXMLElement(doc, "surfaceType", ""); + EXPECT_EQ(SharedSessionConfigUtils::getSurfaceTypeFromXml(emptyElem, &surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with valid surface types + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW), + OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW}, + {std::to_string(OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE), + OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE}, + {std::to_string(OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER), + OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER}, + {std::to_string(OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC), + OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC}, + {std::to_string(OutputConfiguration::SURFACE_TYPE_IMAGE_READER), + OutputConfiguration::SURFACE_TYPE_IMAGE_READER} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "surfaceType", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getSurfaceTypeFromXml(elem, &surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(surfaceType, testCase.expected); + } + + // Test with invalid surface type + XMLElement* invalidElem = CreateXMLElement(doc, "surfaceType", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getSurfaceTypeFromXml(invalidElem, &surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getWidthFromXml +TEST(SharedSessionConfigUtilsTest, GetWidthFromXmlTest) { + int64_t width; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getWidthFromXml(nullptr, &width), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "width", ""); + EXPECT_EQ(SharedSessionConfigUtils::getWidthFromXml(emptyElem, &width), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with valid width + XMLElement* validElem = CreateXMLElement(doc, "width", "1920"); + EXPECT_EQ(SharedSessionConfigUtils::getWidthFromXml(validElem, &width), + ErrorCode::STATUS_OK); + EXPECT_EQ(width, 1920); + + // Test with invalid width (negative) + XMLElement* invalidWidthElem = CreateXMLElement(doc, "width", "-100"); + EXPECT_EQ(SharedSessionConfigUtils::getWidthFromXml(invalidWidthElem, &width), + ErrorCode::STATUS_OK); + EXPECT_EQ(width, -100); // The method logs an error but still returns STATUS_OK + + // Test with non-numeric width + XMLElement* nonNumericElem = CreateXMLElement(doc, "width", "abc"); + EXPECT_EQ(SharedSessionConfigUtils::getWidthFromXml(nonNumericElem, &width), + ErrorCode::STATUS_OK); + EXPECT_EQ(width, 0); // std::atoi returns 0 for non-numeric strings +} + +// Test for SharedSessionConfigUtils::getHeightFromXml +TEST(SharedSessionConfigUtilsTest, GetHeightFromXmlTest) { + int64_t height; + + XMLDocument doc; + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getHeightFromXml(nullptr, &height), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "height", ""); + EXPECT_EQ(SharedSessionConfigUtils::getHeightFromXml(emptyElem, &height), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with valid height + XMLElement* validElem = CreateXMLElement(doc, "height", "1080"); + EXPECT_EQ(SharedSessionConfigUtils::getHeightFromXml(validElem, &height), ErrorCode::STATUS_OK); + EXPECT_EQ(height, 1080); + + // Test with invalid height (zero) + XMLElement* invalidHeightElem = CreateXMLElement(doc, "height", "0"); + EXPECT_EQ(SharedSessionConfigUtils::getHeightFromXml(invalidHeightElem, &height), + ErrorCode::STATUS_OK); + EXPECT_EQ(height, 0); // The method logs an error but still returns STATUS_OK + + // Test with non-numeric height + XMLElement* nonNumericElem = CreateXMLElement(doc, "height", "xyz"); + EXPECT_EQ(SharedSessionConfigUtils::getHeightFromXml(nonNumericElem, &height), + ErrorCode::STATUS_OK); + EXPECT_EQ(height, 0); // std::atoi returns 0 for non-numeric strings +} + +// Test for SharedSessionConfigUtils::getPhysicalCameraIdFromXml +TEST(SharedSessionConfigUtilsTest, GetPhysicalCameraIdFromXmlTest) { + std::string physicalCameraId; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getPhysicalCameraIdFromXml(nullptr, &physicalCameraId), + ErrorCode::STATUS_OK); + EXPECT_EQ(physicalCameraId, ""); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "physicalCameraId", ""); + EXPECT_EQ(SharedSessionConfigUtils::getPhysicalCameraIdFromXml(emptyElem, &physicalCameraId), + ErrorCode::STATUS_OK); + EXPECT_EQ(physicalCameraId, ""); + + // Test with valid physical camera ID + XMLElement* validElem = CreateXMLElement(doc, "physicalCameraId", "physical_camera_1"); + EXPECT_EQ(SharedSessionConfigUtils::getPhysicalCameraIdFromXml(validElem, &physicalCameraId), + ErrorCode::STATUS_OK); + EXPECT_EQ(physicalCameraId, "physical_camera_1"); +} + +// Test for SharedSessionConfigUtils::getStreamUseCaseFromXml +TEST(SharedSessionConfigUtilsTest, GetStreamUseCaseFromXmlTest) { + int64_t streamUseCase; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getStreamUseCaseFromXml(nullptr, &streamUseCase), + ErrorCode::STATUS_OK); + EXPECT_EQ(streamUseCase, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "streamUseCase", ""); + EXPECT_EQ(SharedSessionConfigUtils::getStreamUseCaseFromXml(emptyElem, &streamUseCase), + ErrorCode::STATUS_OK); + EXPECT_EQ(streamUseCase, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT); + + // Test with valid stream use cases + struct { + std::string input; + int64_t expected; + } testCases[] = { + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW}, + {std::to_string(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START), + ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "streamUseCase", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getStreamUseCaseFromXml(elem, &streamUseCase), + ErrorCode::STATUS_OK); + EXPECT_EQ(streamUseCase, testCase.expected); + } + + // Test with invalid stream use case + XMLElement* invalidElem = CreateXMLElement(doc, "streamUseCase", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getStreamUseCaseFromXml(invalidElem, &streamUseCase), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getTimestampBaseFromXml +TEST(SharedSessionConfigUtilsTest, GetTimestampBaseFromXmlTest) { + int64_t timestampBase; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getTimestampBaseFromXml(nullptr, ×tampBase), + ErrorCode::STATUS_OK); + EXPECT_EQ(timestampBase, OutputConfiguration::TIMESTAMP_BASE_DEFAULT); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "timestampBase", ""); + EXPECT_EQ(SharedSessionConfigUtils::getTimestampBaseFromXml(emptyElem, ×tampBase), + ErrorCode::STATUS_OK); + EXPECT_EQ(timestampBase, OutputConfiguration::TIMESTAMP_BASE_DEFAULT); + + // Test with valid timestamp bases + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_DEFAULT), + OutputConfiguration::TIMESTAMP_BASE_DEFAULT}, + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_SENSOR), + OutputConfiguration::TIMESTAMP_BASE_SENSOR}, + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_MONOTONIC), + OutputConfiguration::TIMESTAMP_BASE_MONOTONIC}, + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_REALTIME), + OutputConfiguration::TIMESTAMP_BASE_REALTIME}, + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED), + OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED}, + {std::to_string(OutputConfiguration::TIMESTAMP_BASE_MAX), + OutputConfiguration::TIMESTAMP_BASE_MAX} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "timestampBase", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getTimestampBaseFromXml(elem, ×tampBase), + ErrorCode::STATUS_OK); + EXPECT_EQ(timestampBase, testCase.expected); + } + + // Test with invalid timestamp base + XMLElement* invalidElem = CreateXMLElement(doc, "timestampBase", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getTimestampBaseFromXml(invalidElem, ×tampBase), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getMirrorModeFromXml +TEST(SharedSessionConfigUtilsTest, GetMirrorModeFromXmlTest) { + int64_t mirrorMode; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getMirrorModeFromXml(nullptr, &mirrorMode), + ErrorCode::STATUS_OK); + EXPECT_EQ(mirrorMode, OutputConfiguration::MIRROR_MODE_AUTO); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "mirrorMode", ""); + EXPECT_EQ(SharedSessionConfigUtils::getMirrorModeFromXml(emptyElem, &mirrorMode), + ErrorCode::STATUS_OK); + EXPECT_EQ(mirrorMode, OutputConfiguration::MIRROR_MODE_AUTO); + + // Test with valid mirror modes + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(OutputConfiguration::MIRROR_MODE_AUTO), + OutputConfiguration::MIRROR_MODE_AUTO}, + {std::to_string(OutputConfiguration::MIRROR_MODE_NONE), + OutputConfiguration::MIRROR_MODE_NONE}, + {std::to_string(OutputConfiguration::MIRROR_MODE_H), + OutputConfiguration::MIRROR_MODE_H}, + {std::to_string(OutputConfiguration::MIRROR_MODE_V), + OutputConfiguration::MIRROR_MODE_V} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "mirrorMode", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getMirrorModeFromXml(elem, &mirrorMode), + ErrorCode::STATUS_OK); + EXPECT_EQ(mirrorMode, testCase.expected); + } + + // Test with invalid mirror mode + XMLElement* invalidElem = CreateXMLElement(doc, "mirrorMode", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getMirrorModeFromXml(invalidElem, &mirrorMode), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getUseReadoutTimestampFromXml +TEST(SharedSessionConfigUtilsTest, GetUseReadoutTimestampFromXmlTest) { + bool useReadoutTimestamp; + + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getUseReadoutTimestampFromXml(nullptr, + &useReadoutTimestamp), + ErrorCode::STATUS_OK); + EXPECT_FALSE(useReadoutTimestamp); + + XMLDocument doc; + // Test with empty text (should default to false) + XMLElement* emptyElem = CreateXMLElement(doc, "useReadoutTimestamp", ""); + EXPECT_EQ(SharedSessionConfigUtils::getUseReadoutTimestampFromXml(emptyElem, + &useReadoutTimestamp), + ErrorCode::STATUS_OK); + EXPECT_FALSE(useReadoutTimestamp); + + // Test with "true" + XMLElement* trueElem = CreateXMLElement(doc, "useReadoutTimestamp", "1"); + EXPECT_EQ(SharedSessionConfigUtils::getUseReadoutTimestampFromXml(trueElem, + &useReadoutTimestamp), + ErrorCode::STATUS_OK); + EXPECT_TRUE(useReadoutTimestamp); + + // Test with "false" + XMLElement* falseElem = CreateXMLElement(doc, "useReadoutTimestamp", "0"); + EXPECT_EQ(SharedSessionConfigUtils::getUseReadoutTimestampFromXml(falseElem, + &useReadoutTimestamp), + ErrorCode::STATUS_OK); + EXPECT_FALSE(useReadoutTimestamp); + + // Test with invalid string + XMLElement* invalidElem = CreateXMLElement(doc, "useReadoutTimestamp", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getUseReadoutTimestampFromXml(invalidElem, + &useReadoutTimestamp), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getFormatFromXml +TEST(SharedSessionConfigUtilsTest, GetFormatFromXmlTest) { + int64_t format; + + int64_t surfaceType = OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE; + // Test with nullptr XML element with surfaceType != IMAGE_READER + EXPECT_EQ(SharedSessionConfigUtils::getFormatFromXml(nullptr, &format, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(format, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED); + + surfaceType = OutputConfiguration::SURFACE_TYPE_IMAGE_READER; + // Test with nullptr XML element with surfaceType == IMAGE_READER + EXPECT_EQ(SharedSessionConfigUtils::getFormatFromXml(nullptr, &format, surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "format", ""); + EXPECT_EQ(SharedSessionConfigUtils::getFormatFromXml(emptyElem, &format, surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // Test with valid formats + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(HAL_PIXEL_FORMAT_RGBA_8888), HAL_PIXEL_FORMAT_RGBA_8888}, + {std::to_string(HAL_PIXEL_FORMAT_RGBX_8888), HAL_PIXEL_FORMAT_RGBX_8888}, + {std::to_string(HAL_PIXEL_FORMAT_RGB_888), HAL_PIXEL_FORMAT_RGB_888}, + {std::to_string(HAL_PIXEL_FORMAT_RGB_565), HAL_PIXEL_FORMAT_RGB_565}, + {std::to_string(HAL_PIXEL_FORMAT_BGRA_8888), HAL_PIXEL_FORMAT_BGRA_8888}, + {std::to_string(HAL_PIXEL_FORMAT_YCBCR_422_SP), HAL_PIXEL_FORMAT_YCBCR_422_SP}, + {std::to_string(HAL_PIXEL_FORMAT_YCRCB_420_SP), HAL_PIXEL_FORMAT_YCRCB_420_SP}, + {std::to_string(HAL_PIXEL_FORMAT_YCBCR_422_I), HAL_PIXEL_FORMAT_YCBCR_422_I}, + {std::to_string(HAL_PIXEL_FORMAT_RGBA_FP16), HAL_PIXEL_FORMAT_RGBA_FP16}, + {std::to_string(HAL_PIXEL_FORMAT_RAW16), HAL_PIXEL_FORMAT_RAW16}, + {std::to_string(HAL_PIXEL_FORMAT_BLOB), HAL_PIXEL_FORMAT_BLOB}, + {std::to_string(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}, + {std::to_string(HAL_PIXEL_FORMAT_YCBCR_420_888), HAL_PIXEL_FORMAT_YCBCR_420_888}, + {std::to_string(HAL_PIXEL_FORMAT_RAW_OPAQUE), HAL_PIXEL_FORMAT_RAW_OPAQUE}, + {std::to_string(HAL_PIXEL_FORMAT_RAW10), HAL_PIXEL_FORMAT_RAW10}, + {std::to_string(HAL_PIXEL_FORMAT_RAW12), HAL_PIXEL_FORMAT_RAW12}, + {std::to_string(HAL_PIXEL_FORMAT_RGBA_1010102), HAL_PIXEL_FORMAT_RGBA_1010102}, + {std::to_string(HAL_PIXEL_FORMAT_Y8), HAL_PIXEL_FORMAT_Y8}, + {std::to_string(HAL_PIXEL_FORMAT_Y16), HAL_PIXEL_FORMAT_Y16}, + {std::to_string(HAL_PIXEL_FORMAT_YV12), HAL_PIXEL_FORMAT_YV12}, + {std::to_string(HAL_PIXEL_FORMAT_DEPTH_16), HAL_PIXEL_FORMAT_DEPTH_16}, + {std::to_string(HAL_PIXEL_FORMAT_DEPTH_24), HAL_PIXEL_FORMAT_DEPTH_24}, + {std::to_string(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8), + HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8}, + {std::to_string(HAL_PIXEL_FORMAT_DEPTH_32F), HAL_PIXEL_FORMAT_DEPTH_32F}, + {std::to_string(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8), + HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8}, + {std::to_string(HAL_PIXEL_FORMAT_STENCIL_8), HAL_PIXEL_FORMAT_STENCIL_8}, + {std::to_string(HAL_PIXEL_FORMAT_YCBCR_P010), HAL_PIXEL_FORMAT_YCBCR_P010}, + {std::to_string(HAL_PIXEL_FORMAT_HSV_888), HAL_PIXEL_FORMAT_HSV_888} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "format", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getFormatFromXml(elem, &format, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(format, testCase.expected); + } + + // Test with invalid format + XMLElement* invalidElem = CreateXMLElement(doc, "format", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getFormatFromXml(invalidElem, &format, surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getUsageFromXml +TEST(SharedSessionConfigUtilsTest, GetUsageFromXmlTest) { + int64_t usage = 0; + + int64_t surfaceType = OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE; + // Test with nullptr XML element with surfaceType == SURFACE_TYPE_SURFACE_TEXTURE + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(nullptr, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE)); + + // clear usage value + usage = 0; + surfaceType = OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW; + // Test with nullptr XML element with surfaceType == SURFACE_TYPE_SURFACE_VIEW + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(nullptr, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE + | AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY)); + + // clear usage value + usage = 0; + surfaceType = OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER; + // Test with nullptr XML element with surfaceType == SURFACE_TYPE_MEDIA_RECORDER + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(nullptr, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_VIDEO_ENCODE)); + + // clear usage value + usage = 0; + surfaceType = OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC; + // Test with nullptr XML element with surfaceType == SURFACE_TYPE_MEDIA_CODEC + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(nullptr, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_VIDEO_ENCODE)); + + // clear usage value + usage = 0; + surfaceType = OutputConfiguration::SURFACE_TYPE_IMAGE_READER; + // Test with nullptr XML element with surfaceType == IMAGE_READER + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(nullptr, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER)); + + + // clear usage value + usage = 0; + XMLDocument doc; + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "usage", ""); + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(emptyElem, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER)); + + // clear usage value + usage = 0; + // Test with valid single usage + XMLElement* singleUsageElem = CreateXMLElement(doc, "usage", + std::to_string( + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) + .c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(singleUsageElem, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN)); + + // clear usage value + usage = 0; + // Test with valid multiple usages + XMLElement* multipleUsagesElem = + CreateXMLElement(doc, "usage", + (std::to_string(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER) + + "|" + std::to_string(AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) + + "|" + std::to_string(AHARDWAREBUFFER_USAGE_VIDEO_ENCODE)) + .c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(multipleUsagesElem, &usage, surfaceType), + ErrorCode::STATUS_OK); + EXPECT_EQ(usage, static_cast<int64_t>(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER + | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER + | AHARDWAREBUFFER_USAGE_VIDEO_ENCODE)); + + // clear usage value + usage = 0; + // Test with invalid usage + XMLElement* invalidUsageElem = CreateXMLElement(doc, "usage", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(invalidUsageElem, &usage, surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); + + // clear usage value + usage = 0; + // Test with a mix of valid and invalid usages + XMLElement* mixedUsageElem = + CreateXMLElement(doc, "usage", + (std::to_string(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER) + "|-99") + .c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getUsageFromXml(mixedUsageElem, &usage, surfaceType), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +} + +// Test for SharedSessionConfigUtils::getDataSpaceFromXml +TEST(SharedSessionConfigUtilsTest, GetDataSpaceFromXmlTest) { + int64_t dataSpace; + + XMLDocument doc; + // Test with nullptr XML element + EXPECT_EQ(SharedSessionConfigUtils::getDataSpaceFromXml(nullptr, &dataSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(dataSpace, HAL_DATASPACE_UNKNOWN); + + // Test with empty text + XMLElement* emptyElem = CreateXMLElement(doc, "dataSpace", ""); + EXPECT_EQ(SharedSessionConfigUtils::getDataSpaceFromXml(emptyElem, &dataSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(dataSpace, HAL_DATASPACE_UNKNOWN); + + // Test with valid data spaces + struct { + std::string input; + int expected; + } testCases[] = { + {std::to_string(HAL_DATASPACE_UNKNOWN), HAL_DATASPACE_UNKNOWN}, + {std::to_string(HAL_DATASPACE_ARBITRARY), HAL_DATASPACE_ARBITRARY}, + {std::to_string(HAL_DATASPACE_STANDARD_UNSPECIFIED), + HAL_DATASPACE_STANDARD_UNSPECIFIED}, + {std::to_string(HAL_DATASPACE_STANDARD_BT709), HAL_DATASPACE_STANDARD_BT709}, + {std::to_string(HAL_DATASPACE_STANDARD_BT601_625), HAL_DATASPACE_STANDARD_BT601_625}, + {std::to_string(HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED), + HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED}, + {std::to_string(HAL_DATASPACE_STANDARD_BT601_525), HAL_DATASPACE_STANDARD_BT601_525}, + {std::to_string(HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED), + HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED}, + {std::to_string(HAL_DATASPACE_STANDARD_BT2020), HAL_DATASPACE_STANDARD_BT2020}, + {std::to_string(HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE), + HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE}, + {std::to_string(HAL_DATASPACE_STANDARD_BT470M), HAL_DATASPACE_STANDARD_BT470M}, + {std::to_string(HAL_DATASPACE_STANDARD_FILM), HAL_DATASPACE_STANDARD_FILM}, + {std::to_string(HAL_DATASPACE_STANDARD_DCI_P3), HAL_DATASPACE_STANDARD_DCI_P3}, + {std::to_string(HAL_DATASPACE_STANDARD_ADOBE_RGB), HAL_DATASPACE_STANDARD_ADOBE_RGB}, + {std::to_string(HAL_DATASPACE_TRANSFER_UNSPECIFIED), + HAL_DATASPACE_TRANSFER_UNSPECIFIED}, + {std::to_string(HAL_DATASPACE_TRANSFER_LINEAR), HAL_DATASPACE_TRANSFER_LINEAR}, + {std::to_string(HAL_DATASPACE_TRANSFER_SRGB), HAL_DATASPACE_TRANSFER_SRGB}, + {std::to_string(HAL_DATASPACE_TRANSFER_SMPTE_170M), HAL_DATASPACE_TRANSFER_SMPTE_170M}, + {std::to_string(HAL_DATASPACE_TRANSFER_GAMMA2_2), HAL_DATASPACE_TRANSFER_GAMMA2_2}, + {std::to_string(HAL_DATASPACE_TRANSFER_GAMMA2_6), HAL_DATASPACE_TRANSFER_GAMMA2_6}, + {std::to_string(HAL_DATASPACE_TRANSFER_GAMMA2_8), HAL_DATASPACE_TRANSFER_GAMMA2_8}, + {std::to_string(HAL_DATASPACE_TRANSFER_ST2084), HAL_DATASPACE_TRANSFER_ST2084}, + {std::to_string(HAL_DATASPACE_TRANSFER_HLG), HAL_DATASPACE_TRANSFER_HLG}, + {std::to_string(HAL_DATASPACE_RANGE_UNSPECIFIED), HAL_DATASPACE_RANGE_UNSPECIFIED}, + {std::to_string(HAL_DATASPACE_RANGE_FULL), HAL_DATASPACE_RANGE_FULL}, + {std::to_string(HAL_DATASPACE_RANGE_LIMITED), HAL_DATASPACE_RANGE_LIMITED}, + {std::to_string(HAL_DATASPACE_RANGE_EXTENDED), HAL_DATASPACE_RANGE_EXTENDED}, + {std::to_string(HAL_DATASPACE_SRGB_LINEAR), HAL_DATASPACE_SRGB_LINEAR}, + {std::to_string(HAL_DATASPACE_V0_SRGB_LINEAR), HAL_DATASPACE_V0_SRGB_LINEAR}, + {std::to_string(HAL_DATASPACE_V0_SCRGB_LINEAR), HAL_DATASPACE_V0_SCRGB_LINEAR}, + {std::to_string(HAL_DATASPACE_SRGB), HAL_DATASPACE_SRGB}, + {std::to_string(HAL_DATASPACE_V0_SRGB), HAL_DATASPACE_V0_SRGB}, + {std::to_string(HAL_DATASPACE_V0_SCRGB), HAL_DATASPACE_V0_SCRGB}, + {std::to_string(HAL_DATASPACE_JFIF), HAL_DATASPACE_JFIF}, + {std::to_string(HAL_DATASPACE_V0_JFIF), HAL_DATASPACE_V0_JFIF}, + {std::to_string(HAL_DATASPACE_BT601_625), HAL_DATASPACE_BT601_625}, + {std::to_string(HAL_DATASPACE_V0_BT601_625), HAL_DATASPACE_V0_BT601_625}, + {std::to_string(HAL_DATASPACE_BT601_525), HAL_DATASPACE_BT601_525}, + {std::to_string(HAL_DATASPACE_V0_BT601_525), HAL_DATASPACE_V0_BT601_525}, + {std::to_string(HAL_DATASPACE_BT709), HAL_DATASPACE_BT709}, + {std::to_string(HAL_DATASPACE_V0_BT709), HAL_DATASPACE_V0_BT709}, + {std::to_string(HAL_DATASPACE_DCI_P3_LINEAR), HAL_DATASPACE_DCI_P3_LINEAR}, + {std::to_string(HAL_DATASPACE_DCI_P3), HAL_DATASPACE_DCI_P3}, + {std::to_string(HAL_DATASPACE_DISPLAY_P3_LINEAR), HAL_DATASPACE_DISPLAY_P3_LINEAR}, + {std::to_string(HAL_DATASPACE_DISPLAY_P3), HAL_DATASPACE_DISPLAY_P3}, + {std::to_string(HAL_DATASPACE_ADOBE_RGB), HAL_DATASPACE_ADOBE_RGB}, + {std::to_string(HAL_DATASPACE_BT2020_LINEAR), HAL_DATASPACE_BT2020_LINEAR}, + {std::to_string(HAL_DATASPACE_BT2020), HAL_DATASPACE_BT2020}, + {std::to_string(HAL_DATASPACE_BT2020_PQ), HAL_DATASPACE_BT2020_PQ}, + {std::to_string(HAL_DATASPACE_DEPTH), HAL_DATASPACE_DEPTH}, + {std::to_string(HAL_DATASPACE_SENSOR), HAL_DATASPACE_SENSOR} + }; + + for (const auto& testCase : testCases) { + XMLElement* elem = CreateXMLElement(doc, "dataSpace", testCase.input.c_str()); + EXPECT_EQ(SharedSessionConfigUtils::getDataSpaceFromXml(elem, &dataSpace), + ErrorCode::STATUS_OK); + EXPECT_EQ(dataSpace, testCase.expected); + } + + // Test with invalid data space + XMLElement* invalidElem = CreateXMLElement(doc, "dataSpace", "-99"); + EXPECT_EQ(SharedSessionConfigUtils::getDataSpaceFromXml(invalidElem, &dataSpace), + ErrorCode::ERROR_CONFIG_FILE_FORMAT); +}
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h index 074c84d..8358b10 100644 --- a/services/camera/libcameraservice/utils/ClientManager.h +++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -20,6 +20,7 @@ #include <utils/Condition.h> #include <utils/Mutex.h> #include <utils/Timers.h> +#include <utils/Log.h> #include <algorithm> #include <utility> @@ -27,6 +28,9 @@ #include <set> #include <map> #include <memory> +#include <com_android_internal_camera_flags.h> + +namespace flags = com::android::internal::camera::flags; namespace android { namespace resource_policy { @@ -142,10 +146,10 @@ public: ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, - bool isVendorClient, int32_t oomScoreOffset); + bool isVendorClient, int32_t oomScoreOffset, bool sharedMode = false); ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, bool isVendorClient, - int32_t oomScoreOffset); + int32_t oomScoreOffset, bool sharedMode = false); ~ClientDescriptor(); @@ -189,6 +193,11 @@ */ void setPriority(const ClientPriority& priority); + /** + * Returns true when camera is opened in shared mode. + */ + bool getSharedMode() const; + // This class is ordered by key template<class K, class V> friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b); @@ -200,6 +209,7 @@ std::set<KEY> mConflicting; ClientPriority mPriority; int32_t mOwnerId; + bool mSharedMode; }; // class ClientDescriptor template<class K, class V> @@ -210,18 +220,19 @@ template<class KEY, class VALUE> ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, - bool isVendorClient, int32_t scoreOffset) : + bool isVendorClient, int32_t scoreOffset, bool sharedMode) : mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys}, mPriority(score, state, isVendorClient, scoreOffset), - mOwnerId{ownerId} {} + mOwnerId{ownerId}, mSharedMode{sharedMode} {} template<class KEY, class VALUE> ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state, - bool isVendorClient, int32_t scoreOffset) : + bool isVendorClient, int32_t scoreOffset, bool sharedMode) : mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost}, mConflicting{std::forward<std::set<KEY>>(conflictingKeys)}, - mPriority(score, state, isVendorClient, scoreOffset), mOwnerId{ownerId} {} + mPriority(score, state, isVendorClient, scoreOffset), mOwnerId{ownerId}, + mSharedMode{sharedMode} {} template<class KEY, class VALUE> ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {} @@ -253,7 +264,10 @@ template<class KEY, class VALUE> bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const { - if (key == mKey) return true; + // In shared mode, there can be more than one client using the camera. + // Hence, having more than one client with the same key is not considered as + // conflicting. + if (!mSharedMode && key == mKey) return true; for (const auto& x : mConflicting) { if (key == x) return true; } @@ -266,6 +280,11 @@ } template<class KEY, class VALUE> +bool ClientDescriptor<KEY, VALUE>::getSharedMode() const { + return mSharedMode; +} + +template<class KEY, class VALUE> void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) { // We don't use the usual copy constructor here since we want to remember // whether a client is a vendor client or not. This could have been wiped @@ -349,14 +368,19 @@ void removeAll(); /** - * Remove and return the ClientDescriptor with a given key. + * Remove all ClientDescriptors with a given key. + */ + std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> removeAll(const KEY& key); + + /** + * Remove and return the ClientDescriptors with a given key. */ std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key); /** * Remove the given ClientDescriptor. */ - void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value); + virtual void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value); /** * Return a vector of the ClientDescriptors that would be evicted by adding the given @@ -390,11 +414,19 @@ std::vector<int32_t> getAllOwners() const; /** + * Return the ClientDescriptor for a client which has opened the camera in + * shared mode corresponding to the given pid. + */ + std::shared_ptr<ClientDescriptor<KEY, VALUE>> getSharedClient(int pid) const; + + /** * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer * if none exists. */ std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const; + std::shared_ptr<ClientDescriptor<KEY, VALUE>> getPrimaryClient(const KEY& key) const; + /** * Block until the given client is no longer in the active clients list, or the timeout * occurred. @@ -495,6 +527,8 @@ int32_t cost = client->getCost(); ClientPriority priority = client->getPriority(); int32_t owner = client->getOwnerId(); + bool sharedMode = client->getSharedMode(); + int64_t totalCost = getCurrentCostLocked() + cost; @@ -520,9 +554,10 @@ int32_t curCost = i->getCost(); ClientPriority curPriority = i->getPriority(); int32_t curOwner = i->getOwnerId(); - - bool conflicting = (curKey == key || i->isConflicting(key) || - client->isConflicting(curKey)); + bool curSharedMode = i->getSharedMode(); + bool conflicting; + conflicting = (((!sharedMode || !curSharedMode) && curKey == key) + || i->isConflicting(key) || client->isConflicting(curKey)); if (!returnIncompatibleClients) { // Find evicted clients @@ -647,6 +682,18 @@ } template<class KEY, class VALUE, class LISTENER> +std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::getSharedClient( + int pid) const { + Mutex::Autolock lock(mLock); + for (const auto& i : mClients) { + if ((i->getOwnerId() == pid) && (i->getSharedMode())) { + return i; + } + } + return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr); +} + +template<class KEY, class VALUE, class LISTENER> void ClientManager<KEY, VALUE, LISTENER>::updatePriorities( const std::map<int32_t,ClientPriority>& ownerPriorityList) { Mutex::Autolock lock(mLock); @@ -669,6 +716,23 @@ } template<class KEY, class VALUE, class LISTENER> +std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::getPrimaryClient( + const KEY& key) const { + Mutex::Autolock lock(mLock); + for (const auto& i : mClients) { + bool sharedMode = i->getSharedMode(); + bool primaryClient; + status_t ret = i->getValue()->isPrimaryClient(&primaryClient); + if (ret == OK) { + if ((i->getKey() == key) && sharedMode && primaryClient) { + return i; + } + } + } + return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr); +} + +template<class KEY, class VALUE, class LISTENER> void ClientManager<KEY, VALUE, LISTENER>::removeAll() { Mutex::Autolock lock(mLock); if (mListener != nullptr) { @@ -681,6 +745,25 @@ } template<class KEY, class VALUE, class LISTENER> +std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> + ClientManager<KEY, VALUE, LISTENER>::removeAll(const KEY& key) { + Mutex::Autolock lock(mLock); + std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> clients; + for (auto it = mClients.begin(); it != mClients.end();) + { + if ((*it)->getKey() == key) { + if (mListener != nullptr) mListener->onClientRemoved(**it); + clients.push_back(*it); + it = mClients.erase(it); + } else { + ++it; + } + } + mRemovedCondition.broadcast(); + return clients; +} + +template<class KEY, class VALUE, class LISTENER> std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove( const KEY& key) { Mutex::Autolock lock(mLock);