/* * 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 "CamDev@3.2-impl" #include #include #include #include "CameraDevice_3_2.h" #include namespace android { namespace hardware { namespace camera { namespace device { namespace V3_2 { namespace implementation { using ::android::hardware::camera::common::V1_0::Status; CameraDevice::CameraDevice( sp module, const std::string& cameraId, const SortedVector>& cameraDeviceNames) : mModule(module), mCameraId(cameraId), mDisconnected(false), mCameraDeviceNames(cameraDeviceNames) { mCameraIdInt = atoi(mCameraId.c_str()); // Should not reach here as provider also validate ID if (mCameraIdInt < 0) { ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str()); mInitFail = true; } else if (mCameraIdInt >= mModule->getNumberOfCameras()) { ALOGI("%s: Adding a new camera id: %s", __FUNCTION__, mCameraId.c_str()); } mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt); if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) { ALOGE("%s: Camera id %s does not support HAL3.2+", __FUNCTION__, mCameraId.c_str()); mInitFail = true; } } CameraDevice::~CameraDevice() {} Status CameraDevice::initStatus() const { Mutex::Autolock _l(mLock); Status status = Status::OK; if (mInitFail) { status = Status::INTERNAL_ERROR; } else if (mDisconnected) { status = Status::CAMERA_DISCONNECTED; } return status; } void CameraDevice::setConnectionStatus(bool connected) { Mutex::Autolock _l(mLock); mDisconnected = !connected; if (mSession == nullptr) { return; } sp session = mSession.promote(); if (session == nullptr) { return; } // Only notify active session disconnect events. // Users will need to re-open camera after disconnect event if (!connected) { session->disconnect(); } return; } Status CameraDevice::getHidlStatus(int status) { switch (status) { case 0: return Status::OK; case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED; case -EBUSY : return Status::CAMERA_IN_USE; case -EUSERS: return Status::MAX_CAMERAS_IN_USE; 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; } } // Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. Return CameraDevice::getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb) { Status status = initStatus(); CameraResourceCost resCost; if (status == Status::OK) { int cost = 100; std::vector conflicting_devices; struct camera_info info; // If using post-2.4 module version, query the cost + conflicting devices from the HAL if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { int ret = mModule->getCameraInfo(mCameraIdInt, &info); if (ret == OK) { cost = info.resource_cost; for (size_t i = 0; i < info.conflicting_devices_length; i++) { std::string cameraId(info.conflicting_devices[i]); for (const auto& pair : mCameraDeviceNames) { if (cameraId == pair.first) { conflicting_devices.push_back(pair.second); } } } } else { status = Status::INTERNAL_ERROR; } } if (status == Status::OK) { resCost.resourceCost = cost; resCost.conflictingDevices.resize(conflicting_devices.size()); for (size_t i = 0; i < conflicting_devices.size(); i++) { resCost.conflictingDevices[i] = conflicting_devices[i]; ALOGV("CamDevice %s is conflicting with camDevice %s", mCameraId.c_str(), resCost.conflictingDevices[i].c_str()); } } } _hidl_cb(status, resCost); return Void(); } Return CameraDevice::getCameraCharacteristics( ICameraDevice::getCameraCharacteristics_cb _hidl_cb) { Status status = initStatus(); CameraMetadata cameraCharacteristics; if (status == Status::OK) { //Module 2.1+ codepath. struct camera_info info; int ret = mModule->getCameraInfo(mCameraIdInt, &info); if (ret == OK) { convertToHidl(info.static_camera_characteristics, &cameraCharacteristics); } else { ALOGE("%s: get camera info failed!", __FUNCTION__); status = Status::INTERNAL_ERROR; } } _hidl_cb(status, cameraCharacteristics); return Void(); } Return CameraDevice::setTorchMode(TorchMode mode) { if (!mModule->isSetTorchModeSupported()) { return Status::METHOD_NOT_SUPPORTED; } Status status = initStatus(); if (status == Status::OK) { bool enable = (mode == TorchMode::ON) ? true : false; status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable)); } return status; } Return CameraDevice::open(const sp& callback, ICameraDevice::open_cb _hidl_cb) { Status status = initStatus(); sp session = nullptr; if (callback == nullptr) { ALOGE("%s: cannot open camera %s. callback is null!", __FUNCTION__, mCameraId.c_str()); _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } if (status != Status::OK) { // Provider will never pass initFailed device to client, so // this must be a disconnected camera ALOGE("%s: cannot open camera %s. camera is disconnected!", __FUNCTION__, mCameraId.c_str()); _hidl_cb(Status::CAMERA_DISCONNECTED, nullptr); return Void(); } else { mLock.lock(); ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt); session = mSession.promote(); if (session != nullptr && !session->isClosed()) { ALOGE("%s: cannot open an already opened camera!", __FUNCTION__); mLock.unlock(); _hidl_cb(Status::CAMERA_IN_USE, nullptr); return Void(); } /** Open HAL device */ status_t res; camera3_device_t *device; ATRACE_BEGIN("camera3->open"); res = mModule->open(mCameraId.c_str(), reinterpret_cast(&device)); ATRACE_END(); if (res != OK) { ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str()); mLock.unlock(); _hidl_cb(getHidlStatus(res), nullptr); return Void(); } /** Cross-check device version */ if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) { ALOGE("%s: Could not open camera: " "Camera device should be at least %x, reports %x instead", __FUNCTION__, CAMERA_DEVICE_API_VERSION_3_2, device->common.version); device->common.close(&device->common); mLock.unlock(); _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } struct camera_info info; res = mModule->getCameraInfo(mCameraIdInt, &info); if (res != OK) { ALOGE("%s: Could not open camera: getCameraInfo failed", __FUNCTION__); device->common.close(&device->common); mLock.unlock(); _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void(); } session = createSession( device, info.static_camera_characteristics, callback); if (session == nullptr) { ALOGE("%s: camera device session allocation failed", __FUNCTION__); mLock.unlock(); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } if (session->isInitFailed()) { ALOGE("%s: camera device session init failed", __FUNCTION__); session = nullptr; mLock.unlock(); _hidl_cb(Status::INTERNAL_ERROR, nullptr); return Void(); } mSession = session; IF_ALOGV() { session->getInterface()->interfaceChain([]( ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { ALOGV("Session interface chain:"); for (const auto& iface : interfaceChain) { ALOGV(" %s", iface.c_str()); } }); } mLock.unlock(); } _hidl_cb(status, session->getInterface()); return Void(); } Return CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) { Mutex::Autolock _l(mLock); if (handle.getNativeHandle() == nullptr) { ALOGE("%s: handle must not be null", __FUNCTION__); return Void(); } if (handle->numFds != 1 || handle->numInts != 0) { ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints", __FUNCTION__, handle->numFds, handle->numInts); return Void(); } int fd = handle->data[0]; if (mSession == nullptr) { dprintf(fd, "No active camera device session instance\n"); return Void(); } sp session = mSession.promote(); if (session == nullptr) { dprintf(fd, "No active camera device session instance\n"); return Void(); } // Call into active session to dump states session->dumpState(handle); return Void(); } sp CameraDevice::createSession(camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp& callback) { return new CameraDeviceSession(device, deviceInfo, callback); } // End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice. } // namespace implementation } // namespace V3_2 } // namespace device } // namespace camera } // namespace hardware } // namespace android