| /* |
| * Copyright (C) 2022 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 "AidlProviderInfo.h" |
| #include "common/HalConversionsTemplated.h" |
| #include "common/CameraProviderInfoTemplated.h" |
| |
| #include <com_android_internal_camera_flags.h> |
| #include <cutils/properties.h> |
| |
| #include <aidlcommonsupport/NativeHandle.h> |
| #include <android_companion_virtualdevice_flags.h> |
| #include <android/binder_manager.h> |
| #include <android/hardware/ICameraService.h> |
| #include <camera_metadata_hidden.h> |
| |
| #include "device3/ZoomRatioMapper.h" |
| #include <utils/SessionConfigurationUtils.h> |
| #include <utils/Trace.h> |
| |
| namespace { |
| const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false)); |
| } // anonymous namespace |
| |
| namespace android { |
| |
| namespace SessionConfigurationUtils = ::android::camera3::SessionConfigurationUtils; |
| namespace flags = com::android::internal::camera::flags; |
| namespace vd_flags = android::companion::virtualdevice::flags; |
| |
| using namespace aidl::android::hardware; |
| using namespace hardware::camera; |
| using hardware::camera2::utils::CameraIdAndSessionConfiguration; |
| using hardware::ICameraService; |
| |
| using HalDeviceStatusType = aidl::android::hardware::camera::common::CameraDeviceStatus; |
| using ICameraProvider = aidl::android::hardware::camera::provider::ICameraProvider; |
| using StatusListener = CameraProviderManager::StatusListener; |
| |
| static status_t mapExceptionCodeToStatusT(binder_exception_t binderException) { |
| switch (binderException) { |
| case EX_NONE: |
| return OK; |
| case EX_ILLEGAL_ARGUMENT: |
| case EX_NULL_POINTER: |
| case EX_BAD_PARCELABLE: |
| case EX_ILLEGAL_STATE: |
| return BAD_VALUE; |
| case EX_UNSUPPORTED_OPERATION: |
| return INVALID_OPERATION; |
| case EX_TRANSACTION_FAILED: |
| return DEAD_OBJECT; |
| default: |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| status_t AidlProviderInfo::mapToStatusT(const ndk::ScopedAStatus& s) { |
| using Status = aidl::android::hardware::camera::common::Status; |
| auto exceptionCode = s.getExceptionCode(); |
| if (exceptionCode != EX_SERVICE_SPECIFIC) { |
| return mapExceptionCodeToStatusT(exceptionCode); |
| } |
| Status st = static_cast<Status>(s.getServiceSpecificError()); |
| switch (st) { |
| case Status::OK: |
| return OK; |
| case Status::ILLEGAL_ARGUMENT: |
| return BAD_VALUE; |
| case Status::CAMERA_IN_USE: |
| return -EBUSY; |
| case Status::MAX_CAMERAS_IN_USE: |
| return -EUSERS; |
| case Status::OPERATION_NOT_SUPPORTED: |
| return INVALID_OPERATION; |
| case Status::CAMERA_DISCONNECTED: |
| return DEAD_OBJECT; |
| case Status::INTERNAL_ERROR: |
| return INVALID_OPERATION; |
| } |
| ALOGW("Unexpected HAL status code %d", static_cast<int>(st)); |
| return INVALID_OPERATION; |
| } |
| |
| AidlProviderInfo::AidlProviderInfo( |
| const std::string &providerName, |
| const std::string &providerInstance, |
| CameraProviderManager *manager) : |
| CameraProviderManager::ProviderInfo(providerName, providerInstance, manager) {} |
| |
| status_t AidlProviderInfo::initializeAidlProvider( |
| std::shared_ptr<ICameraProvider>& interface, int64_t currentDeviceState) { |
| |
| using aidl::android::hardware::camera::provider::ICameraProvider; |
| std::string parsedProviderName = mProviderName; |
| if (flags::lazy_aidl_wait_for_service()) { |
| parsedProviderName = |
| mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1); |
| } |
| |
| status_t res = parseProviderName(parsedProviderName, &mType, &mId); |
| if (res != OK) { |
| ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| ALOGI("Connecting to new camera provider: %s, isRemote? %d", |
| mProviderName.c_str(), interface->isRemote()); |
| |
| // cameraDeviceStatusChange callbacks may be called (and causing new devices added) |
| // before setCallback returns |
| mCallbacks = |
| ndk::SharedRefBase::make<AidlProviderCallbacks>(this); |
| ndk::ScopedAStatus status = |
| interface->setCallback(mCallbacks); |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s", |
| __FUNCTION__, mProviderName.c_str(), status.getMessage()); |
| return mapToStatusT(status); |
| } |
| |
| mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(binderDied)); |
| |
| if (!vd_flags::virtual_camera_service_discovery() || interface->isRemote()) { |
| binder_status_t link = |
| AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(), this); |
| if (link != STATUS_OK) { |
| ALOGW("%s: Unable to link to provider '%s' death notifications (%d)", __FUNCTION__, |
| mProviderName.c_str(), link); |
| return DEAD_OBJECT; |
| } |
| } |
| |
| if (!kEnableLazyHal) { |
| // Save HAL reference indefinitely |
| mSavedInterface = interface; |
| } else { |
| mActiveInterface = interface; |
| } |
| |
| ALOGV("%s: Setting device state for %s: 0x%" PRIx64, |
| __FUNCTION__, mProviderName.c_str(), mDeviceState); |
| notifyDeviceStateChange(currentDeviceState); |
| |
| res = setUpVendorTags(); |
| if (res != OK) { |
| ALOGE("%s: Unable to set up vendor tags from provider '%s'", |
| __FUNCTION__, mProviderName.c_str()); |
| return res; |
| } |
| |
| // Get initial list of camera devices, if any |
| std::vector<std::string> devices; |
| std::vector<std::string> retDevices; |
| status = interface->getCameraIdList(&retDevices); |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s", |
| __FUNCTION__, mProviderName.c_str(), status.getMessage()); |
| return mapToStatusT(status); |
| } |
| |
| for (auto& name : retDevices) { |
| uint16_t major, minor; |
| std::string type, id; |
| status_t res = parseDeviceName(name, &major, &minor, &type, &id); |
| if (res != OK) { |
| ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res); |
| return res; |
| } else { |
| devices.push_back(name); |
| mProviderPublicCameraIds.push_back(id); |
| } |
| } |
| |
| // Get list of concurrent streaming camera device combinations |
| res = getConcurrentCameraIdsInternalLocked(interface); |
| if (res != OK) { |
| return res; |
| } |
| |
| mSetTorchModeSupported = true; |
| |
| mIsRemote = interface->isRemote(); |
| |
| initializeProviderInfoCommon(devices); |
| return OK; |
| } |
| |
| void AidlProviderInfo::binderDied(void *cookie) { |
| AidlProviderInfo *provider = reinterpret_cast<AidlProviderInfo *>(cookie); |
| ALOGI("Camera provider '%s' has died; removing it", provider->mProviderInstance.c_str()); |
| provider->mManager->removeProvider(provider->mProviderInstance); |
| } |
| |
| status_t AidlProviderInfo::setUpVendorTags() { |
| if (mVendorTagDescriptor != nullptr) |
| return OK; |
| |
| std::vector<camera::common::VendorTagSection> vts; |
| ::ndk::ScopedAStatus status; |
| const std::shared_ptr<ICameraProvider> interface = startProviderInterface(); |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| status = interface->getVendorTags(&vts); |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s", |
| __FUNCTION__, mProviderName.c_str(), status.getMessage()); |
| return mapToStatusT(status); |
| } |
| |
| // Read all vendor tag definitions into a descriptor |
| status_t res; |
| if ((res = |
| IdlVendorTagDescriptor:: |
| createDescriptorFromIdl<std::vector<camera::common::VendorTagSection>, |
| camera::common::VendorTagSection>(vts, /*out*/mVendorTagDescriptor)) |
| != OK) { |
| ALOGE("%s: Could not generate descriptor from vendor tag operations," |
| "received error %s (%d). Camera clients will not be able to use" |
| "vendor tags", __FUNCTION__, strerror(res), res); |
| return res; |
| } |
| |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::notifyDeviceStateChange(int64_t newDeviceState) { |
| |
| mDeviceState = newDeviceState; |
| // Check if the provider is currently active - not going to start it up for this notification |
| auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock(); |
| if (interface != nullptr) { |
| // Send current device state |
| interface->notifyDeviceStateChange(mDeviceState); |
| } |
| return OK; |
| } |
| |
| bool AidlProviderInfo::successfullyStartedProviderInterface() { |
| return startProviderInterface() != nullptr; |
| } |
| |
| std::shared_ptr<camera::device::ICameraDevice> |
| AidlProviderInfo::startDeviceInterface(const std::string &name) { |
| ::ndk::ScopedAStatus status; |
| std::shared_ptr<camera::device::ICameraDevice> cameraInterface; |
| const std::shared_ptr<ICameraProvider> interface = startProviderInterface(); |
| if (interface == nullptr) { |
| return nullptr; |
| } |
| status = interface->getCameraDeviceInterface(name, &cameraInterface); |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s", |
| __FUNCTION__, name.c_str(), status.getMessage()); |
| return nullptr; |
| } |
| return cameraInterface; |
| } |
| |
| const std::shared_ptr<ICameraProvider> AidlProviderInfo::startProviderInterface() { |
| ATRACE_CALL(); |
| ALOGV("Request to start camera provider: %s", mProviderName.c_str()); |
| if (mSavedInterface != nullptr) { |
| return mSavedInterface; |
| } |
| if (!kEnableLazyHal) { |
| ALOGE("Bad provider state! Should not be here on a non-lazy HAL!"); |
| return nullptr; |
| } |
| |
| auto interface = mActiveInterface.lock(); |
| if (interface == nullptr) { |
| // Try to get service without starting |
| interface = |
| ICameraProvider::fromBinder( |
| ndk::SpAIBinder(AServiceManager_checkService(mProviderName.c_str()))); |
| if (interface == nullptr) { |
| ALOGV("Camera provider actually needs restart, calling getService(%s)", |
| mProviderName.c_str()); |
| interface = mManager->mAidlServiceProxy->getAidlService(mProviderName.c_str()); |
| |
| if (interface == nullptr) { |
| ALOGD("%s: %s service not started", __FUNCTION__, mProviderName.c_str()); |
| return nullptr; |
| } |
| |
| // Set all devices as ENUMERATING, provider should update status |
| // to PRESENT after initializing. |
| // This avoids failing getCameraDeviceInterface_V3_x before devices |
| // are ready. |
| for (auto& device : mDevices) { |
| device->mIsDeviceAvailable = false; |
| } |
| |
| interface->setCallback(mCallbacks); |
| auto link = AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(), |
| this); |
| if (link != STATUS_OK) { |
| ALOGW("%s: Unable to link to provider '%s' death notifications", |
| __FUNCTION__, mProviderName.c_str()); |
| mManager->removeProvider(mProviderInstance); |
| return nullptr; |
| } |
| |
| // Send current device state |
| interface->notifyDeviceStateChange(mDeviceState); |
| } |
| mActiveInterface = interface; |
| } else { |
| ALOGV("Camera provider (%s) already in use. Re-using instance.", |
| mProviderName.c_str()); |
| } |
| |
| return interface; |
| } |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::cameraDeviceStatusChange( |
| const std::string& cameraDeviceName, |
| HalDeviceStatusType newStatus) { |
| sp<AidlProviderInfo> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: Parent provider not alive", __FUNCTION__); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| return parent->cameraDeviceStatusChange(cameraDeviceName, newStatus); |
| } |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::torchModeStatusChange( |
| const std::string& cameraDeviceName, |
| aidl::android::hardware::camera::common::TorchModeStatus newStatus) { |
| sp<AidlProviderInfo> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: Parent provider not alive", __FUNCTION__); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| return parent->torchModeStatusChange(cameraDeviceName, newStatus); |
| |
| }; |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::AidlProviderCallbacks::physicalCameraDeviceStatusChange( |
| const std::string& cameraDeviceName, |
| const std::string& physicalCameraDeviceName, |
| HalDeviceStatusType newStatus) { |
| sp<AidlProviderInfo> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: Parent provider not alive", __FUNCTION__); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| return parent->physicalCameraDeviceStatusChange(cameraDeviceName, physicalCameraDeviceName, |
| newStatus); |
| }; |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::cameraDeviceStatusChange(const std::string& cameraDeviceName, |
| HalDeviceStatusType newStatus) { |
| cameraDeviceStatusChangeInternal(cameraDeviceName, HalToFrameworkCameraDeviceStatus(newStatus)); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::torchModeStatusChange(const std::string& cameraDeviceName, |
| aidl::android::hardware::camera::common::TorchModeStatus newStatus) { |
| torchModeStatusChangeInternal(cameraDeviceName, HalToFrameworkTorchModeStatus(newStatus)); |
| return ::ndk::ScopedAStatus::ok(); |
| }; |
| |
| ::ndk::ScopedAStatus AidlProviderInfo::physicalCameraDeviceStatusChange( |
| const std::string& cameraDeviceName, |
| const std::string& physicalCameraDeviceName, |
| HalDeviceStatusType newStatus) { |
| physicalCameraDeviceStatusChangeInternal(cameraDeviceName, physicalCameraDeviceName, |
| HalToFrameworkCameraDeviceStatus(newStatus)); |
| return ::ndk::ScopedAStatus::ok(); |
| }; |
| |
| std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo> |
| AidlProviderInfo::initializeDeviceInfo( |
| const std::string &name, const metadata_vendor_id_t tagId, |
| const std::string &id, uint16_t /*minorVersion*/) { |
| ::ndk::ScopedAStatus status; |
| |
| auto cameraInterface = startDeviceInterface(name); |
| if (cameraInterface == nullptr) return nullptr; |
| |
| camera::common::CameraResourceCost resourceCost; |
| status = cameraInterface->getResourceCost(&resourceCost); |
| if (!status.isOk()) { |
| ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__, |
| name.c_str(), status.getMessage()); |
| return nullptr; |
| } |
| |
| for (auto& conflictName : resourceCost.conflictingDevices) { |
| uint16_t major, minor; |
| std::string type, id; |
| status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id); |
| if (res != OK) { |
| ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str()); |
| return nullptr; |
| } |
| conflictName = id; |
| } |
| |
| int32_t interfaceVersion = 0; |
| status = cameraInterface->getInterfaceVersion(&interfaceVersion); |
| if (!status.isOk()) { |
| ALOGE("%s: Unable to obtain interface version for camera device %s: %s", __FUNCTION__, |
| id.c_str(), status.getMessage()); |
| return nullptr; |
| } |
| |
| return std::unique_ptr<DeviceInfo3>( |
| new AidlDeviceInfo3(name, tagId, id, static_cast<uint16_t>(interfaceVersion), |
| HalToFrameworkResourceCost(resourceCost), this, |
| mProviderPublicCameraIds, cameraInterface)); |
| } |
| |
| status_t AidlProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() { |
| |
| // Check if the provider is currently active - not going to start it up for this notification |
| auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock(); |
| if (interface == nullptr) { |
| ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__, |
| mProviderName.c_str()); |
| return INVALID_OPERATION; |
| } |
| |
| return getConcurrentCameraIdsInternalLocked(interface); |
| } |
| |
| status_t AidlProviderInfo::getConcurrentCameraIdsInternalLocked( |
| std::shared_ptr<ICameraProvider> &interface) { |
| if (interface == nullptr) { |
| ALOGE("%s: null interface provided", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| std::vector<aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination> combs; |
| ::ndk::ScopedAStatus status = interface->getConcurrentCameraIds(&combs); |
| |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'", |
| __FUNCTION__, mProviderName.c_str()); |
| return mapToStatusT(status); |
| } |
| mConcurrentCameraIdCombinations.clear(); |
| for (const auto& combination : combs) { |
| std::unordered_set<std::string> deviceIds; |
| for (const auto &cameraDeviceId : combination.combination) { |
| deviceIds.insert(cameraDeviceId); |
| } |
| mConcurrentCameraIdCombinations.push_back(std::move(deviceIds)); |
| } |
| |
| return OK; |
| } |
| |
| AidlProviderInfo::AidlDeviceInfo3::AidlDeviceInfo3( |
| const std::string& name, |
| const metadata_vendor_id_t tagId, |
| const std::string &id, uint16_t minorVersion, |
| const CameraResourceCost& resourceCost, |
| sp<CameraProviderManager::ProviderInfo> parentProvider, |
| const std::vector<std::string>& publicCameraIds, |
| std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice> interface) : |
| DeviceInfo3(name, tagId, id, minorVersion, resourceCost, parentProvider, publicCameraIds) { |
| |
| // Get camera characteristics and initialize flash unit availability |
| aidl::android::hardware::camera::device::CameraMetadata chars; |
| ::ndk::ScopedAStatus status = interface->getCameraCharacteristics(&chars); |
| std::vector<uint8_t> &metadata = chars.metadata; |
| camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data()); |
| size_t expectedSize = metadata.size(); |
| int resV = validate_camera_metadata_structure(buffer, &expectedSize); |
| if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| set_camera_metadata_vendor_id(buffer, mProviderTagid); |
| mCameraCharacteristics = buffer; |
| } else { |
| ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__); |
| return; |
| } |
| |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error getting camera characteristics for device %s" |
| " to check for a flash unit: %s", __FUNCTION__, id.c_str(), |
| status.getMessage()); |
| return; |
| } |
| |
| if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) { |
| const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS); |
| if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) { |
| for (size_t i = 0; i < stateMap.count; i += 2) { |
| mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]); |
| } |
| } else { |
| ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__, |
| stateMap.count); |
| } |
| } |
| |
| mCompositeJpegRDisabled = mCameraCharacteristics.exists( |
| ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS); |
| |
| mSystemCameraKind = getSystemCameraKind(); |
| |
| status_t res = fixupMonochromeTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| if (flags::camera_manual_flash_strength_control()) { |
| res = fixupManualFlashStrengthControlTags(mCameraCharacteristics); |
| if (OK != res) { |
| ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| } |
| |
| auto stat = addDynamicDepthTags(); |
| if (OK != stat) { |
| ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat), |
| stat); |
| } |
| res = deriveHeicTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| res = deriveJpegRTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to derive Jpeg/R tags based on camera and media capabilities: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| using camera3::SessionConfigurationUtils::supportsUltraHighResolutionCapture; |
| if (supportsUltraHighResolutionCapture(mCameraCharacteristics)) { |
| status_t status = addDynamicDepthTags(/*maxResolution*/true); |
| if (OK != status) { |
| ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)", |
| __FUNCTION__, strerror(-status), status); |
| } |
| |
| status = deriveHeicTags(/*maxResolution*/true); |
| if (OK != status) { |
| ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for" |
| "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status); |
| } |
| |
| status = deriveJpegRTags(/*maxResolution*/true); |
| if (OK != status) { |
| ALOGE("%s: Unable to derive Jpeg/R tags based on camera and media capabilities for" |
| "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status); |
| } |
| } |
| |
| res = addRotateCropTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__, |
| strerror(-res), res); |
| } |
| res = addAutoframingTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add default AUTOFRAMING tags: %s (%d)", __FUNCTION__, |
| strerror(-res), res); |
| } |
| res = addPreCorrectionActiveArraySize(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__, |
| strerror(-res), res); |
| } |
| res = camera3::ZoomRatioMapper::overrideZoomRatioTags( |
| &mCameraCharacteristics, &mSupportNativeZoomRatio); |
| if (OK != res) { |
| ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| res = addReadoutTimestampTag(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add sensorReadoutTimestamp tag: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| |
| camera_metadata_entry flashAvailable = |
| mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE); |
| if (flashAvailable.count == 1 && |
| flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) { |
| mHasFlashUnit = true; |
| // Fix up flash strength tags for devices without these keys. |
| res = fixupTorchStrengthTags(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and" |
| "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__, |
| strerror(-res), res); |
| } |
| |
| // b/247038031: In case of system_server crash, camera_server is |
| // restarted as well. If flashlight is turned on before the crash, it |
| // may be stuck to be on. As a workaround, set torch mode to be OFF. |
| interface->setTorchMode(false); |
| } else { |
| mHasFlashUnit = false; |
| } |
| |
| if (flags::feature_combination_query()) { |
| res = addSessionConfigQueryVersionTag(); |
| if (OK != res) { |
| ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| } |
| |
| camera_metadata_entry entry = |
| mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL); |
| if (entry.count == 1) { |
| mTorchDefaultStrengthLevel = entry.data.i32[0]; |
| } else { |
| mTorchDefaultStrengthLevel = 0; |
| } |
| entry = mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL); |
| if (entry.count == 1) { |
| mTorchMaximumStrengthLevel = entry.data.i32[0]; |
| } else { |
| mTorchMaximumStrengthLevel = 0; |
| } |
| |
| mTorchStrengthLevel = 0; |
| |
| queryPhysicalCameraIds(); |
| |
| // Get physical camera characteristics if applicable |
| if (mIsLogicalCamera) { |
| for (auto& id : mPhysicalIds) { |
| if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) != |
| mPublicCameraIds.end()) { |
| continue; |
| } |
| |
| aidl::android::hardware::camera::device::CameraMetadata pChars; |
| status = interface->getPhysicalCameraCharacteristics(id, &pChars); |
| if (!status.isOk()) { |
| ALOGE("%s: Transaction error getting physical camera %s characteristics for " |
| "logical id %s: %s", __FUNCTION__, id.c_str(), mId.c_str(), |
| status.getMessage()); |
| return; |
| } |
| std::vector<uint8_t> &pMetadata = pChars.metadata; |
| camera_metadata_t *pBuffer = |
| reinterpret_cast<camera_metadata_t*>(pMetadata.data()); |
| size_t expectedSize = pMetadata.size(); |
| int res = validate_camera_metadata_structure(pBuffer, &expectedSize); |
| if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| set_camera_metadata_vendor_id(pBuffer, mProviderTagid); |
| mPhysicalCameraCharacteristics[id] = pBuffer; |
| } else { |
| ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__); |
| return; |
| } |
| |
| res = camera3::ZoomRatioMapper::overrideZoomRatioTags( |
| &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio); |
| if (OK != res) { |
| ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| } |
| |
| if (flags::camera_manual_flash_strength_control()) { |
| res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]); |
| if (OK != res) { |
| ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| } |
| } |
| } |
| |
| if (!kEnableLazyHal) { |
| // Save HAL reference indefinitely |
| mSavedInterface = interface; |
| } |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::setTorchMode(bool enabled) { |
| const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface(); |
| ::ndk::ScopedAStatus s = interface->setTorchMode(enabled); |
| if (!s.isOk()) { |
| ALOGE("%s Unable to set torch mode: %s", __FUNCTION__, s.getMessage()); |
| return mapToStatusT(s); |
| } |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::turnOnTorchWithStrengthLevel( |
| int32_t torchStrength) { |
| const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface(); |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| |
| ::ndk::ScopedAStatus s = interface->turnOnTorchWithStrengthLevel(torchStrength); |
| if (!s.isOk()) { |
| ALOGE("%s Unable to set torch mode strength %d : %s", __FUNCTION__, torchStrength, |
| s.getMessage()); |
| return mapToStatusT(s); |
| } |
| mTorchStrengthLevel = torchStrength; |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::getTorchStrengthLevel(int32_t *torchStrength) { |
| if (torchStrength == nullptr) { |
| return BAD_VALUE; |
| } |
| const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface(); |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| |
| ::ndk::ScopedAStatus status = interface->getTorchStrengthLevel(torchStrength); |
| if (!status.isOk()) { |
| ALOGE("%s: Couldn't get torch strength level: %s", __FUNCTION__, status.getMessage()); |
| return mapToStatusT(status); |
| } |
| return OK; |
| } |
| |
| std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice> |
| AidlProviderInfo::AidlDeviceInfo3::startDeviceInterface() { |
| Mutex::Autolock l(mDeviceAvailableLock); |
| std::shared_ptr<camera::device::ICameraDevice> device; |
| ATRACE_CALL(); |
| if (mSavedInterface == nullptr) { |
| sp<AidlProviderInfo> parentProvider = |
| static_cast<AidlProviderInfo *>(mParentProvider.promote().get()); |
| if (parentProvider != nullptr) { |
| // Wait for lazy HALs to confirm device availability |
| if (parentProvider->isExternalLazyHAL() && !mIsDeviceAvailable) { |
| ALOGV("%s: Wait for external device to become available %s", |
| __FUNCTION__, |
| mId.c_str()); |
| |
| auto res = mDeviceAvailableSignal.waitRelative(mDeviceAvailableLock, |
| kDeviceAvailableTimeout); |
| if (res != OK) { |
| ALOGE("%s: Failed waiting for device to become available", |
| __FUNCTION__); |
| return nullptr; |
| } |
| } |
| |
| device = parentProvider->startDeviceInterface(mName); |
| } |
| } else { |
| device = mSavedInterface; |
| } |
| return device; |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::dumpState(int fd) { |
| const std::shared_ptr<camera::device::ICameraDevice> interface = startDeviceInterface(); |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| const char *args = nullptr; |
| auto ret = interface->dump(fd, &args, /*numArgs*/0); |
| if (ret != OK) { |
| return ret; |
| } |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported( |
| const SessionConfiguration &configuration, bool overrideForPerfClass, |
| bool checkSessionParams, bool *status) { |
| |
| auto operatingMode = configuration.getOperatingMode(); |
| |
| auto res = SessionConfigurationUtils::checkOperatingMode(operatingMode, |
| mCameraCharacteristics, mId); |
| if (!res.isOk()) { |
| return UNKNOWN_ERROR; |
| } |
| |
| camera::device::StreamConfiguration streamConfiguration; |
| bool earlyExit = false; |
| camera3::metadataGetter getMetadata = [this](const std::string &id, |
| bool /*overrideForPerfClass*/) {return this->deviceInfo(id);}; |
| auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration, |
| mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata, |
| mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid, |
| checkSessionParams, &earlyExit); |
| |
| if (!bRes.isOk()) { |
| return UNKNOWN_ERROR; |
| } |
| |
| if (earlyExit) { |
| *status = false; |
| return OK; |
| } |
| |
| const std::shared_ptr<camera::device::ICameraDevice> interface = |
| startDeviceInterface(); |
| |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| |
| ::ndk::ScopedAStatus ret; |
| if (checkSessionParams) { |
| // Only interface version 1_3 or greater supports |
| // isStreamCombinationWIthSettingsSupported. |
| int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor()); |
| if (deviceVersion < CAMERA_DEVICE_API_VERSION_1_3) { |
| ALOGI("%s: Camera device version (major %d, minor %d) doesn't support querying of " |
| "session configuration!", __FUNCTION__, mVersion.get_major(), |
| mVersion.get_minor()); |
| return INVALID_OPERATION; |
| } |
| if (flags::feature_combination_query()) { |
| ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status); |
| } else { |
| return INVALID_OPERATION; |
| } |
| } else { |
| ret = interface->isStreamCombinationSupported(streamConfiguration, status); |
| } |
| if (!ret.isOk()) { |
| *status = false; |
| ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage()); |
| return mapToStatusT(ret); |
| } |
| return OK; |
| |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::createDefaultRequest( |
| camera3::camera_request_template_t templateId, camera_metadata_t** metadata) { |
| const std::shared_ptr<camera::device::ICameraDevice> interface = |
| startDeviceInterface(); |
| |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| |
| int deviceVersion = HARDWARE_DEVICE_API_VERSION(mVersion.get_major(), mVersion.get_minor()); |
| if (deviceVersion < CAMERA_DEVICE_API_VERSION_1_3) { |
| ALOGI("%s: Camera device minor version 0x%x doesn't support creating " |
| " default request!", __FUNCTION__, mVersion.get_minor()); |
| return INVALID_OPERATION; |
| } |
| |
| aidl::android::hardware::camera::device::CameraMetadata request; |
| |
| using aidl::android::hardware::camera::device::RequestTemplate; |
| RequestTemplate id; |
| status_t res = SessionConfigurationUtils::mapRequestTemplateToAidl( |
| templateId, &id); |
| if (res != OK) { |
| return res; |
| } |
| |
| if (!flags::feature_combination_query()) { |
| return INVALID_OPERATION; |
| } |
| |
| auto err = interface->constructDefaultRequestSettings(id, &request); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage()); |
| return AidlProviderInfo::mapToStatusT(err); |
| } |
| const camera_metadata *r = |
| reinterpret_cast<const camera_metadata_t*>(request.metadata.data()); |
| size_t expectedSize = request.metadata.size(); |
| int ret = validate_camera_metadata_structure(r, &expectedSize); |
| if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| *metadata = clone_camera_metadata(r); |
| if (*metadata == nullptr) { |
| ALOGE("%s: Unable to clone camera metadata received from HAL", |
| __FUNCTION__); |
| res = UNKNOWN_ERROR; |
| } |
| } else { |
| ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__); |
| res = UNKNOWN_ERROR; |
| } |
| |
| return res; |
| } |
| |
| status_t AidlProviderInfo::AidlDeviceInfo3::getSessionCharacteristics( |
| const SessionConfiguration &configuration, bool overrideForPerfClass, |
| camera3::metadataGetter getMetadata, CameraMetadata *sessionCharacteristics) { |
| camera::device::StreamConfiguration streamConfiguration; |
| bool earlyExit = false; |
| auto res = SessionConfigurationUtils::convertToHALStreamCombination(configuration, |
| mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata, |
| mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid, |
| /*checkSessionParams*/true, &earlyExit); |
| |
| if (!res.isOk()) { |
| return UNKNOWN_ERROR; |
| } |
| |
| if (earlyExit) { |
| return BAD_VALUE; |
| } |
| |
| const std::shared_ptr<camera::device::ICameraDevice> interface = |
| startDeviceInterface(); |
| |
| if (interface == nullptr) { |
| return DEAD_OBJECT; |
| } |
| |
| aidl::android::hardware::camera::device::CameraMetadata chars; |
| ::ndk::ScopedAStatus ret = |
| interface->getSessionCharacteristics(streamConfiguration, &chars); |
| std::vector<uint8_t> &metadata = chars.metadata; |
| |
| camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data()); |
| size_t expectedSize = metadata.size(); |
| int resV = validate_camera_metadata_structure(buffer, &expectedSize); |
| if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| set_camera_metadata_vendor_id(buffer, mProviderTagid); |
| *sessionCharacteristics = buffer; |
| } else { |
| ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| if (!ret.isOk()) { |
| ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage()); |
| return mapToStatusT(ret); |
| } |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked( |
| const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs, |
| const std::set<std::string>& perfClassPrimaryCameraIds, |
| int targetSdkVersion, |
| std::vector<camera::provider::CameraIdAndStreamCombination> |
| *halCameraIdsAndStreamCombinations, |
| bool *earlyExit) { |
| binder::Status bStatus = binder::Status::ok(); |
| std::vector<camera::provider::CameraIdAndStreamCombination> halCameraIdsAndStreamsV; |
| bool shouldExit = false; |
| status_t res = OK; |
| for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) { |
| const std::string& cameraId = cameraIdAndSessionConfig.mCameraId; |
| camera::device::StreamConfiguration streamConfiguration; |
| CameraMetadata deviceInfo; |
| bool overrideForPerfClass = |
| SessionConfigurationUtils::targetPerfClassPrimaryCamera( |
| perfClassPrimaryCameraIds, cameraId, targetSdkVersion); |
| res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo, |
| /*overrideToPortrait*/false); |
| if (res != OK) { |
| return res; |
| } |
| camera3::metadataGetter getMetadata = |
| [this](const std::string &id, bool overrideForPerfClass) { |
| CameraMetadata physicalDeviceInfo; |
| mManager->getCameraCharacteristicsLocked(id, overrideForPerfClass, |
| &physicalDeviceInfo, |
| /*overrideToPortrait*/false); |
| return physicalDeviceInfo; |
| }; |
| std::vector<std::string> physicalCameraIds; |
| mManager->isLogicalCameraLocked(cameraId, &physicalCameraIds); |
| bStatus = |
| SessionConfigurationUtils::convertToHALStreamCombination( |
| cameraIdAndSessionConfig.mSessionConfiguration, |
| cameraId, deviceInfo, |
| mManager->isCompositeJpegRDisabledLocked(cameraId), getMetadata, |
| physicalCameraIds, streamConfiguration, |
| overrideForPerfClass, mProviderTagid, |
| /*checkSessionParams*/false, &shouldExit); |
| if (!bStatus.isOk()) { |
| ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| if (shouldExit) { |
| *earlyExit = true; |
| return OK; |
| } |
| camera::provider::CameraIdAndStreamCombination halCameraIdAndStream; |
| halCameraIdAndStream.cameraId = cameraId; |
| halCameraIdAndStream.streamConfiguration = streamConfiguration; |
| halCameraIdsAndStreamsV.push_back(halCameraIdAndStream); |
| } |
| *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV; |
| return OK; |
| } |
| |
| status_t AidlProviderInfo::isConcurrentSessionConfigurationSupported( |
| const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs, |
| const std::set<std::string>& perfClassPrimaryCameraIds, |
| int targetSdkVersion, bool *isSupported) { |
| |
| std::vector<camera::provider::CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations; |
| bool knowUnsupported = false; |
| status_t res = convertToAidlHALStreamCombinationAndCameraIdsLocked( |
| cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds, |
| targetSdkVersion, &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; |
| } |
| |
| // Check if the provider is currently active - not going to start it up for this notification |
| auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.lock(); |
| if (interface == nullptr) { |
| // TODO: This might be some other problem |
| return INVALID_OPERATION; |
| } |
| ::ndk::ScopedAStatus status = interface->isConcurrentStreamCombinationSupported( |
| halCameraIdsAndStreamCombinations, isSupported); |
| if (!status.isOk()) { |
| *isSupported = false; |
| ALOGE("%s: hal interface session configuration query failed", __FUNCTION__); |
| return mapToStatusT(status); |
| } |
| |
| return OK; |
| } |
| |
| } //namespace android |