You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
817 lines
30 KiB
817 lines
30 KiB
/*
|
|
* Copyright (C) 2018 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 "ACameraManagerVendor"
|
|
|
|
#include <memory>
|
|
#include "ndk_vendor/impl/ACameraManager.h"
|
|
#include "ACameraMetadata.h"
|
|
#include "ndk_vendor/impl/ACameraDevice.h"
|
|
#include "utils.h"
|
|
#include <CameraMetadata.h>
|
|
#include <camera_metadata_hidden.h>
|
|
|
|
#include <utils/Vector.h>
|
|
#include <cutils/properties.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <VendorTagDescriptor.h>
|
|
|
|
using namespace android::acam;
|
|
|
|
namespace android {
|
|
namespace acam {
|
|
|
|
using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
|
|
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
|
|
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
|
|
|
|
// Static member definitions
|
|
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
|
|
const char* CameraManagerGlobal::kPhysicalCameraIdKey = "PhysicalCameraId";
|
|
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
|
|
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
|
|
const nsecs_t CameraManagerGlobal::kCallbackDrainTimeout = 5000000; // 5 ms
|
|
Mutex CameraManagerGlobal::sLock;
|
|
CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
|
|
|
|
/**
|
|
* The vendor tag descriptor class that takes HIDL vendor tag information as
|
|
* input. Not part of vendor available VendorTagDescriptor class because that class is used by
|
|
* default HAL implementation code as well.
|
|
*/
|
|
class HidlVendorTagDescriptor : public VendorTagDescriptor {
|
|
public:
|
|
/**
|
|
* Create a VendorTagDescriptor object from the HIDL VendorTagSection
|
|
* vector.
|
|
*
|
|
* Returns OK on success, or a negative error code.
|
|
*/
|
|
static status_t createDescriptorFromHidl(const hidl_vec<VendorTagSection>& vts,
|
|
/*out*/ sp<VendorTagDescriptor> *descriptor);
|
|
};
|
|
|
|
status_t HidlVendorTagDescriptor::createDescriptorFromHidl(const hidl_vec<VendorTagSection> &vts,
|
|
sp<VendorTagDescriptor> *descriptor) {
|
|
int tagCount = 0;
|
|
|
|
for (size_t s = 0; s < vts.size(); s++) {
|
|
tagCount += vts[s].tags.size();
|
|
}
|
|
|
|
if (tagCount < 0 || tagCount > INT32_MAX) {
|
|
ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
Vector<uint32_t> tagArray;
|
|
LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
|
|
"%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
|
|
|
|
sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
|
|
desc->mTagCount = tagCount;
|
|
|
|
KeyedVector<uint32_t, String8> tagToSectionMap;
|
|
|
|
int idx = 0;
|
|
for (size_t s = 0; s < vts.size(); s++) {
|
|
const VendorTagSection& section = vts[s];
|
|
const char *sectionName = section.sectionName.c_str();
|
|
if (sectionName == NULL) {
|
|
ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
|
|
return BAD_VALUE;
|
|
}
|
|
String8 sectionString(sectionName);
|
|
desc->mSections.add(sectionString);
|
|
|
|
for (size_t j = 0; j < section.tags.size(); j++) {
|
|
uint32_t tag = section.tags[j].tagId;
|
|
if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
|
|
ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
tagArray.editItemAt(idx++) = section.tags[j].tagId;
|
|
|
|
const char *tagName = section.tags[j].tagName.c_str();
|
|
if (tagName == NULL) {
|
|
ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
|
|
return BAD_VALUE;
|
|
}
|
|
desc->mTagToNameMap.add(tag, String8(tagName));
|
|
tagToSectionMap.add(tag, sectionString);
|
|
|
|
int tagType = (int) section.tags[j].tagType;
|
|
if (tagType < 0 || tagType >= NUM_TYPES) {
|
|
ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
|
|
return BAD_VALUE;
|
|
}
|
|
desc->mTagToTypeMap.emplace(tag, tagType);
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < tagArray.size(); ++i) {
|
|
uint32_t tag = tagArray[i];
|
|
String8 sectionString = tagToSectionMap.valueFor(tag);
|
|
|
|
// Set up tag to section index map
|
|
ssize_t index = desc->mSections.indexOf(sectionString);
|
|
LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
|
|
desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
|
|
|
|
// Set up reverse mapping
|
|
ssize_t reverseIndex = -1;
|
|
if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
|
|
KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
|
|
reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
|
|
}
|
|
desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
|
|
}
|
|
|
|
*descriptor = std::move(desc);
|
|
return OK;
|
|
}
|
|
|
|
CameraManagerGlobal&
|
|
CameraManagerGlobal::getInstance() {
|
|
Mutex::Autolock _l(sLock);
|
|
CameraManagerGlobal* instance = sInstance;
|
|
if (instance == nullptr) {
|
|
instance = new CameraManagerGlobal();
|
|
sInstance = instance;
|
|
}
|
|
return *instance;
|
|
}
|
|
|
|
CameraManagerGlobal::~CameraManagerGlobal() {
|
|
// clear sInstance so next getInstance call knows to create a new one
|
|
Mutex::Autolock _sl(sLock);
|
|
sInstance = nullptr;
|
|
Mutex::Autolock _l(mLock);
|
|
if (mCameraService != nullptr) {
|
|
mCameraService->unlinkToDeath(mDeathNotifier);
|
|
mCameraService->removeListener(mCameraServiceListener);
|
|
}
|
|
mDeathNotifier.clear();
|
|
if (mCbLooper != nullptr) {
|
|
mCbLooper->unregisterHandler(mHandler->id());
|
|
mCbLooper->stop();
|
|
}
|
|
mCbLooper.clear();
|
|
mHandler.clear();
|
|
mCameraServiceListener.clear();
|
|
mCameraService.clear();
|
|
}
|
|
|
|
static bool isCameraServiceDisabled() {
|
|
char value[PROPERTY_VALUE_MAX];
|
|
property_get("config.disable_cameraservice", value, "0");
|
|
return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
|
|
}
|
|
|
|
bool CameraManagerGlobal::setupVendorTags() {
|
|
sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
|
|
Status status = Status::NO_ERROR;
|
|
std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
|
|
auto remoteRet = mCameraService->getCameraVendorTagSections([&status, &providerIdsAndVts]
|
|
(Status s,
|
|
auto &IdsAndVts) {
|
|
status = s;
|
|
providerIdsAndVts = IdsAndVts; });
|
|
|
|
if (!remoteRet.isOk() || status != Status::NO_ERROR) {
|
|
ALOGE("Failed to retrieve VendorTagSections %s", remoteRet.description().c_str());
|
|
return false;
|
|
}
|
|
// Convert each providers VendorTagSections into a VendorTagDescriptor and
|
|
// add it to the cache
|
|
for (auto &providerIdAndVts : providerIdsAndVts) {
|
|
sp<VendorTagDescriptor> vendorTagDescriptor;
|
|
if (HidlVendorTagDescriptor::createDescriptorFromHidl(providerIdAndVts.vendorTagSections,
|
|
&vendorTagDescriptor) != OK) {
|
|
ALOGE("Failed to convert from Hidl: VendorTagDescriptor");
|
|
return false;
|
|
}
|
|
tagCache->addVendorDescriptor(providerIdAndVts.providerId, vendorTagDescriptor);
|
|
}
|
|
VendorTagDescriptorCache::setAsGlobalVendorTagCache(tagCache);
|
|
return true;
|
|
}
|
|
|
|
sp<ICameraService> CameraManagerGlobal::getCameraService() {
|
|
Mutex::Autolock _l(mLock);
|
|
if (mCameraService.get() == nullptr) {
|
|
if (isCameraServiceDisabled()) {
|
|
return mCameraService;
|
|
}
|
|
|
|
sp<ICameraService> cameraServiceBinder;
|
|
do {
|
|
cameraServiceBinder = ICameraService::getService();
|
|
if (cameraServiceBinder != nullptr) {
|
|
break;
|
|
}
|
|
ALOGW("CameraService not published, waiting...");
|
|
usleep(kCameraServicePollDelay);
|
|
} while(true);
|
|
if (mDeathNotifier == nullptr) {
|
|
mDeathNotifier = new DeathNotifier(this);
|
|
}
|
|
cameraServiceBinder->linkToDeath(mDeathNotifier, 0);
|
|
mCameraService = cameraServiceBinder;
|
|
|
|
// Setup looper thread to perfrom availiability callbacks
|
|
if (mCbLooper == nullptr) {
|
|
mCbLooper = new ALooper;
|
|
mCbLooper->setName("C2N-mgr-looper");
|
|
status_t err = mCbLooper->start(
|
|
/*runOnCallingThread*/false,
|
|
/*canCallJava*/ true,
|
|
PRIORITY_DEFAULT);
|
|
if (err != OK) {
|
|
ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
|
|
__FUNCTION__, strerror(-err), err);
|
|
mCbLooper.clear();
|
|
return nullptr;
|
|
}
|
|
if (mHandler == nullptr) {
|
|
mHandler = new CallbackHandler(this);
|
|
}
|
|
mCbLooper->registerHandler(mHandler);
|
|
}
|
|
|
|
// register ICameraServiceListener
|
|
if (mCameraServiceListener == nullptr) {
|
|
mCameraServiceListener = new CameraServiceListener(this);
|
|
}
|
|
hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId> cameraStatuses{};
|
|
Status status = Status::NO_ERROR;
|
|
auto remoteRet = mCameraService->addListener_2_1(mCameraServiceListener,
|
|
[&status, &cameraStatuses](Status s,
|
|
auto &retStatuses) {
|
|
status = s;
|
|
cameraStatuses = retStatuses;
|
|
});
|
|
if (!remoteRet.isOk() || status != Status::NO_ERROR) {
|
|
ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
|
|
}
|
|
|
|
// Setup vendor tags
|
|
if (!setupVendorTags()) {
|
|
ALOGE("Unable to set up vendor tags");
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto& c : cameraStatuses) {
|
|
onStatusChangedLocked(c.v2_0);
|
|
|
|
for (auto& unavailablePhysicalId : c.unavailPhysicalCameraIds) {
|
|
PhysicalCameraStatusAndId statusAndId;
|
|
statusAndId.deviceStatus = CameraDeviceStatus::STATUS_NOT_PRESENT;
|
|
statusAndId.cameraId = c.v2_0.cameraId;
|
|
statusAndId.physicalCameraId = unavailablePhysicalId;
|
|
onStatusChangedLocked(statusAndId);
|
|
}
|
|
}
|
|
}
|
|
return mCameraService;
|
|
}
|
|
|
|
void CameraManagerGlobal::DeathNotifier::serviceDied(uint64_t cookie, const wp<IBase> &who) {
|
|
(void) cookie;
|
|
(void) who;
|
|
ALOGE("Camera service binderDied!");
|
|
sp<CameraManagerGlobal> cm = mCameraManager.promote();
|
|
if (cm != nullptr) {
|
|
AutoMutex lock(cm->mLock);
|
|
for (auto& pair : cm->mDeviceStatusMap) {
|
|
CameraStatusAndId cameraStatusAndId;
|
|
cameraStatusAndId.cameraId = pair.first;
|
|
cameraStatusAndId.deviceStatus = pair.second.getStatus();
|
|
cm->onStatusChangedLocked(cameraStatusAndId);
|
|
}
|
|
cm->mCameraService.clear();
|
|
// TODO: consider adding re-connect call here?
|
|
}
|
|
}
|
|
|
|
void CameraManagerGlobal::registerAvailabilityCallback(
|
|
const ACameraManager_AvailabilityCallbacks *callback) {
|
|
return registerAvailCallback<ACameraManager_AvailabilityCallbacks>(callback);
|
|
}
|
|
|
|
void CameraManagerGlobal::unregisterAvailabilityCallback(
|
|
const ACameraManager_AvailabilityCallbacks *callback) {
|
|
Mutex::Autolock _l(mLock);
|
|
drainPendingCallbacksLocked();
|
|
Callback cb(callback);
|
|
mCallbacks.erase(cb);
|
|
}
|
|
|
|
void CameraManagerGlobal::registerExtendedAvailabilityCallback(
|
|
const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
|
|
return registerAvailCallback<ACameraManager_ExtendedAvailabilityCallbacks>(callback);
|
|
}
|
|
|
|
void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
|
|
const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
|
|
Mutex::Autolock _l(mLock);
|
|
drainPendingCallbacksLocked();
|
|
Callback cb(callback);
|
|
mCallbacks.erase(cb);
|
|
}
|
|
|
|
void CameraManagerGlobal::onCallbackCalled() {
|
|
Mutex::Autolock _l(mLock);
|
|
if (mPendingCallbackCnt > 0) {
|
|
mPendingCallbackCnt--;
|
|
}
|
|
mCallbacksCond.signal();
|
|
}
|
|
|
|
void CameraManagerGlobal::drainPendingCallbacksLocked() {
|
|
while (mPendingCallbackCnt > 0) {
|
|
auto res = mCallbacksCond.waitRelative(mLock, kCallbackDrainTimeout);
|
|
if (res != NO_ERROR) {
|
|
ALOGE("%s: Error waiting to drain callbacks: %s(%d)",
|
|
__FUNCTION__, strerror(-res), res);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
void CameraManagerGlobal::registerAvailCallback(const T *callback) {
|
|
Mutex::Autolock _l(mLock);
|
|
Callback cb(callback);
|
|
auto pair = mCallbacks.insert(cb);
|
|
// Send initial callbacks if callback is newly registered
|
|
if (pair.second) {
|
|
for (auto& pair : mDeviceStatusMap) {
|
|
const hidl_string& cameraId = pair.first;
|
|
CameraDeviceStatus status = pair.second.getStatus();
|
|
|
|
// Camera available/unavailable callback
|
|
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
|
|
ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
|
|
cb.mAvailable : cb.mUnavailable;
|
|
msg->setPointer(kCallbackFpKey, (void *) cbFunc);
|
|
msg->setPointer(kContextKey, cb.mContext);
|
|
msg->setString(kCameraIdKey, AString(cameraId.c_str()));
|
|
mPendingCallbackCnt++;
|
|
msg->post();
|
|
|
|
// Physical camera unavailable callback
|
|
std::set<hidl_string> unavailPhysicalIds = pair.second.getUnavailablePhysicalIds();
|
|
for (const auto& physicalCameraId : unavailPhysicalIds) {
|
|
sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
|
|
ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
|
|
cb.mPhysicalCamUnavailable;
|
|
msg->setPointer(kCallbackFpKey, (void *) cbFunc);
|
|
msg->setPointer(kContextKey, cb.mContext);
|
|
msg->setString(kCameraIdKey, AString(cameraId.c_str()));
|
|
msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
|
|
mPendingCallbackCnt++;
|
|
msg->post();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
|
|
// Ensure that we have initialized/refreshed the list of available devices
|
|
auto cs = getCameraService();
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
for(auto& deviceStatus : mDeviceStatusMap) {
|
|
CameraDeviceStatus status = deviceStatus.second.getStatus();
|
|
if (status == CameraDeviceStatus::STATUS_NOT_PRESENT ||
|
|
status == CameraDeviceStatus::STATUS_ENUMERATING) {
|
|
continue;
|
|
}
|
|
cameraIds->push_back(deviceStatus.first);
|
|
}
|
|
}
|
|
|
|
bool CameraManagerGlobal::validStatus(CameraDeviceStatus status) {
|
|
switch (status) {
|
|
case CameraDeviceStatus::STATUS_NOT_PRESENT:
|
|
case CameraDeviceStatus::STATUS_PRESENT:
|
|
case CameraDeviceStatus::STATUS_ENUMERATING:
|
|
case CameraDeviceStatus::STATUS_NOT_AVAILABLE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CameraManagerGlobal::isStatusAvailable(CameraDeviceStatus status) {
|
|
switch (status) {
|
|
case CameraDeviceStatus::STATUS_PRESENT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CameraManagerGlobal::CallbackHandler::onMessageReceived(
|
|
const sp<AMessage> &msg) {
|
|
onMessageReceivedInternal(msg);
|
|
if (msg->what() == kWhatSendSingleCallback ||
|
|
msg->what() == kWhatSendSinglePhysicalCameraCallback) {
|
|
notifyParent();
|
|
}
|
|
}
|
|
|
|
void CameraManagerGlobal::CallbackHandler::onMessageReceivedInternal(
|
|
const sp<AMessage> &msg) {
|
|
switch (msg->what()) {
|
|
case kWhatSendSingleCallback:
|
|
{
|
|
ACameraManager_AvailabilityCallback cb;
|
|
void* context;
|
|
AString cameraId;
|
|
bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
|
|
return;
|
|
}
|
|
found = msg->findPointer(kContextKey, &context);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find callback context!", __FUNCTION__);
|
|
return;
|
|
}
|
|
found = msg->findString(kCameraIdKey, &cameraId);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
|
|
return;
|
|
}
|
|
(*cb)(context, cameraId.c_str());
|
|
break;
|
|
}
|
|
case kWhatSendSinglePhysicalCameraCallback:
|
|
{
|
|
ACameraManager_PhysicalCameraAvailabilityCallback cb;
|
|
void* context;
|
|
AString cameraId;
|
|
AString physicalCameraId;
|
|
bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
|
|
return;
|
|
}
|
|
found = msg->findPointer(kContextKey, &context);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find callback context!", __FUNCTION__);
|
|
return;
|
|
}
|
|
found = msg->findString(kCameraIdKey, &cameraId);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
|
|
return;
|
|
}
|
|
found = msg->findString(kPhysicalCameraIdKey, &physicalCameraId);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find physical camera ID!", __FUNCTION__);
|
|
return;
|
|
}
|
|
(*cb)(context, cameraId.c_str(), physicalCameraId.c_str());
|
|
break;
|
|
}
|
|
default:
|
|
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CameraManagerGlobal::CallbackHandler::notifyParent() {
|
|
sp<CameraManagerGlobal> parent = mParent.promote();
|
|
if (parent != nullptr) {
|
|
parent->onCallbackCalled();
|
|
}
|
|
}
|
|
|
|
hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onStatusChanged(
|
|
const CameraStatusAndId &statusAndId) {
|
|
sp<CameraManagerGlobal> cm = mCameraManager.promote();
|
|
if (cm != nullptr) {
|
|
cm->onStatusChanged(statusAndId);
|
|
} else {
|
|
ALOGE("Cannot deliver status change. Global camera manager died");
|
|
}
|
|
return Void();
|
|
}
|
|
|
|
void CameraManagerGlobal::onStatusChanged(
|
|
const CameraStatusAndId &statusAndId) {
|
|
Mutex::Autolock _l(mLock);
|
|
onStatusChangedLocked(statusAndId);
|
|
}
|
|
|
|
void CameraManagerGlobal::onStatusChangedLocked(
|
|
const CameraStatusAndId &statusAndId) {
|
|
hidl_string cameraId = statusAndId.cameraId;
|
|
CameraDeviceStatus status = statusAndId.deviceStatus;
|
|
if (!validStatus(status)) {
|
|
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
|
|
return;
|
|
}
|
|
|
|
bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
|
|
CameraDeviceStatus oldStatus = firstStatus ?
|
|
status : // first status
|
|
mDeviceStatusMap[cameraId].getStatus();
|
|
|
|
if (!firstStatus &&
|
|
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
|
|
// No status update. No need to send callback
|
|
return;
|
|
}
|
|
|
|
// Iterate through all registered callbacks
|
|
mDeviceStatusMap[cameraId].updateStatus(status);
|
|
for (auto cb : mCallbacks) {
|
|
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
|
|
ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
|
|
cb.mAvailable : cb.mUnavailable;
|
|
msg->setPointer(kCallbackFpKey, (void *) cbFp);
|
|
msg->setPointer(kContextKey, cb.mContext);
|
|
msg->setString(kCameraIdKey, AString(cameraId.c_str()));
|
|
mPendingCallbackCnt++;
|
|
msg->post();
|
|
}
|
|
if (status == CameraDeviceStatus::STATUS_NOT_PRESENT) {
|
|
mDeviceStatusMap.erase(cameraId);
|
|
}
|
|
}
|
|
|
|
hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
|
|
const PhysicalCameraStatusAndId &statusAndId) {
|
|
sp<CameraManagerGlobal> cm = mCameraManager.promote();
|
|
if (cm != nullptr) {
|
|
cm->onStatusChanged(statusAndId);
|
|
} else {
|
|
ALOGE("Cannot deliver status change. Global camera manager died");
|
|
}
|
|
return Void();
|
|
}
|
|
|
|
void CameraManagerGlobal::onStatusChanged(
|
|
const PhysicalCameraStatusAndId &statusAndId) {
|
|
Mutex::Autolock _l(mLock);
|
|
onStatusChangedLocked(statusAndId);
|
|
}
|
|
|
|
void CameraManagerGlobal::onStatusChangedLocked(
|
|
const PhysicalCameraStatusAndId &statusAndId) {
|
|
hidl_string cameraId = statusAndId.cameraId;
|
|
hidl_string physicalCameraId = statusAndId.physicalCameraId;
|
|
CameraDeviceStatus status = statusAndId.deviceStatus;
|
|
if (!validStatus(status)) {
|
|
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
|
|
return;
|
|
}
|
|
|
|
auto logicalStatus = mDeviceStatusMap.find(cameraId);
|
|
if (logicalStatus == mDeviceStatusMap.end()) {
|
|
ALOGE("%s: Physical camera id %s status change on a non-present id %s",
|
|
__FUNCTION__, physicalCameraId.c_str(), cameraId.c_str());
|
|
return;
|
|
}
|
|
CameraDeviceStatus logicalCamStatus = mDeviceStatusMap[cameraId].getStatus();
|
|
if (logicalCamStatus != CameraDeviceStatus::STATUS_PRESENT &&
|
|
logicalCamStatus != CameraDeviceStatus::STATUS_NOT_AVAILABLE) {
|
|
ALOGE("%s: Physical camera id %s status %d change for an invalid logical camera state %d",
|
|
__FUNCTION__, physicalCameraId.c_str(), status, logicalCamStatus);
|
|
return;
|
|
}
|
|
|
|
bool updated = false;
|
|
if (status == CameraDeviceStatus::STATUS_PRESENT) {
|
|
updated = mDeviceStatusMap[cameraId].removeUnavailablePhysicalId(physicalCameraId);
|
|
} else {
|
|
updated = mDeviceStatusMap[cameraId].addUnavailablePhysicalId(physicalCameraId);
|
|
}
|
|
|
|
// Iterate through all registered callbacks
|
|
if (updated) {
|
|
for (auto cb : mCallbacks) {
|
|
sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
|
|
ACameraManager_PhysicalCameraAvailabilityCallback cbFp = isStatusAvailable(status) ?
|
|
cb.mPhysicalCamAvailable : cb.mPhysicalCamUnavailable;
|
|
msg->setPointer(kCallbackFpKey, (void *) cbFp);
|
|
msg->setPointer(kContextKey, cb.mContext);
|
|
msg->setString(kCameraIdKey, AString(cameraId.c_str()));
|
|
msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
|
|
mPendingCallbackCnt++;
|
|
msg->post();
|
|
}
|
|
}
|
|
}
|
|
|
|
CameraDeviceStatus CameraManagerGlobal::CameraStatus::getStatus() {
|
|
std::lock_guard<std::mutex> lock(mLock);
|
|
return status;
|
|
}
|
|
|
|
void CameraManagerGlobal::CameraStatus::updateStatus(CameraDeviceStatus newStatus) {
|
|
std::lock_guard<std::mutex> lock(mLock);
|
|
status = newStatus;
|
|
}
|
|
|
|
bool CameraManagerGlobal::CameraStatus::addUnavailablePhysicalId(
|
|
const hidl_string& physicalCameraId) {
|
|
std::lock_guard<std::mutex> lock(mLock);
|
|
auto result = unavailablePhysicalIds.insert(physicalCameraId);
|
|
return result.second;
|
|
}
|
|
|
|
bool CameraManagerGlobal::CameraStatus::removeUnavailablePhysicalId(
|
|
const hidl_string& physicalCameraId) {
|
|
std::lock_guard<std::mutex> lock(mLock);
|
|
auto count = unavailablePhysicalIds.erase(physicalCameraId);
|
|
return count > 0;
|
|
}
|
|
|
|
std::set<hidl_string> CameraManagerGlobal::CameraStatus::getUnavailablePhysicalIds() {
|
|
std::lock_guard<std::mutex> lock(mLock);
|
|
return unavailablePhysicalIds;
|
|
}
|
|
|
|
} // namespace acam
|
|
} // namespace android
|
|
|
|
/**
|
|
* ACameraManger Implementation
|
|
*/
|
|
camera_status_t
|
|
ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
std::vector<hidl_string> idList;
|
|
CameraManagerGlobal::getInstance().getCameraIdList(&idList);
|
|
|
|
int numCameras = idList.size();
|
|
ACameraIdList *out = new ACameraIdList;
|
|
if (!out) {
|
|
ALOGE("Allocate memory for ACameraIdList failed!");
|
|
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
out->numCameras = numCameras;
|
|
out->cameraIds = new const char*[numCameras];
|
|
if (!out->cameraIds) {
|
|
ALOGE("Allocate memory for ACameraIdList failed!");
|
|
deleteCameraIdList(out);
|
|
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
for (int i = 0; i < numCameras; i++) {
|
|
const char* src = idList[i].c_str();
|
|
size_t dstSize = strlen(src) + 1;
|
|
char* dst = new char[dstSize];
|
|
if (!dst) {
|
|
ALOGE("Allocate memory for ACameraIdList failed!");
|
|
deleteCameraIdList(out);
|
|
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
strlcpy(dst, src, dstSize);
|
|
out->cameraIds[i] = dst;
|
|
}
|
|
*cameraIdList = out;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
void
|
|
ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
|
|
if (cameraIdList != nullptr) {
|
|
if (cameraIdList->cameraIds != nullptr) {
|
|
for (int i = 0; i < cameraIdList->numCameras; i ++) {
|
|
if (cameraIdList->cameraIds[i] != nullptr) {
|
|
delete[] cameraIdList->cameraIds[i];
|
|
}
|
|
}
|
|
delete[] cameraIdList->cameraIds;
|
|
}
|
|
delete cameraIdList;
|
|
}
|
|
}
|
|
|
|
camera_status_t ACameraManager::getCameraCharacteristics(
|
|
const char *cameraIdStr, sp<ACameraMetadata> *characteristics) {
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
|
|
if (cs == nullptr) {
|
|
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
|
|
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
|
|
}
|
|
CameraMetadata rawMetadata;
|
|
Status status = Status::NO_ERROR;
|
|
auto serviceRet =
|
|
cs->getCameraCharacteristics(cameraIdStr,
|
|
[&status, &rawMetadata] (auto s ,
|
|
const hidl_vec<uint8_t> &metadata) {
|
|
status = s;
|
|
if (status == Status::NO_ERROR) {
|
|
utils::convertFromHidlCloned(metadata, &rawMetadata);
|
|
}
|
|
});
|
|
if (!serviceRet.isOk() || status != Status::NO_ERROR) {
|
|
ALOGE("Get camera characteristics from camera service failed");
|
|
return ACAMERA_ERROR_UNKNOWN; // should not reach here
|
|
}
|
|
|
|
*characteristics = new ACameraMetadata(
|
|
rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
ACameraManager::openCamera(
|
|
const char* cameraId,
|
|
ACameraDevice_StateCallbacks* callback,
|
|
/*out*/ACameraDevice** outDevice) {
|
|
sp<ACameraMetadata> rawChars;
|
|
camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
|
|
Mutex::Autolock _l(mLock);
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
|
|
__FUNCTION__, cameraId, ret);
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
|
|
|
|
sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
|
|
if (cs == nullptr) {
|
|
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
|
|
delete device;
|
|
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
|
|
}
|
|
|
|
sp<ICameraDeviceCallback> callbacks = device->getServiceCallback();
|
|
sp<ICameraDeviceUser> deviceRemote;
|
|
|
|
// No way to get package name from native.
|
|
// Send a zero length package name and let camera service figure it out from UID
|
|
Status status = Status::NO_ERROR;
|
|
auto serviceRet = cs->connectDevice(
|
|
callbacks, cameraId, [&status, &deviceRemote](auto s, auto &device) {
|
|
status = s;
|
|
deviceRemote = device;
|
|
});
|
|
|
|
if (!serviceRet.isOk() || status != Status::NO_ERROR) {
|
|
ALOGE("%s: connect camera device failed", __FUNCTION__);
|
|
delete device;
|
|
return utils::convertFromHidl(status);
|
|
}
|
|
if (deviceRemote == nullptr) {
|
|
ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
|
|
delete device;
|
|
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
|
|
}
|
|
device->setRemoteDevice(deviceRemote);
|
|
device->setDeviceMetadataQueues();
|
|
*outDevice = device;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
ACameraManager::getTagFromName(const char *cameraId, const char *name, uint32_t *tag) {
|
|
sp<ACameraMetadata> rawChars;
|
|
camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("%s, Cannot retrieve camera characteristics for camera id %s", __FUNCTION__,
|
|
cameraId);
|
|
return ACAMERA_ERROR_METADATA_NOT_FOUND;
|
|
}
|
|
const CameraMetadata& metadata = rawChars->getInternalData();
|
|
const camera_metadata_t *rawMetadata = metadata.getAndLock();
|
|
metadata_vendor_id_t vendorTagId = get_camera_metadata_vendor_id(rawMetadata);
|
|
metadata.unlock(rawMetadata);
|
|
sp<VendorTagDescriptorCache> vtCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
|
|
sp<VendorTagDescriptor> vTags = nullptr;
|
|
vtCache->getVendorTagDescriptor(vendorTagId, &vTags);
|
|
status_t status= metadata.getTagFromName(name, vTags.get(), tag);
|
|
return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
|
|
}
|
|
|
|
ACameraManager::~ACameraManager() {
|
|
|
|
}
|