From 2bbdce4e9b9d36ebd6fac699cbefe33c773558fe Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Sun, 12 Jan 2020 14:55:41 -0800 Subject: [PATCH] ICameraService: Add methods to query concurrent streaming camera support. - getConcurrentStreamingCameraIds() : returns a list of combinations of camera ids that may stream concurrently. - isConcurrentSessionConfigurationSupported() : queries whether camera devices can support the corresponding given session configurations concurrently. Bug: 77960042 Test: GCA (sanity) Test: CTS Change-Id: Iba237118ccf145695a500a2c406713e416e66011 Signed-off-by: Jayant Chowdhary --- camera/Android.bp | 3 +- .../aidl/android/hardware/ICameraService.aidl | 21 ++ .../CameraIdAndSessionConfiguration.aidl | 20 ++ .../utils/ConcurrentCameraIdCombination.aidl | 20 ++ camera/camera2/ConcurrentCamera.cpp | 129 ++++++++++ .../include/camera/camera2/ConcurrentCamera.h | 56 +++++ services/camera/libcameraservice/Android.bp | 3 +- .../camera/libcameraservice/CameraService.cpp | 80 ++++++ .../camera/libcameraservice/CameraService.h | 9 + .../api2/CameraDeviceClient.cpp | 180 +++++++------ .../api2/CameraDeviceClient.h | 29 ++- .../common/CameraProviderManager.cpp | 236 +++++++++++++++++- .../common/CameraProviderManager.h | 27 ++ .../camera/libcameraservice/tests/Android.mk | 4 +- .../utils/SessionConfigurationUtils.cpp | 33 +++ .../utils/SessionConfigurationUtils.h | 47 ++++ 16 files changed, 805 insertions(+), 92 deletions(-) create mode 100644 camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl create mode 100644 camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl create mode 100644 camera/camera2/ConcurrentCamera.cpp create mode 100644 camera/include/camera/camera2/ConcurrentCamera.h create mode 100644 services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp create mode 100644 services/camera/libcameraservice/utils/SessionConfigurationUtils.h diff --git a/camera/Android.bp b/camera/Android.bp index ea7259a6dc..fa36bb31b1 100644 --- a/camera/Android.bp +++ b/camera/Android.bp @@ -40,6 +40,7 @@ cc_library_shared { "ICameraRecordingProxy.cpp", "ICameraRecordingProxyListener.cpp", "camera2/CaptureRequest.cpp", + "camera2/ConcurrentCamera.cpp", "camera2/OutputConfiguration.cpp", "camera2/SessionConfiguration.cpp", "camera2/SubmitInfo.cpp", @@ -66,7 +67,7 @@ cc_library_shared { "include", "include/camera" ], - export_shared_lib_headers: ["libcamera_metadata"], + export_shared_lib_headers: ["libcamera_metadata", "libnativewindow", "libgui"], cflags: [ "-Werror", diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl index 62dbb5e29a..833893e1e4 100644 --- a/camera/aidl/android/hardware/ICameraService.aidl +++ b/camera/aidl/android/hardware/ICameraService.aidl @@ -22,6 +22,8 @@ import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.params.VendorTagDescriptor; import android.hardware.camera2.params.VendorTagDescriptorCache; +import android.hardware.camera2.utils.ConcurrentCameraIdCombination; +import android.hardware.camera2.utils.CameraIdAndSessionConfiguration; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.ICameraServiceListener; import android.hardware.CameraInfo; @@ -113,6 +115,25 @@ interface ICameraService */ CameraStatus[] addListener(ICameraServiceListener listener); + /** + * Get a list of combinations of camera ids which support concurrent streaming. + * + */ + ConcurrentCameraIdCombination[] getConcurrentStreamingCameraIds(); + + /** + * Check whether a particular set of session configurations are concurrently supported by the + * corresponding camera ids. + * + * @param sessions the set of camera id and session configuration pairs to be queried. + * @return true - the set of concurrent camera id and stream combinations is supported. + * false - the set of concurrent camera id and stream combinations is not supported + * OR the method was called with a set of camera ids not returned by + * getConcurrentMultiStreamingCameraIds(). + */ + boolean isConcurrentSessionConfigurationSupported( + in CameraIdAndSessionConfiguration[] sessions); + /** * Remove listener for changes to camera device and flashlight state. */ diff --git a/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl b/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl new file mode 100644 index 0000000000..ca89ad82cd --- /dev/null +++ b/camera/aidl/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.camera2.utils; + +/** @hide */ +parcelable CameraIdAndSessionConfiguration cpp_header "camera/camera2/ConcurrentCamera.h"; diff --git a/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl b/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl new file mode 100644 index 0000000000..4b35c314e4 --- /dev/null +++ b/camera/aidl/android/hardware/camera2/utils/ConcurrentCameraIdCombination.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.camera2.utils; + +/** @hide */ +parcelable ConcurrentCameraIdCombination cpp_header "camera/camera2/ConcurrentCamera.h"; diff --git a/camera/camera2/ConcurrentCamera.cpp b/camera/camera2/ConcurrentCamera.cpp new file mode 100644 index 0000000000..01a695c979 --- /dev/null +++ b/camera/camera2/ConcurrentCamera.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 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_NDEBUG 0 +#define LOG_TAG "ConcurrentCamera" +#include +#include + +#include + +#include + +namespace android { +namespace hardware { +namespace camera2 { +namespace utils { + +ConcurrentCameraIdCombination::ConcurrentCameraIdCombination() = default; + +ConcurrentCameraIdCombination::ConcurrentCameraIdCombination( + std::vector &&combination) : mConcurrentCameraIds(std::move(combination)) { } + +ConcurrentCameraIdCombination::~ConcurrentCameraIdCombination() = default; + +status_t ConcurrentCameraIdCombination::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + status_t err = OK; + mConcurrentCameraIds.clear(); + int32_t cameraIdCount = 0; + if ((err = parcel->readInt32(&cameraIdCount)) != OK) { + ALOGE("%s: Failed to read the camera id count from parcel: %d", __FUNCTION__, err); + return err; + } + for (int32_t i = 0; i < cameraIdCount; i++) { + String16 id; + if ((err = parcel->readString16(&id)) != OK) { + ALOGE("%s: Failed to read camera id!", __FUNCTION__); + return err; + } + mConcurrentCameraIds.push_back(std::string(String8(id).string())); + } + return OK; +} + +status_t ConcurrentCameraIdCombination::writeToParcel(android::Parcel* parcel) const { + + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + status_t err = OK; + + if ((err = parcel->writeInt32(mConcurrentCameraIds.size())) != OK) { + ALOGE("%s: Failed to write the camera id count to parcel: %d", __FUNCTION__, err); + return err; + } + + for (const auto &it : mConcurrentCameraIds) { + if ((err = parcel->writeString16(String16(it.c_str()))) != OK) { + ALOGE("%s: Failed to write the camera id string to parcel: %d", __FUNCTION__, err); + return err; + } + } + return OK; +} + +CameraIdAndSessionConfiguration::CameraIdAndSessionConfiguration() = default; +CameraIdAndSessionConfiguration::~CameraIdAndSessionConfiguration() = default; + +status_t CameraIdAndSessionConfiguration::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + status_t err = OK; + String16 id; + if ((err = parcel->readString16(&id)) != OK) { + ALOGE("%s: Failed to read camera id!", __FUNCTION__); + return err; + } + if ((err = mSessionConfiguration.readFromParcel(parcel)) != OK) { + ALOGE("%s: Failed to read sessionConfiguration!", __FUNCTION__); + return err; + } + mCameraId = std::string(String8(id).string()); + return OK; +} + +status_t CameraIdAndSessionConfiguration::writeToParcel(android::Parcel* parcel) const { + + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + status_t err = OK; + if ((err = parcel->writeString16(String16(mCameraId.c_str()))) != OK) { + ALOGE("%s: Failed to write camera id!", __FUNCTION__); + return err; + } + + if ((err = mSessionConfiguration.writeToParcel(parcel) != OK)) { + ALOGE("%s: Failed to write session configuration!", __FUNCTION__); + return err; + } + return OK; +} + +} // namespace utils +} // namespace camera2 +} // namespace hardware +} // namespace android diff --git a/camera/include/camera/camera2/ConcurrentCamera.h b/camera/include/camera/camera2/ConcurrentCamera.h new file mode 100644 index 0000000000..ac99fd5823 --- /dev/null +++ b/camera/include/camera/camera2/ConcurrentCamera.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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_HARDWARE_CAMERA2_UTIL_CONCURRENTCAMERA_H +#define ANDROID_HARDWARE_CAMERA2_UTIL_CONCURRENTCAMERA_H + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace camera2 { +namespace utils { + +struct ConcurrentCameraIdCombination : public Parcelable { + std::vector mConcurrentCameraIds; + ConcurrentCameraIdCombination(); + ConcurrentCameraIdCombination(std::vector &&combination); + virtual ~ConcurrentCameraIdCombination(); + + virtual status_t writeToParcel(android::Parcel *parcel) const override; + virtual status_t readFromParcel(const android::Parcel* parcel) override; +}; + +struct CameraIdAndSessionConfiguration : public Parcelable { + std::string mCameraId; + SessionConfiguration mSessionConfiguration; + + CameraIdAndSessionConfiguration(); + virtual ~CameraIdAndSessionConfiguration(); + + virtual status_t writeToParcel(android::Parcel *parcel) const override; + virtual status_t readFromParcel(const android::Parcel* parcel) override; +}; + +} // namespace utils +} // namespace camera2 +} // namespace hardware +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp index da44e56821..109ce7d1a8 100644 --- a/services/camera/libcameraservice/Android.bp +++ b/services/camera/libcameraservice/Android.bp @@ -66,15 +66,16 @@ cc_library_shared { "device3/Camera3OutputStreamInterface.cpp", "device3/Camera3OutputUtils.cpp", "gui/RingBufferConsumer.cpp", - "utils/CameraThreadState.cpp", "hidl/AidlCameraDeviceCallbacks.cpp", "hidl/AidlCameraServiceListener.cpp", "hidl/Convert.cpp", "hidl/HidlCameraDeviceUser.cpp", "hidl/HidlCameraService.cpp", + "utils/CameraThreadState.cpp", "utils/CameraTraces.cpp", "utils/AutoConditionLock.cpp", "utils/ExifUtils.cpp", + "utils/SessionConfigurationUtils.cpp", "utils/TagMonitor.cpp", "utils/LatencyHistogram.cpp", ], diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 01d6c8e531..f1d5d166a8 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -91,6 +92,8 @@ using hardware::ICameraServiceProxy; using hardware::ICameraServiceListener; using hardware::camera::common::V1_0::CameraDeviceStatus; using hardware::camera::common::V1_0::TorchModeStatus; +using hardware::camera2::utils::CameraIdAndSessionConfiguration; +using hardware::camera2::utils::ConcurrentCameraIdCombination; // ---------------------------------------------------------------------------- // Logging support -- this is for debugging only @@ -2040,6 +2043,83 @@ Status CameraService::notifyDeviceStateChange(int64_t newState) { return Status::ok(); } + Status CameraService::getConcurrentStreamingCameraIds( + std::vector* concurrentCameraIds) { + ATRACE_CALL(); + if (!concurrentCameraIds) { + ALOGE("%s: concurrentCameraIds is NULL", __FUNCTION__); + return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "concurrentCameraIds is NULL"); + } + + if (!mInitialized) { + ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__); + return STATUS_ERROR(ERROR_DISCONNECTED, + "Camera subsystem is not available"); + } + // First call into the provider and get the set of concurrent camera + // combinations + std::vector> concurrentCameraCombinations = + mCameraProviderManager->getConcurrentStreamingCameraIds(); + for (auto &combination : concurrentCameraCombinations) { + std::vector validCombination; + for (auto &cameraId : combination) { + // if the camera state is not present, skip + String8 cameraIdStr(cameraId.c_str()); + auto state = getCameraState(cameraIdStr); + if (state == nullptr) { + ALOGW("%s: camera id %s does not exist", __FUNCTION__, cameraId.c_str()); + continue; + } + StatusInternal status = state->getStatus(); + if (status == StatusInternal::NOT_PRESENT || status == StatusInternal::ENUMERATING) { + continue; + } + if (shouldRejectSystemCameraConnection(cameraIdStr)) { + continue; + } + validCombination.push_back(cameraId); + } + if (validCombination.size() != 0) { + concurrentCameraIds->push_back(std::move(validCombination)); + } + } + return Status::ok(); +} + +Status CameraService::isConcurrentSessionConfigurationSupported( + const std::vector& cameraIdsAndSessionConfigurations, + /*out*/bool* isSupported) { + if (!isSupported) { + ALOGE("%s: isSupported is NULL", __FUNCTION__); + return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "isSupported is NULL"); + } + + if (!mInitialized) { + ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__); + return STATUS_ERROR(ERROR_DISCONNECTED, + "Camera subsystem is not available"); + } + + // Check for camera permissions + int callingPid = CameraThreadState::getCallingPid(); + int callingUid = CameraThreadState::getCallingUid(); + if ((callingPid != getpid()) && !checkPermission(sCameraPermission, callingPid, callingUid)) { + ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid); + return STATUS_ERROR(ERROR_PERMISSION_DENIED, + "android.permission.CAMERA needed to call" + "isConcurrentSessionConfigurationSupported"); + } + + status_t res = + mCameraProviderManager->isConcurrentSessionConfigurationSupported( + cameraIdsAndSessionConfigurations, isSupported); + if (res != OK) { + return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to query session configuration " + "support %s (%d)", strerror(-res), res); + } + return Status::ok(); +} + Status CameraService::addListener(const sp& listener, /*out*/ std::vector *cameraStatuses) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 8d731838a1..e433544b1a 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "CameraFlashlight.h" @@ -150,6 +151,14 @@ public: virtual binder::Status removeListener( const sp& listener); + virtual binder::Status getConcurrentStreamingCameraIds( + /*out*/ + std::vector* concurrentCameraIds); + + virtual binder::Status isConcurrentSessionConfigurationSupported( + const std::vector& sessions, + /*out*/bool* supported); + virtual binder::Status getLegacyParameters( int32_t cameraId, /*out*/ diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index 8ed3ab667a..ff9d27442e 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -492,7 +492,7 @@ binder::Status CameraDeviceClient::endConfigure(int operatingMode, return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive"); } - res = checkOperatingModeLocked(operatingMode); + res = checkOperatingMode(operatingMode, mDevice->info(), mCameraIdStr); if (!res.isOk()) { return res; } @@ -550,8 +550,8 @@ binder::Status CameraDeviceClient::endConfigure(int operatingMode, return res; } -binder::Status CameraDeviceClient::checkSurfaceTypeLocked(size_t numBufferProducers, - bool deferredConsumer, int surfaceType) const { +binder::Status CameraDeviceClient::checkSurfaceType(size_t numBufferProducers, + bool deferredConsumer, int surfaceType) { if (numBufferProducers > MAX_SURFACES_PER_STREAM) { ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d", __FUNCTION__, numBufferProducers, MAX_SURFACES_PER_STREAM); @@ -572,28 +572,27 @@ binder::Status CameraDeviceClient::checkSurfaceTypeLocked(size_t numBufferProduc return binder::Status::ok(); } -binder::Status CameraDeviceClient::checkPhysicalCameraIdLocked(String8 physicalCameraId) { - if (physicalCameraId.size() > 0) { - std::vector physicalCameraIds; - bool logicalCamera = - mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds); - if (!logicalCamera || - std::find(physicalCameraIds.begin(), physicalCameraIds.end(), - physicalCameraId.string()) == physicalCameraIds.end()) { - String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.", - mCameraIdStr.string(), physicalCameraId.string()); - ALOGE("%s: %s", __FUNCTION__, msg.string()); - return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); - } +binder::Status CameraDeviceClient::checkPhysicalCameraId( + const std::vector &physicalCameraIds, const String8 &physicalCameraId, + const String8 &logicalCameraId) { + if (physicalCameraId.size() == 0) { + return binder::Status::ok(); + } + if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), + physicalCameraId.string()) == physicalCameraIds.end()) { + String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.", + logicalCameraId.string(), physicalCameraId.string()); + ALOGE("%s: %s", __FUNCTION__, msg.string()); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } - return binder::Status::ok(); } -binder::Status CameraDeviceClient::checkOperatingModeLocked(int operatingMode) const { +binder::Status CameraDeviceClient::checkOperatingMode(int operatingMode, + const CameraMetadata &staticInfo, const String8 &cameraId) { if (operatingMode < 0) { String8 msg = String8::format( - "Camera %s: Invalid operating mode %d requested", mCameraIdStr.string(), operatingMode); + "Camera %s: Invalid operating mode %d requested", cameraId.string(), operatingMode); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); @@ -601,8 +600,7 @@ binder::Status CameraDeviceClient::checkOperatingModeLocked(int operatingMode) c bool isConstrainedHighSpeed = (operatingMode == ICameraDeviceUser::CONSTRAINED_HIGH_SPEED_MODE); if (isConstrainedHighSpeed) { - CameraMetadata staticInfo = mDevice->info(); - camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); + camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); bool isConstrainedHighSpeedSupported = false; for(size_t i = 0; i < entry.count; ++i) { uint8_t capability = entry.data.u8[i]; @@ -614,7 +612,7 @@ binder::Status CameraDeviceClient::checkOperatingModeLocked(int operatingMode) c if (!isConstrainedHighSpeedSupported) { String8 msg = String8::format( "Camera %s: Try to create a constrained high speed configuration on a device" - " that doesn't support it.", mCameraIdStr.string()); + " that doesn't support it.", cameraId.string()); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); @@ -645,39 +643,31 @@ void CameraDeviceClient::mapStreamInfo(const OutputStreamInfo &streamInfo, stream->bufferSize = 0; } -binder::Status CameraDeviceClient::isSessionConfigurationSupported( - const SessionConfiguration& sessionConfiguration, bool *status /*out*/) { - ATRACE_CALL(); - - binder::Status res; - 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"); - } - +binder::Status +CameraDeviceClient::convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration, + const String8 &logicalCameraId, const CameraMetadata &deviceInfo, + metadataGetter getMetadata, const std::vector &physicalCameraIds, + hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, + bool *unsupported) { auto operatingMode = sessionConfiguration.getOperatingMode(); - res = checkOperatingModeLocked(operatingMode); + binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId); if (!res.isOk()) { return res; } - if (status == nullptr) { - String8 msg = String8::format( "Camera %s: Invalid status!", mCameraIdStr.string()); + if (unsupported == nullptr) { + String8 msg("unsupported nullptr"); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } - - hardware::camera::device::V3_4::StreamConfiguration streamConfiguration; + *unsupported = false; auto ret = Camera3Device::mapToStreamConfigurationMode( static_cast (operatingMode), /*out*/ &streamConfiguration.operationMode); if (ret != OK) { String8 msg = String8::format( - "Camera %s: Failed mapping operating mode %d requested: %s (%d)", mCameraIdStr.string(), - operatingMode, strerror(-ret), ret); + "Camera %s: Failed mapping operating mode %d requested: %s (%d)", + logicalCameraId.string(), operatingMode, strerror(-ret), ret); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); @@ -711,12 +701,12 @@ binder::Status CameraDeviceClient::isSessionConfigurationSupported( bool isStreamInfoValid = false; OutputStreamInfo streamInfo; - res = checkSurfaceTypeLocked(numBufferProducers, deferredConsumer, it.getSurfaceType()); + res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType()); if (!res.isOk()) { return res; } - - res = checkPhysicalCameraIdLocked(physicalCameraId); + res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId, + logicalCameraId); if (!res.isOk()) { return res; } @@ -742,8 +732,10 @@ binder::Status CameraDeviceClient::isSessionConfigurationSupported( for (auto& bufferProducer : bufferProducers) { sp surface; + const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId); res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer, - physicalCameraId); + logicalCameraId, + physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo ); if (!res.isOk()) return res; @@ -759,15 +751,15 @@ binder::Status CameraDeviceClient::isSessionConfigurationSupported( std::vector compositeStreams; if (isDepthCompositeStream) { ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo, - mDevice->info(), &compositeStreams); + deviceInfo, &compositeStreams); } else { ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo, - mDevice->info(), &compositeStreams); + deviceInfo, &compositeStreams); } if (ret != OK) { String8 msg = String8::format( "Camera %s: Failed adding composite streams: %s (%d)", - mCameraIdStr.string(), strerror(-ret), ret); + logicalCameraId.string(), strerror(-ret), ret); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } @@ -775,7 +767,7 @@ binder::Status CameraDeviceClient::isSessionConfigurationSupported( if (compositeStreams.size() == 0) { // No internal streams means composite stream not // supported. - *status = false; + *unsupported = true; return binder::Status::ok(); } else if (compositeStreams.size() > 1) { streamCount += compositeStreams.size() - 1; @@ -796,6 +788,49 @@ binder::Status CameraDeviceClient::isSessionConfigurationSupported( } } } + return binder::Status::ok(); +} + +binder::Status CameraDeviceClient::isSessionConfigurationSupported( + const SessionConfiguration& sessionConfiguration, bool *status /*out*/) { + ATRACE_CALL(); + + binder::Status res; + status_t ret = OK; + 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"); + } + + auto operatingMode = sessionConfiguration.getOperatingMode(); + res = checkOperatingMode(operatingMode, mDevice->info(), mCameraIdStr); + if (!res.isOk()) { + return res; + } + + if (status == nullptr) { + String8 msg = String8::format( "Camera %s: Invalid status!", mCameraIdStr.string()); + ALOGE("%s: %s", __FUNCTION__, msg.string()); + return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); + } + hardware::camera::device::V3_4::StreamConfiguration streamConfiguration; + bool earlyExit = false; + metadataGetter getMetadata = [this](const String8 &id) {return mDevice->info(id);}; + std::vector physicalCameraIds; + mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds); + res = convertToHALStreamCombination(sessionConfiguration, mCameraIdStr, + mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration, &earlyExit); + if (!res.isOk()) { + return res; + } + + if (earlyExit) { + *status = false; + return binder::Status::ok(); + } *status = false; ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(), @@ -935,7 +970,7 @@ binder::Status CameraDeviceClient::createStream( String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId()); bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0; - res = checkSurfaceTypeLocked(numBufferProducers, deferredConsumer, + res = checkSurfaceType(numBufferProducers, deferredConsumer, outputConfiguration.getSurfaceType()); if (!res.isOk()) { return res; @@ -944,8 +979,9 @@ binder::Status CameraDeviceClient::createStream( if (!mDevice.get()) { return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive"); } - - res = checkPhysicalCameraIdLocked(physicalCameraId); + std::vector physicalCameraIds; + mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds); + res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId, mCameraIdStr); if (!res.isOk()) { return res; } @@ -974,7 +1010,7 @@ binder::Status CameraDeviceClient::createStream( sp surface; res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer, - physicalCameraId); + mCameraIdStr, mDevice->info(physicalCameraId)); if (!res.isOk()) return res; @@ -1278,7 +1314,7 @@ binder::Status CameraDeviceClient::updateOutputConfiguration(int streamId, OutputStreamInfo outInfo; sp surface; res = createSurfaceFromGbp(outInfo, /*isStreamInfoValid*/ false, surface, - newOutputsMap.valueAt(i), physicalCameraId); + newOutputsMap.valueAt(i), mCameraIdStr, mDevice->info(physicalCameraId)); if (!res.isOk()) return res; @@ -1358,11 +1394,11 @@ bool CameraDeviceClient::isPublicFormat(int32_t format) binder::Status CameraDeviceClient::createSurfaceFromGbp( OutputStreamInfo& streamInfo, bool isStreamInfoValid, sp& surface, const sp& gbp, - const String8& physicalId) { + const String8 &cameraId, const CameraMetadata &physicalCameraMetadata) { // bufferProducer must be non-null if (gbp == nullptr) { - String8 msg = String8::format("Camera %s: Surface is NULL", mCameraIdStr.string()); + String8 msg = String8::format("Camera %s: Surface is NULL", cameraId.string()); ALOGW("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } @@ -1374,13 +1410,13 @@ binder::Status CameraDeviceClient::createSurfaceFromGbp( status_t err; if ((err = gbp->getConsumerUsage(&consumerUsage)) != OK) { String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)", - mCameraIdStr.string(), strerror(-err), err); + cameraId.string(), strerror(-err), err); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); } if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) { ALOGW("%s: Camera %s with consumer usage flag: %" PRIu64 ": Forcing asynchronous mode for stream", - __FUNCTION__, mCameraIdStr.string(), consumerUsage); + __FUNCTION__, cameraId.string(), consumerUsage); useAsync = true; } @@ -1399,26 +1435,26 @@ binder::Status CameraDeviceClient::createSurfaceFromGbp( android_dataspace dataSpace; if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) { String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)", - mCameraIdStr.string(), strerror(-err), err); + cameraId.string(), strerror(-err), err); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); } if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) { String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)", - mCameraIdStr.string(), strerror(-err), err); + cameraId.string(), strerror(-err), err); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); } if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) { String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)", - mCameraIdStr.string(), strerror(-err), err); + cameraId.string(), strerror(-err), err); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); } if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, reinterpret_cast(&dataSpace))) != OK) { String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)", - mCameraIdStr.string(), strerror(-err), err); + cameraId.string(), strerror(-err), err); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); } @@ -1429,16 +1465,16 @@ binder::Status CameraDeviceClient::createSurfaceFromGbp( ((consumerUsage & GRALLOC_USAGE_HW_MASK) && ((consumerUsage & GRALLOC_USAGE_SW_READ_MASK) == 0))) { ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED", - __FUNCTION__, mCameraIdStr.string(), format); + __FUNCTION__, cameraId.string(), format); format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } // Round dimensions to the nearest dimensions available for this format if (flexibleConsumer && isPublicFormat(format) && !CameraDeviceClient::roundBufferDimensionNearest(width, height, - format, dataSpace, mDevice->info(physicalId), /*out*/&width, /*out*/&height)) { + format, dataSpace, physicalCameraMetadata, /*out*/&width, /*out*/&height)) { String8 msg = String8::format("Camera %s: No supported stream configurations with " "format %#x defined, failed to create output stream", - mCameraIdStr.string(), format); + cameraId.string(), format); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } @@ -1453,26 +1489,26 @@ binder::Status CameraDeviceClient::createSurfaceFromGbp( } if (width != streamInfo.width) { String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d", - mCameraIdStr.string(), width, streamInfo.width); + cameraId.string(), width, streamInfo.width); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } if (height != streamInfo.height) { String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d", - mCameraIdStr.string(), height, streamInfo.height); + cameraId.string(), height, streamInfo.height); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } if (format != streamInfo.format) { String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d", - mCameraIdStr.string(), format, streamInfo.format); + cameraId.string(), format, streamInfo.format); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { if (dataSpace != streamInfo.dataSpace) { String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d", - mCameraIdStr.string(), dataSpace, streamInfo.dataSpace); + cameraId.string(), dataSpace, streamInfo.dataSpace); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } @@ -1481,7 +1517,7 @@ binder::Status CameraDeviceClient::createSurfaceFromGbp( if (consumerUsage != streamInfo.consumerUsage) { String8 msg = String8::format( "Camera %s:Surface usage flag doesn't match %" PRIu64 " vs %" PRIu64 "", - mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage); + cameraId.string(), consumerUsage, streamInfo.consumerUsage); ALOGE("%s: %s", __FUNCTION__, msg.string()); return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); } @@ -1861,7 +1897,7 @@ binder::Status CameraDeviceClient::finalizeOutputConfigurations(int32_t streamId sp surface; res = createSurfaceFromGbp(mStreamInfoMap[streamId], true /*isStreamInfoValid*/, - surface, bufferProducer, physicalId); + surface, bufferProducer, mCameraIdStr, mDevice->info(physicalId)); if (!res.isOk()) return res; diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 7d38f9f9d4..888fcce34b 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -34,6 +34,8 @@ using android::camera3::CompositeStream; namespace android { +typedef std::function metadataGetter; + struct CameraDeviceClientBase : public CameraService::BasicClient, public hardware::camera2::BnCameraDeviceUser @@ -202,6 +204,16 @@ public: virtual void notifyRequestQueueEmpty(); virtual void notifyRepeatingRequestError(long lastFrameNumber); + // utility function to convert AIDL SessionConfiguration to HIDL + // streamConfiguration. Also checks for sanity of SessionConfiguration and + // returns a non-ok binder::Status if the passed in session configuration + // isn't valid. + static binder::Status + convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration, + const String8 &cameraId, const CameraMetadata &deviceInfo, + metadataGetter getMetadata, const std::vector &physicalCameraIds, + hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, + bool *earlyExit); /** * Interface used by independent components of CameraDeviceClient. */ @@ -256,10 +268,10 @@ private: /** Utility members */ binder::Status checkPidStatus(const char* checkLocation); - binder::Status checkOperatingModeLocked(int operatingMode) const; - binder::Status checkPhysicalCameraIdLocked(String8 physicalCameraId); - binder::Status checkSurfaceTypeLocked(size_t numBufferProducers, bool deferredConsumer, - int surfaceType) const; + static binder::Status checkOperatingMode(int operatingMode, const CameraMetadata &staticInfo, + const String8 &cameraId); + static binder::Status checkSurfaceType(size_t numBufferProducers, bool deferredConsumer, + int surfaceType); static void mapStreamInfo(const OutputStreamInfo &streamInfo, camera3_stream_rotation_t rotation, String8 physicalId, hardware::camera::device::V3_4::Stream *stream /*out*/); @@ -290,9 +302,9 @@ private: // Create a Surface from an IGraphicBufferProducer. Returns error if // IGraphicBufferProducer's property doesn't match with streamInfo - binder::Status createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid, - sp& surface, const sp& gbp, - const String8& physicalCameraId); + static binder::Status createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid, + sp& surface, const sp& gbp, const String8 &cameraId, + const CameraMetadata &physicalCameraMetadata); // Utility method to insert the surface into SurfaceMap @@ -302,7 +314,8 @@ private: // Check that the physicalCameraId passed in is spported by the camera // device. - bool checkPhysicalCameraId(const String8& physicalCameraId); + static binder::Status checkPhysicalCameraId(const std::vector &physicalCameraIds, + const String8 &physicalCameraId, const String8 &logicalCameraId); // IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams KeyedVector, StreamSurfaceId> mStreamMap; diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 1401ba7e8f..b20774ada2 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "api2/HeicCompositeStream.h" @@ -47,6 +48,8 @@ namespace android { using namespace ::android::hardware::camera; using namespace ::android::hardware::camera::common::V1_0; using std::literals::chrono_literals::operator""s; +using hardware::camera2::utils::CameraIdAndSessionConfiguration; +using hardware::camera::provider::V2_6::CameraIdAndStreamCombination; namespace { const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false)); @@ -267,7 +270,6 @@ status_t CameraProviderManager::isSessionConfigurationSupported(const std::strin const hardware::camera::device::V3_4::StreamConfiguration &configuration, bool *status /*out*/) const { std::lock_guard lock(mInterfaceMutex); - auto deviceInfo = findDeviceInfoLocked(id); if (deviceInfo == nullptr) { return NAME_NOT_FOUND; @@ -1083,10 +1085,8 @@ status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags() { return OK; } -bool CameraProviderManager::isLogicalCamera(const std::string& id, +bool CameraProviderManager::isLogicalCameraLocked(const std::string& id, std::vector* physicalCameraIds) { - std::lock_guard lock(mInterfaceMutex); - auto deviceInfo = findDeviceInfoLocked(id); if (deviceInfo == nullptr) return false; @@ -1096,6 +1096,12 @@ bool CameraProviderManager::isLogicalCamera(const std::string& id, return deviceInfo->mIsLogicalCamera; } +bool CameraProviderManager::isLogicalCamera(const std::string& id, + std::vector* physicalCameraIds) { + std::lock_guard lock(mInterfaceMutex); + return isLogicalCameraLocked(id, physicalCameraIds); +} + status_t CameraProviderManager::getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const { std::lock_guard lock(mInterfaceMutex); @@ -1261,11 +1267,27 @@ status_t CameraProviderManager::ProviderInfo::initialize( mProviderName.c_str(), interface->isRemote()); // Determine minor version - auto castResult = provider::V2_5::ICameraProvider::castFrom(interface); - if (castResult.isOk()) { - mMinorVersion = 5; - } else { - mMinorVersion = 4; + mMinorVersion = 4; + auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface); + sp interface2_6 = nullptr; + if (cast2_6.isOk()) { + interface2_6 = cast2_6; + if (interface2_6 != nullptr) { + mMinorVersion = 6; + } + } + // We need to check again since cast2_6.isOk() succeeds even if the provider + // version isn't actually 2.6. + if (interface2_6 == nullptr){ + auto cast2_5 = + provider::V2_5::ICameraProvider::castFrom(interface); + sp interface2_5 = nullptr; + if (cast2_5.isOk()) { + interface2_5 = cast2_5; + if (interface != nullptr) { + mMinorVersion = 5; + } + } } hardware::Return linked = interface->linkToDeath(this, /*cookie*/ mId); @@ -1328,6 +1350,34 @@ status_t CameraProviderManager::ProviderInfo::initialize( return mapToStatusT(status); } + // Get list of concurrent streaming camera device combinations + if (mMinorVersion >= 6) { + hardware::Return ret = interface2_6->getConcurrentStreamingCameraIds([&status, this]( + Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using' + const hardware::hidl_vec>& + cameraDeviceIdCombinations) { + status = concurrentIdStatus; + if (status == Status::OK) { + for (auto& combination : cameraDeviceIdCombinations) { + std::unordered_set deviceIds; + for (auto &cameraDeviceId : combination) { + deviceIds.insert(cameraDeviceId.c_str()); + } + mConcurrentCameraIdCombinations.push_back(std::move(deviceIds)); + } + } }); + if (!ret.isOk()) { + ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s", + __FUNCTION__, mProviderName.c_str(), linked.description().c_str()); + return DEAD_OBJECT; + } + if (status != Status::OK) { + ALOGE("%s: Unable to query for camera devices from provider '%s'", + __FUNCTION__, mProviderName.c_str()); + return mapToStatusT(status); + } + } + ret = interface->isSetTorchModeSupported( [this](auto status, bool supported) { if (status == Status::OK) { @@ -1780,6 +1830,55 @@ status_t CameraProviderManager::ProviderInfo::notifyDeviceStateChange( return OK; } +status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSupported( + const hardware::hidl_vec &halCameraIdsAndStreamCombinations, + bool *isSupported) { + status_t res = OK; + if (mMinorVersion >= 6) { + // Check if the provider is currently active - not going to start it up for this notification + auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote(); + if (interface == nullptr) { + // TODO: This might be some other problem + return INVALID_OPERATION; + } + auto castResult = provider::V2_6::ICameraProvider::castFrom(interface); + if (castResult.isOk()) { + sp interface_2_6 = castResult; + if (interface_2_6 != nullptr) { + Status callStatus; + auto cb = + [&isSupported, &callStatus](Status s, bool supported) { + callStatus = s; + *isSupported = supported; }; + + auto ret = interface_2_6->isConcurrentStreamCombinationSupported( + halCameraIdsAndStreamCombinations, cb); + if (ret.isOk()) { + switch (callStatus) { + case Status::OK: + // Expected case, do nothing. + res = OK; + break; + case Status::METHOD_NOT_SUPPORTED: + res = INVALID_OPERATION; + break; + default: + ALOGE("%s: Session configuration query failed: %d", __FUNCTION__, + callStatus); + res = UNKNOWN_ERROR; + } + } else { + ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str()); + res = UNKNOWN_ERROR; + } + return res; + } + } + } + // unsupported operation + return INVALID_OPERATION; +} + template std::unique_ptr CameraProviderManager::ProviderInfo::initializeDeviceInfo( @@ -2642,6 +2741,125 @@ status_t HidlVendorTagDescriptor::createDescriptorFromHidl( return OK; } +// Expects to have mInterfaceMutex locked +std::vector> +CameraProviderManager::getConcurrentStreamingCameraIds() const { + std::vector> deviceIdCombinations; + std::lock_guard lock(mInterfaceMutex); + for (auto &provider : mProviders) { + for (auto &combinations : provider->mConcurrentCameraIdCombinations) { + deviceIdCombinations.push_back(combinations); + } + } + return deviceIdCombinations; +} + +status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked( + const std::vector &cameraIdsAndSessionConfigs, + hardware::hidl_vec *halCameraIdsAndStreamCombinations, + bool *earlyExit) { + binder::Status bStatus = binder::Status::ok(); + std::vector halCameraIdsAndStreamsV; + bool shouldExit = false; + status_t res = OK; + for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) { + hardware::camera::device::V3_4::StreamConfiguration streamConfiguration; + CameraMetadata deviceInfo; + res = getCameraCharacteristicsLocked(cameraIdAndSessionConfig.mCameraId, &deviceInfo); + if (res != OK) { + return res; + } + metadataGetter getMetadata = + [this](const String8 &id) { + CameraMetadata physicalDeviceInfo; + getCameraCharacteristicsLocked(id.string(), &physicalDeviceInfo); + return physicalDeviceInfo; + }; + std::vector physicalCameraIds; + isLogicalCameraLocked(cameraIdAndSessionConfig.mCameraId, &physicalCameraIds); + bStatus = + SessionConfigurationUtils::convertToHALStreamCombination( + cameraIdAndSessionConfig.mSessionConfiguration, + String8(cameraIdAndSessionConfig.mCameraId.c_str()), deviceInfo, getMetadata, + physicalCameraIds, streamConfiguration, &shouldExit); + if (!bStatus.isOk()) { + ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__); + return INVALID_OPERATION; + } + if (shouldExit) { + *earlyExit = true; + return OK; + } + CameraIdAndStreamCombination halCameraIdAndStream; + halCameraIdAndStream.cameraId = cameraIdAndSessionConfig.mCameraId; + halCameraIdAndStream.streamConfiguration = streamConfiguration; + halCameraIdsAndStreamsV.push_back(halCameraIdAndStream); + } + *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV; + return OK; +} + +// Checks if the containing vector of sets has any set that contains all of the +// camera ids in cameraIdsAndSessionConfigs. +static bool checkIfSetContainsAll( + const std::vector &cameraIdsAndSessionConfigs, + const std::vector> &containingSets) { + for (auto &containingSet : containingSets) { + bool didHaveAll = true; + for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) { + if (containingSet.find(cameraIdAndSessionConfig.mCameraId) == containingSet.end()) { + // a camera id doesn't belong to this set, keep looking in other + // sets + didHaveAll = false; + break; + } + } + if (didHaveAll) { + // found a set that has all camera ids, lets return; + return true; + } + } + return false; +} + +status_t CameraProviderManager::isConcurrentSessionConfigurationSupported( + const std::vector &cameraIdsAndSessionConfigs, + bool *isSupported) { + std::lock_guard lock(mInterfaceMutex); + // Check if all the devices are a subset of devices advertised by the + // same provider through getConcurrentStreamingCameraIds() + // TODO: we should also do a findDeviceInfoLocked here ? + for (auto &provider : mProviders) { + if (checkIfSetContainsAll(cameraIdsAndSessionConfigs, + provider->mConcurrentCameraIdCombinations)) { + // For each camera device in cameraIdsAndSessionConfigs collect + // the streamConfigs and create the HAL + // CameraIdAndStreamCombination, exit early if needed + hardware::hidl_vec halCameraIdsAndStreamCombinations; + bool knowUnsupported = false; + status_t res = convertToHALStreamCombinationAndCameraIdsLocked( + cameraIdsAndSessionConfigs, &halCameraIdsAndStreamCombinations, + &knowUnsupported); + if (res != OK) { + ALOGE("%s unable to convert session configurations provided to HAL stream" + "combinations", __FUNCTION__); + return res; + } + if (knowUnsupported) { + // We got to know the streams aren't valid before doing the HAL + // call itself. + *isSupported = false; + return OK; + } + return provider->isConcurrentSessionConfigurationSupported( + halCameraIdsAndStreamCombinations, isSupported); + } + } + *isSupported = false; + //The set of camera devices were not found + return INVALID_OPERATION; +} + status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id, CameraMetadata* characteristics) const { auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0}); diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h index 49a93cc3cd..42da2278ca 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.h +++ b/services/camera/libcameraservice/common/CameraProviderManager.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -214,6 +216,12 @@ public: status_t getCameraCharacteristics(const std::string &id, CameraMetadata* characteristics) const; + status_t isConcurrentSessionConfigurationSupported( + const std::vector + &cameraIdsAndSessionConfigs, + bool *isSupported); + + std::vector> getConcurrentStreamingCameraIds() const; /** * Check for device support of specific stream combination. */ @@ -409,6 +417,14 @@ private: status_t notifyDeviceStateChange( hardware::hidl_bitfield newDeviceState); + /** + * Query the camera provider for concurrent stream configuration support + */ + status_t isConcurrentSessionConfigurationSupported( + const hardware::hidl_vec< + hardware::camera::provider::V2_6::CameraIdAndStreamCombination> + &halCameraIdsAndStreamCombinations, + bool *isSupported); // Basic device information, common to all camera devices struct DeviceInfo { @@ -494,6 +510,8 @@ private: // physical camera IDs. std::vector mProviderPublicCameraIds; + std::vector> mConcurrentCameraIdCombinations; + // HALv1-specific camera fields, including the actual device interface struct DeviceInfo1 : public DeviceInfo { typedef hardware::camera::device::V1_0::ICameraDevice InterfaceT; @@ -618,6 +636,8 @@ private: status_t addProviderLocked(const std::string& newProvider); + bool isLogicalCameraLocked(const std::string& id, std::vector* physicalCameraIds); + status_t removeProvider(const std::string& provider); sp getStatusListener() const; @@ -648,6 +668,13 @@ private: void collectDeviceIdsLocked(const std::vector deviceIds, std::vector& normalDeviceIds, std::vector& systemCameraDeviceIds) const; + + status_t convertToHALStreamCombinationAndCameraIdsLocked( + const std::vector + &cameraIdsAndSessionConfigs, + hardware::hidl_vec + *halCameraIdsAndStreamCombinations, + bool *earlyExit); }; } // namespace android diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk index 8784c95cbc..fa5d69e2c4 100644 --- a/services/camera/libcameraservice/tests/Android.mk +++ b/services/camera/libcameraservice/tests/Android.mk @@ -25,6 +25,7 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libcamera_client \ libcamera_metadata \ + libui \ libutils \ libjpeg \ libexif \ @@ -34,7 +35,8 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.camera.provider@2.6 \ android.hardware.camera.device@1.0 \ android.hardware.camera.device@3.2 \ - android.hardware.camera.device@3.4 + android.hardware.camera.device@3.4 \ + android.hidl.token@1.0-utils LOCAL_STATIC_LIBRARIES := \ libgmock diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp new file mode 100644 index 0000000000..888671c898 --- /dev/null +++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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. + */ +#include "SessionConfigurationUtils.h" +#include "../api2/CameraDeviceClient.h" + +namespace android { + +binder::Status +SessionConfigurationUtils::convertToHALStreamCombination( + const SessionConfiguration& sessionConfiguration, + const String8 &logicalCameraId, const CameraMetadata &deviceInfo, + metadataGetter getMetadata, const std::vector &physicalCameraIds, + hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, bool *earlyExit) { + // TODO: http://b/148329298 Move the other dependencies from + // CameraDeviceClient into SessionConfigurationUtils. + return CameraDeviceClient::convertToHALStreamCombination(sessionConfiguration, logicalCameraId, + deviceInfo, getMetadata, physicalCameraIds, streamConfiguration, earlyExit); +} + +}// namespace android diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h new file mode 100644 index 0000000000..fb519d97ac --- /dev/null +++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 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_SESSION_CONFIGURATION_UTILS_H +#define ANDROID_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_H + +#include +#include +#include +#include +#include +#include + +#include + +namespace android { + +typedef std::function metadataGetter; + +class SessionConfigurationUtils { +public: + // utility function to convert AIDL SessionConfiguration to HIDL + // streamConfiguration. Also checks for sanity of SessionConfiguration and + // returns a non-ok binder::Status if the passed in session configuration + // isn't valid. + static binder::Status + convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration, + const String8 &cameraId, const CameraMetadata &deviceInfo, + metadataGetter getMetadata, const std::vector &physicalCameraIds, + hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, + bool *earlyExit); +}; + +} // android +#endif