| /* |
| * 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. |
| */ |
| |
| #define LOG_TAG "GCH_AidlCameraProvider" |
| //#define LOG_NDEBUG 0 |
| #include "aidl_camera_provider.h" |
| |
| #include <log/log.h> |
| |
| #include <regex> |
| |
| #include "aidl_camera_device.h" |
| #include "aidl_utils.h" |
| #include "camera_device.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace camera { |
| namespace provider { |
| namespace implementation { |
| |
| namespace aidl_utils = ::android::hardware::camera::implementation::aidl_utils; |
| |
| using aidl::android::hardware::camera::common::CameraDeviceStatus; |
| using aidl::android::hardware::camera::common::Status; |
| using aidl::android::hardware::camera::common::TorchModeStatus; |
| using aidl::android::hardware::camera::common::VendorTagSection; |
| using ::android::google_camera_hal::CameraDevice; |
| |
| const std::string AidlCameraProvider::kProviderName = "internal"; |
| // "device@<version>/internal/<id>" |
| const std::regex AidlCameraProvider::kDeviceNameRegex( |
| "device@([0-9]+\\.[0-9]+)/internal/(.+)"); |
| |
| std::shared_ptr<AidlCameraProvider> AidlCameraProvider::Create() { |
| std::shared_ptr<AidlCameraProvider> provider = |
| ndk::SharedRefBase::make<AidlCameraProvider>(); |
| |
| status_t res = provider->Initialize(); |
| if (res != OK) { |
| ALOGE("%s: Initializing AidlCameraProvider failed: %s(%d)", __FUNCTION__, |
| strerror(-res), res); |
| return nullptr; |
| } |
| |
| return provider; |
| } |
| |
| status_t AidlCameraProvider::Initialize() { |
| google_camera_provider_ = CameraProvider::Create(); |
| if (google_camera_provider_ == nullptr) { |
| ALOGE("%s: Creating CameraProvider failed.", __FUNCTION__); |
| return NO_INIT; |
| } |
| |
| camera_provider_callback_ = { |
| .camera_device_status_change = google_camera_hal::CameraDeviceStatusChangeFunc( |
| [this](std::string camera_id, |
| google_camera_hal::CameraDeviceStatus new_status) { |
| if (callbacks_ == nullptr) { |
| ALOGE("%s: callbacks_ is null", __FUNCTION__); |
| return; |
| } |
| CameraDeviceStatus aidl_camera_device_status; |
| status_t res = aidl_utils::ConvertToAidlCameraDeviceStatus( |
| new_status, &aidl_camera_device_status); |
| if (res != OK) { |
| ALOGE( |
| "%s: Converting to aidl camera device status failed: %s(%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| |
| std::unique_lock<std::mutex> lock(callbacks_lock_); |
| auto aidl_res = callbacks_->cameraDeviceStatusChange( |
| "device@" + |
| device::implementation::AidlCameraDevice::kDeviceVersion + |
| "/" + kProviderName + "/" + camera_id, |
| aidl_camera_device_status); |
| if (!aidl_res.isOk()) { |
| ALOGE("%s: device status change transaction error: %s", |
| __FUNCTION__, aidl_res.getMessage()); |
| return; |
| } |
| }), |
| .physical_camera_device_status_change = |
| google_camera_hal::PhysicalCameraDeviceStatusChangeFunc( |
| [this](std::string camera_id, std::string physical_camera_id, |
| google_camera_hal::CameraDeviceStatus new_status) { |
| if (callbacks_ == nullptr) { |
| ALOGE("%s: callbacks_ is null", __FUNCTION__); |
| return; |
| } |
| /*auto castResult = |
| provider::V2_6::ICameraProviderCallback::castFrom(callbacks_); |
| if (!castResult.isOk()) { |
| ALOGE("%s: callbacks_ cannot be casted to version 2.6", |
| __FUNCTION__); |
| return; |
| } |
| sp<provider::V2_6::ICameraProviderCallback> callbacks_2_6_ = |
| castResult; |
| if (callbacks_2_6_ == nullptr) { |
| ALOGE("%s: callbacks_2_6_ is null", __FUNCTION__); |
| return; |
| }*/ |
| |
| CameraDeviceStatus aidl_camera_device_status; |
| status_t res = aidl_utils::ConvertToAidlCameraDeviceStatus( |
| new_status, &aidl_camera_device_status); |
| if (res != OK) { |
| ALOGE( |
| "%s: Converting to aidl camera device status failed: " |
| "%s(%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| |
| std::unique_lock<std::mutex> lock(callbacks_lock_); |
| auto aidl_res = callbacks_->physicalCameraDeviceStatusChange( |
| "device@" + |
| device::implementation::AidlCameraDevice::kDeviceVersion + |
| "/" + kProviderName + "/" + camera_id, |
| physical_camera_id, aidl_camera_device_status); |
| if (!aidl_res.isOk()) { |
| ALOGE( |
| "%s: physical camera status change transaction error: %s", |
| __FUNCTION__, aidl_res.getMessage()); |
| return; |
| } |
| }), |
| .torch_mode_status_change = google_camera_hal::TorchModeStatusChangeFunc( |
| [this](std::string camera_id, |
| google_camera_hal::TorchModeStatus new_status) { |
| if (callbacks_ == nullptr) { |
| ALOGE("%s: callbacks_ is null", __FUNCTION__); |
| return; |
| } |
| |
| TorchModeStatus aidl_torch_status; |
| status_t res = aidl_utils::ConvertToAidlTorchModeStatus( |
| new_status, &aidl_torch_status); |
| if (res != OK) { |
| ALOGE("%s: Converting to aidl torch status failed: %s(%d)", |
| __FUNCTION__, strerror(-res), res); |
| return; |
| } |
| |
| std::unique_lock<std::mutex> lock(callbacks_lock_); |
| auto aidl_res = callbacks_->torchModeStatusChange( |
| "device@" + |
| device::implementation::AidlCameraDevice::kDeviceVersion + |
| "/" + kProviderName + "/" + camera_id, |
| aidl_torch_status); |
| if (!aidl_res.isOk()) { |
| ALOGE("%s: torch status change transaction error: %s", |
| __FUNCTION__, aidl_res.getMessage()); |
| return; |
| } |
| }), |
| }; |
| |
| google_camera_provider_->SetCallback(&camera_provider_callback_); |
| // purge pending malloc pages after initialization |
| mallopt(M_PURGE, 0); |
| return OK; |
| } |
| |
| ScopedAStatus AidlCameraProvider::setCallback( |
| const std::shared_ptr<ICameraProviderCallback>& callback) { |
| if (callback == nullptr) { |
| ALOGE("AidlCameraProvider::setCallback() called with nullptr"); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| |
| bool first_time = false; |
| { |
| std::unique_lock<std::mutex> lock(callbacks_lock_); |
| first_time = callbacks_ == nullptr; |
| callbacks_ = callback; |
| } |
| google_camera_provider_->TriggerDeferredCallbacks(); |
| #ifdef __ANDROID_APEX__ |
| if (first_time) { |
| std::string ready_property_name = "vendor.camera.hal.ready.count"; |
| int ready_count = property_get_int32(ready_property_name.c_str(), 0); |
| property_set(ready_property_name.c_str(), |
| std::to_string(++ready_count).c_str()); |
| ALOGI("AidlCameraProvider::setCallback() first time ready count: %d ", |
| ready_count); |
| } |
| #endif |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlCameraProvider::getVendorTags( |
| std::vector<VendorTagSection>* vts) { |
| if (vts == nullptr) { |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| vts->clear(); |
| std::vector<google_camera_hal::VendorTagSection> hal_vendor_tag_sections; |
| |
| status_t res = |
| google_camera_provider_->GetVendorTags(&hal_vendor_tag_sections); |
| if (res != OK) { |
| ALOGE("%s: Getting vendor tags failed: %s(%d)", __FUNCTION__, |
| strerror(-res), res); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| |
| res = aidl_utils::ConvertToAidlVendorTagSections(hal_vendor_tag_sections, vts); |
| if (res != OK) { |
| ALOGE("%s: Converting to aidl vendor tags failed: %s(%d)", __FUNCTION__, |
| strerror(-res), res); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlCameraProvider::getCameraIdList( |
| std::vector<std::string>* camera_ids_ret) { |
| if (camera_ids_ret == nullptr) { |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| camera_ids_ret->clear(); |
| std::vector<uint32_t> camera_ids; |
| status_t res = google_camera_provider_->GetCameraIdList(&camera_ids); |
| if (res != OK) { |
| ALOGE("%s: Getting camera ID list failed: %s(%d)", __FUNCTION__, |
| strerror(-res), res); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| |
| camera_ids_ret->resize(camera_ids.size()); |
| for (uint32_t i = 0; i < camera_ids_ret->size(); i++) { |
| // camera ID is in the form of "device@<major>.<minor>/<type>/<id>" |
| (*camera_ids_ret)[i] = |
| "device@" + device::implementation::AidlCameraDevice::kDeviceVersion + |
| "/" + kProviderName + "/" + std::to_string(camera_ids[i]); |
| } |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlCameraProvider::getConcurrentCameraIds( |
| std::vector<ConcurrentCameraIdCombination>* aidl_camera_id_combinations) { |
| if (aidl_camera_id_combinations == nullptr) { |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| aidl_camera_id_combinations->clear(); |
| std::vector<std::unordered_set<uint32_t>> camera_id_combinations; |
| status_t res = google_camera_provider_->GetConcurrentStreamingCameraIds( |
| &camera_id_combinations); |
| if (res != OK) { |
| ALOGE( |
| "%s: Getting the combinations of concurrent streaming camera ids " |
| "failed: %s(%d)", |
| __FUNCTION__, strerror(-res), res); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| aidl_camera_id_combinations->resize(camera_id_combinations.size()); |
| int i = 0; |
| for (auto& combination : camera_id_combinations) { |
| std::vector<std::string> aidl_combination(combination.size()); |
| int c = 0; |
| for (auto& camera_id : combination) { |
| aidl_combination[c] = std::to_string(camera_id); |
| c++; |
| } |
| (*aidl_camera_id_combinations)[i].combination = aidl_combination; |
| i++; |
| } |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlCameraProvider::isConcurrentStreamCombinationSupported( |
| const std::vector<CameraIdAndStreamCombination>& configs, bool* supported) { |
| *supported = false; |
| std::vector<google_camera_hal::CameraIdAndStreamConfiguration> |
| devices_stream_configs(configs.size()); |
| status_t res = OK; |
| size_t c = 0; |
| for (auto& config : configs) { |
| res = aidl_utils::ConvertToHalStreamConfig( |
| config.streamConfiguration, |
| &devices_stream_configs[c].stream_configuration); |
| if (res != OK) { |
| ALOGE("%s: ConverToHalStreamConfig failed", __FUNCTION__); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| uint32_t camera_id = atoi(config.cameraId.c_str()); |
| devices_stream_configs[c].camera_id = camera_id; |
| c++; |
| } |
| res = google_camera_provider_->IsConcurrentStreamCombinationSupported( |
| devices_stream_configs, supported); |
| if (res != OK) { |
| ALOGE("%s: ConverToHalStreamConfig failed", __FUNCTION__); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| return ScopedAStatus::ok(); |
| } |
| |
| bool AidlCameraProvider::ParseDeviceName(const std::string& device_name, |
| std::string* device_version, |
| std::string* camera_id) { |
| std::string device_name_std(device_name.c_str()); |
| std::smatch sm; |
| |
| if (std::regex_match(device_name_std, sm, |
| AidlCameraProvider::kDeviceNameRegex)) { |
| if (device_version != nullptr) { |
| *device_version = sm[1]; |
| } |
| if (camera_id != nullptr) { |
| *camera_id = sm[2]; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| ScopedAStatus AidlCameraProvider::getCameraDeviceInterface( |
| const std::string& camera_device_name, |
| std::shared_ptr<ICameraDevice>* device) { |
| std::unique_ptr<CameraDevice> google_camera_device; |
| if (device == nullptr) { |
| ALOGE("%s: device is nullptr. ", __FUNCTION__); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| |
| // Parse camera_device_name. |
| std::string camera_id, device_version; |
| |
| bool match = ParseDeviceName(camera_device_name, &device_version, &camera_id); |
| if (!match) { |
| ALOGE("%s: Device name parse fail. ", __FUNCTION__); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)); |
| } |
| |
| status_t res = google_camera_provider_->CreateCameraDevice( |
| atoi(camera_id.c_str()), &google_camera_device); |
| if (res != OK) { |
| ALOGE("%s: Creating CameraDevice failed: %s(%d)", __FUNCTION__, |
| strerror(-res), res); |
| return aidl_utils::ConvertToAidlReturn(res); |
| } |
| |
| *device = device::implementation::AidlCameraDevice::Create( |
| std::move(google_camera_device)); |
| if (*device == nullptr) { |
| ALOGE("%s: Creating AidlCameraDevice failed", __FUNCTION__); |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(Status::INTERNAL_ERROR)); |
| } |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlCameraProvider::notifyDeviceStateChange(int64_t new_state) { |
| google_camera_hal::DeviceState device_state = |
| google_camera_hal::DeviceState::kNormal; |
| ::android::hardware::camera::implementation::aidl_utils::ConvertToHalDeviceState( |
| new_state, device_state); |
| google_camera_provider_->NotifyDeviceStateChange(device_state); |
| return ScopedAStatus::ok(); |
| } |
| |
| } // namespace implementation |
| } // namespace provider |
| } // namespace camera |
| } // namespace hardware |
| } // namespace android |