/* * Copyright (C) 2016 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 "CamPrvdr@2.4-legacy" //#define LOG_NDEBUG 0 #include <android/log.h> #include "LegacyCameraProviderImpl_2_4.h" #include "CameraDevice_1_0.h" #include "CameraDevice_3_3.h" #include "CameraDevice_3_4.h" #include "CameraDevice_3_5.h" #include "CameraProvider_2_4.h" #include <cutils/properties.h> #include <regex> #include <string.h> #include <utils/Trace.h> namespace android { namespace hardware { namespace camera { namespace provider { namespace V2_4 { namespace implementation { template struct CameraProvider<LegacyCameraProviderImpl_2_4>; namespace { // "device@<version>/legacy/<id>" const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)"); const char *kHAL3_4 = "3.4"; const char *kHAL3_5 = "3.5"; const int kMaxCameraDeviceNameLen = 128; const int kMaxCameraIdLen = 16; bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion, std::string* cameraId) { std::string deviceNameStd(deviceName.c_str()); std::smatch sm; if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) { if (deviceVersion != nullptr) { *deviceVersion = sm[1]; } if (cameraId != nullptr) { *cameraId = sm[2]; } return true; } return false; } } // anonymous namespace using ::android::hardware::camera::common::V1_0::CameraMetadataType; using ::android::hardware::camera::common::V1_0::Status; void LegacyCameraProviderImpl_2_4::addDeviceNames(int camera_id, CameraDeviceStatus status, bool cam_new) { char cameraId[kMaxCameraIdLen]; snprintf(cameraId, sizeof(cameraId), "%d", camera_id); std::string cameraIdStr(cameraId); mCameraIds.add(cameraIdStr); // initialize mCameraDeviceNames and mOpenLegacySupported mOpenLegacySupported[cameraIdStr] = false; int deviceVersion = mModule->getDeviceVersion(camera_id); auto deviceNamePair = std::make_pair(cameraIdStr, getHidlDeviceName(cameraIdStr, deviceVersion)); mCameraDeviceNames.add(deviceNamePair); if (cam_new) { mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status); } if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 && mModule->isOpenLegacyDefined()) { // try open_legacy to see if it actually works struct hw_device_t* halDev = nullptr; int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev); if (ret == 0) { mOpenLegacySupported[cameraIdStr] = true; halDev->close(halDev); deviceNamePair = std::make_pair(cameraIdStr, getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)); mCameraDeviceNames.add(deviceNamePair); if (cam_new) { mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status); } } else if (ret == -EBUSY || ret == -EUSERS) { // Looks like this provider instance is not initialized during // system startup and there are other camera users already. // Not a good sign but not fatal. ALOGW("%s: open_legacy try failed!", __FUNCTION__); } } } void LegacyCameraProviderImpl_2_4::removeDeviceNames(int camera_id) { std::string cameraIdStr = std::to_string(camera_id); mCameraIds.remove(cameraIdStr); int deviceVersion = mModule->getDeviceVersion(camera_id); auto deviceNamePair = std::make_pair(cameraIdStr, getHidlDeviceName(cameraIdStr, deviceVersion)); mCameraDeviceNames.remove(deviceNamePair); mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, CameraDeviceStatus::NOT_PRESENT); if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 && mModule->isOpenLegacyDefined() && mOpenLegacySupported[cameraIdStr]) { deviceNamePair = std::make_pair(cameraIdStr, getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)); mCameraDeviceNames.remove(deviceNamePair); mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, CameraDeviceStatus::NOT_PRESENT); } mModule->removeCamera(camera_id); } /** * static callback forwarding methods from HAL to instance */ void LegacyCameraProviderImpl_2_4::sCameraDeviceStatusChange( const struct camera_module_callbacks* callbacks, int camera_id, int new_status) { LegacyCameraProviderImpl_2_4* cp = const_cast<LegacyCameraProviderImpl_2_4*>( static_cast<const LegacyCameraProviderImpl_2_4*>(callbacks)); if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); return; } Mutex::Autolock _l(cp->mCbLock); char cameraId[kMaxCameraIdLen]; snprintf(cameraId, sizeof(cameraId), "%d", camera_id); std::string cameraIdStr(cameraId); cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status; if (cp->mCallbacks == nullptr) { // For camera connected before mCallbacks is set, the corresponding // addDeviceNames() would be called later in setCallbacks(). return; } bool found = false; CameraDeviceStatus status = (CameraDeviceStatus)new_status; for (auto const& deviceNamePair : cp->mCameraDeviceNames) { if (cameraIdStr.compare(deviceNamePair.first) == 0) { cp->mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status); found = true; } } switch (status) { case CameraDeviceStatus::PRESENT: case CameraDeviceStatus::ENUMERATING: if (!found) { cp->addDeviceNames(camera_id, status, true); } break; case CameraDeviceStatus::NOT_PRESENT: if (found) { cp->removeDeviceNames(camera_id); } } } void LegacyCameraProviderImpl_2_4::sTorchModeStatusChange( const struct camera_module_callbacks* callbacks, const char* camera_id, int new_status) { LegacyCameraProviderImpl_2_4* cp = const_cast<LegacyCameraProviderImpl_2_4*>( static_cast<const LegacyCameraProviderImpl_2_4*>(callbacks)); if (cp == nullptr) { ALOGE("%s: callback ops is null", __FUNCTION__); return; } Mutex::Autolock _l(cp->mCbLock); if (cp->mCallbacks != nullptr) { std::string cameraIdStr(camera_id); TorchModeStatus status = (TorchModeStatus) new_status; for (auto const& deviceNamePair : cp->mCameraDeviceNames) { if (cameraIdStr.compare(deviceNamePair.first) == 0) { cp->mCallbacks->torchModeStatusChange( deviceNamePair.second, status); } } } } Status LegacyCameraProviderImpl_2_4::getHidlStatus(int status) { switch (status) { case 0: return Status::OK; case -ENODEV: return Status::INTERNAL_ERROR; case -EINVAL: return Status::ILLEGAL_ARGUMENT; default: ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status); return Status::INTERNAL_ERROR; } } std::string LegacyCameraProviderImpl_2_4::getLegacyCameraId(const hidl_string& deviceName) { std::string cameraId; matchDeviceName(deviceName, nullptr, &cameraId); return cameraId; } std::string LegacyCameraProviderImpl_2_4::getHidlDeviceName( std::string cameraId, int deviceVersion) { // Maybe consider create a version check method and SortedVec to speed up? if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_5 && deviceVersion != CAMERA_DEVICE_API_VERSION_3_6) { return hidl_string(""); } // Supported combinations: // CAMERA_DEVICE_API_VERSION_1_0 -> ICameraDevice@1.0 // CAMERA_DEVICE_API_VERSION_3_[2-4] -> ICameraDevice@[3.2|3.3] // CAMERA_DEVICE_API_VERSION_3_5 + CAMERA_MODULE_API_VERSION_2_4 -> ICameraDevice@3.4 // CAMERA_DEVICE_API_VERSION_3_[5-6] + CAMERA_MODULE_API_VERSION_2_5 -> ICameraDevice@3.5 bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0; int versionMajor = isV1 ? 1 : 3; int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion; if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) { if (mModule->getModuleApiVersion() == CAMERA_MODULE_API_VERSION_2_5) { versionMinor = 5; } else { versionMinor = 4; } } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) { versionMinor = 5; } char deviceName[kMaxCameraDeviceNameLen]; snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s", versionMajor, versionMinor, cameraId.c_str()); return deviceName; } LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() : camera_module_callbacks_t({sCameraDeviceStatusChange, sTorchModeStatusChange}) { mInitFailed = initialize(); } LegacyCameraProviderImpl_2_4::~LegacyCameraProviderImpl_2_4() {} bool LegacyCameraProviderImpl_2_4::initialize() { camera_module_t *rawModule; int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule); if (err < 0) { ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err)); return true; } mModule = new CameraModule(rawModule); err = mModule->init(); if (err != OK) { ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err)); mModule.clear(); return true; } ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); // Setup vendor tags here so HAL can setup vendor keys in camera characteristics VendorTagDescriptor::clearGlobalVendorTagDescriptor(); if (!setUpVendorTags()) { ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__); } // Setup callback now because we are going to try openLegacy next err = mModule->setCallbacks(this); if (err != OK) { ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err)); mModule.clear(); return true; } mPreferredHal3MinorVersion = property_get_int32("ro.vendor.camera.wrapper.hal3TrebleMinorVersion", 3); ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion); switch(mPreferredHal3MinorVersion) { case 2: case 3: // OK break; default: ALOGW("Unknown minor camera device HAL version %d in property " "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3", mPreferredHal3MinorVersion); mPreferredHal3MinorVersion = 3; } mNumberOfLegacyCameras = mModule->getNumberOfCameras(); for (int i = 0; i < mNumberOfLegacyCameras; i++) { struct camera_info info; auto rc = mModule->getCameraInfo(i, &info); if (rc != NO_ERROR) { ALOGE("%s: Camera info query failed!", __func__); mModule.clear(); return true; } if (checkCameraVersion(i, info) != OK) { ALOGE("%s: Camera version check failed!", __func__); mModule.clear(); return true; } char cameraId[kMaxCameraIdLen]; snprintf(cameraId, sizeof(cameraId), "%d", i); std::string cameraIdStr(cameraId); mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT; addDeviceNames(i); } return false; // mInitFailed } /** * Check that the device HAL version is still in supported. */ int LegacyCameraProviderImpl_2_4::checkCameraVersion(int id, camera_info info) { if (mModule == nullptr) { return NO_INIT; } // device_version undefined in CAMERA_MODULE_API_VERSION_1_0, // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible uint16_t moduleVersion = mModule->getModuleApiVersion(); if (moduleVersion >= CAMERA_MODULE_API_VERSION_2_0) { // Verify the device version is in the supported range switch (info.device_version) { case CAMERA_DEVICE_API_VERSION_1_0: case CAMERA_DEVICE_API_VERSION_3_2: case CAMERA_DEVICE_API_VERSION_3_3: case CAMERA_DEVICE_API_VERSION_3_4: case CAMERA_DEVICE_API_VERSION_3_5: // in support break; case CAMERA_DEVICE_API_VERSION_3_6: /** * ICameraDevice@3.5 contains APIs from both * CAMERA_DEVICE_API_VERSION_3_6 and CAMERA_MODULE_API_VERSION_2_5 * so we require HALs to uprev both for simplified supported combinations. * HAL can still opt in individual new APIs indepedently. */ if (moduleVersion < CAMERA_MODULE_API_VERSION_2_5) { ALOGE("%s: Device %d has unsupported version combination:" "HAL version %x and module version %x", __FUNCTION__, id, info.device_version, moduleVersion); return NO_INIT; } break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: case CAMERA_DEVICE_API_VERSION_3_0: case CAMERA_DEVICE_API_VERSION_3_1: // no longer supported default: ALOGE("%s: Device %d has HAL version %x, which is not supported", __FUNCTION__, id, info.device_version); return NO_INIT; } } return OK; } bool LegacyCameraProviderImpl_2_4::setUpVendorTags() { ATRACE_CALL(); vendor_tag_ops_t vOps = vendor_tag_ops_t(); // Check if vendor operations have been implemented if (!mModule->isVendorTagDefined()) { ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__); return true; } mModule->getVendorTagOps(&vOps); // Ensure all vendor operations are present if (vOps.get_tag_count == nullptr || vOps.get_all_tags == nullptr || vOps.get_section_name == nullptr || vOps.get_tag_name == nullptr || vOps.get_tag_type == nullptr) { ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions." , __FUNCTION__); return false; } // Read all vendor tag definitions into a descriptor sp<VendorTagDescriptor> desc; status_t res; if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc)) != 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 false; } // Set the global descriptor to use with camera metadata VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc); const SortedVector<String8>* sectionNames = desc->getAllSectionNames(); size_t numSections = sectionNames->size(); std::vector<std::vector<VendorTag>> tagsBySection(numSections); int tagCount = desc->getTagCount(); std::vector<uint32_t> tags(tagCount); desc->getTagArray(tags.data()); for (int i = 0; i < tagCount; i++) { VendorTag vt; vt.tagId = tags[i]; vt.tagName = desc->getTagName(tags[i]); vt.tagType = (CameraMetadataType) desc->getTagType(tags[i]); ssize_t sectionIdx = desc->getSectionIndex(tags[i]); tagsBySection[sectionIdx].push_back(vt); } mVendorTagSections.resize(numSections); for (size_t s = 0; s < numSections; s++) { mVendorTagSections[s].sectionName = (*sectionNames)[s].string(); mVendorTagSections[s].tags = tagsBySection[s]; } return true; } // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. Return<Status> LegacyCameraProviderImpl_2_4::setCallback( const sp<ICameraProviderCallback>& callback) { Mutex::Autolock _l(mCbLock); mCallbacks = callback; // Add and report all presenting external cameras. for (auto const& statusPair : mCameraStatusMap) { int id = std::stoi(statusPair.first); auto status = static_cast<CameraDeviceStatus>(statusPair.second); if (id >= mNumberOfLegacyCameras && status != CameraDeviceStatus::NOT_PRESENT) { addDeviceNames(id, status, true); } } return Status::OK; } Return<void> LegacyCameraProviderImpl_2_4::getVendorTags( ICameraProvider::getVendorTags_cb _hidl_cb) { _hidl_cb(Status::OK, mVendorTagSections); return Void(); } Return<void> LegacyCameraProviderImpl_2_4::getCameraIdList( ICameraProvider::getCameraIdList_cb _hidl_cb) { std::vector<hidl_string> deviceNameList; for (auto const& deviceNamePair : mCameraDeviceNames) { if (std::stoi(deviceNamePair.first) >= mNumberOfLegacyCameras) { // External camera devices must be reported through the device status change callback, // not in this list. continue; } if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) { deviceNameList.push_back(deviceNamePair.second); } } hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList); _hidl_cb(Status::OK, hidlDeviceNameList); return Void(); } Return<void> LegacyCameraProviderImpl_2_4::isSetTorchModeSupported( ICameraProvider::isSetTorchModeSupported_cb _hidl_cb) { bool support = mModule->isSetTorchModeSupported(); _hidl_cb (Status::OK, support); return Void(); } Return<void> LegacyCameraProviderImpl_2_4::getCameraDeviceInterface_V1_x( const hidl_string& cameraDeviceName, ICameraProvider::getCameraDeviceInterface_V1_x_cb _hidl_cb) { std::string cameraId, deviceVersion; bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); if (!match) { _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } std::string deviceName(cameraDeviceName.c_str()); ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName)); if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch Status status = Status::OK; ssize_t idx = mCameraIds.indexOf(cameraId); if (idx == NAME_NOT_FOUND) { ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str()); status = Status::ILLEGAL_ARGUMENT; } else { // invalid version ALOGE("%s: camera device %s does not support version %s!", __FUNCTION__, cameraId.c_str(), deviceVersion.c_str()); status = Status::OPERATION_NOT_SUPPORTED; } _hidl_cb(status, nullptr); return Void(); } if (mCameraStatusMap.count(cameraId) == 0 || mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) { _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } sp<android::hardware::camera::device::V1_0::implementation::CameraDevice> device = new android::hardware::camera::device::V1_0::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); if (device == nullptr) { ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str()); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } if (device->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); device = nullptr; _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } _hidl_cb (Status::OK, device); return Void(); } Return<void> LegacyCameraProviderImpl_2_4::getCameraDeviceInterface_V3_x( const hidl_string& cameraDeviceName, ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) { std::string cameraId, deviceVersion; bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId); if (!match) { _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } std::string deviceName(cameraDeviceName.c_str()); ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName)); if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch Status status = Status::OK; ssize_t idx = mCameraIds.indexOf(cameraId); if (idx == NAME_NOT_FOUND) { ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str()); status = Status::ILLEGAL_ARGUMENT; } else { // invalid version ALOGE("%s: camera device %s does not support version %s!", __FUNCTION__, cameraId.c_str(), deviceVersion.c_str()); status = Status::OPERATION_NOT_SUPPORTED; } _hidl_cb(status, nullptr); return Void(); } if (mCameraStatusMap.count(cameraId) == 0 || mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) { _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl; // ICameraDevice 3.4 or upper if (deviceVersion >= kHAL3_4) { ALOGV("Constructing v3.4+ camera device"); if (deviceVersion == kHAL3_4) { deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); } else if (deviceVersion == kHAL3_5) { deviceImpl = new android::hardware::camera::device::V3_5::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); } if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } IF_ALOGV() { deviceImpl->getInterface()->interfaceChain([]( ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { ALOGV("Device interface chain:"); for (auto iface : interfaceChain) { ALOGV(" %s", iface.c_str()); } }); } _hidl_cb (Status::OK, deviceImpl->getInterface()); return Void(); } // ICameraDevice 3.2 and 3.3 // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default // to the newest possible Treble HAL revision, but allow for override if needed via // system property. switch (mPreferredHal3MinorVersion) { case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2 ALOGV("Constructing v3.2 camera device"); deviceImpl = new android::hardware::camera::device::V3_2::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } break; } case 3: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.3 ALOGV("Constructing v3.3 camera device"); deviceImpl = new android::hardware::camera::device::V3_3::implementation::CameraDevice( mModule, cameraId, mCameraDeviceNames); if (deviceImpl == nullptr || deviceImpl->isInitFailed()) { ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } break; } default: ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } _hidl_cb (Status::OK, deviceImpl->getInterface()); return Void(); } } // namespace implementation } // namespace V2_4 } // namespace provider } // namespace camera } // namespace hardware } // namespace android