blob: 35555ffce196cc4ee450c100a103efdf44c2417e [file] [log] [blame]
/*
* Copyright (C) 2015 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 "ACameraManager"
#include <memory>
#include "ACameraManager.h"
#include "ACameraMetadata.h"
#include "ACameraDevice.h"
#include <utils/Vector.h>
#include <cutils/properties.h>
#include <stdlib.h>
#include <camera/VendorTagDescriptor.h>
using namespace android;
//constants shared between ACameraManager and CameraManagerGlobal
namespace {
const int kMaxCameraIdLen = 32;
}
namespace android {
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
Mutex CameraManagerGlobal::sLock;
CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
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) {
IInterface::asBinder(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);
}
sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() {
Mutex::Autolock _l(mLock);
if (mCameraService.get() == nullptr) {
if (isCameraServiceDisabled()) {
return mCameraService;
}
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16(kCameraServiceName));
if (binder != nullptr) {
break;
}
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
} while(true);
if (mDeathNotifier == nullptr) {
mDeathNotifier = new DeathNotifier(this);
}
binder->linkToDeath(mDeathNotifier);
mCameraService = interface_cast<hardware::ICameraService>(binder);
// 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();
}
mCbLooper->registerHandler(mHandler);
}
// register ICameraServiceListener
if (mCameraServiceListener == nullptr) {
mCameraServiceListener = new CameraServiceListener(this);
}
mCameraService->addListener(mCameraServiceListener);
// setup vendor tags
sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
binder::Status ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
if (ret.isOk()) {
status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
if (err != OK) {
ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
__FUNCTION__, strerror(-err), err);
}
} else if (ret.serviceSpecificErrorCode() ==
hardware::ICameraService::ERROR_DEPRECATED_HAL) {
ALOGW("%s: Camera HAL too old; does not support vendor tags",
__FUNCTION__);
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
} else {
ALOGE("%s: Failed to get vendor tag descriptors: %s",
__FUNCTION__, ret.toString8().string());
}
}
ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
return mCameraService;
}
void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
{
ALOGE("Camera service binderDied!");
sp<CameraManagerGlobal> cm = mCameraManager.promote();
if (cm != nullptr) {
AutoMutex lock(cm->mLock);
for (auto pair : cm->mDeviceStatusMap) {
int32_t cameraId = pair.first;
cm->onStatusChangedLocked(
CameraServiceListener::STATUS_NOT_PRESENT, cameraId);
}
cm->mCameraService.clear();
// TODO: consider adding re-connect call here?
}
}
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *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) {
int32_t cameraId = pair.first;
int32_t status = pair.second;
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
callback->onCameraAvailable : callback->onCameraUnavailable;
msg->setPointer(kCallbackFpKey, (void *) cb);
msg->setPointer(kContextKey, callback->context);
msg->setInt32(kCameraIdKey, cameraId);
msg->post();
}
}
}
void CameraManagerGlobal::unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
Mutex::Autolock _l(mLock);
Callback cb(callback);
mCallbacks.erase(cb);
}
bool CameraManagerGlobal::validStatus(int32_t status) {
switch (status) {
case hardware::ICameraServiceListener::STATUS_NOT_PRESENT:
case hardware::ICameraServiceListener::STATUS_PRESENT:
case hardware::ICameraServiceListener::STATUS_ENUMERATING:
case hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE:
return true;
default:
return false;
}
}
bool CameraManagerGlobal::isStatusAvailable(int32_t status) {
switch (status) {
case hardware::ICameraServiceListener::STATUS_PRESENT:
return true;
default:
return false;
}
}
void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
int32_t cameraId, void* context,
ACameraManager_AvailabilityCallback cb) const {
char cameraIdStr[kMaxCameraIdLen];
snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
(*cb)(context, cameraIdStr);
}
void CameraManagerGlobal::CallbackHandler::onMessageReceived(
const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatSendSingleCallback:
{
ACameraManager_AvailabilityCallback cb;
void* context;
int32_t 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->findInt32(kCameraIdKey, &cameraId);
if (!found) {
ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
return;
}
sendSingleCallback(cameraId, context, cb);
break;
}
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
}
}
binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
int32_t status, int32_t cameraId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
if (cm != nullptr) {
cm->onStatusChanged(status, cameraId);
} else {
ALOGE("Cannot deliver status change. Global camera manager died");
}
return binder::Status::ok();
}
void CameraManagerGlobal::onStatusChanged(
int32_t status, int32_t cameraId) {
Mutex::Autolock _l(mLock);
onStatusChangedLocked(status, cameraId);
}
void CameraManagerGlobal::onStatusChangedLocked(
int32_t status, int32_t cameraId) {
if (!validStatus(status)) {
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
return;
}
bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
int32_t oldStatus = firstStatus ?
status : // first status
mDeviceStatusMap[cameraId];
if (!firstStatus &&
isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
// No status update. No need to send callback
return;
}
// Iterate through all registered callbacks
mDeviceStatusMap[cameraId] = 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->setInt32(kCameraIdKey, cameraId);
msg->post();
}
}
} // namespace android
/**
* ACameraManger Implementation
*/
camera_status_t
ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
if (isCameraServiceDisabled()) {
mCachedCameraIdList.numCameras = 0;
mCachedCameraIdList.cameraIds = new const char*[0];
*cameraIdList = &mCachedCameraIdList;
return ACAMERA_OK;
}
int numCameras = 0;
Vector<char *> cameraIds;
sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
// Get number of cameras
int numAllCameras = 0;
binder::Status serviceRet = cs->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL,
&numAllCameras);
if (!serviceRet.isOk()) {
ALOGE("%s: Error getting camera count: %s", __FUNCTION__,
serviceRet.toString8().string());
numAllCameras = 0;
}
// Filter API2 compatible cameras and push to cameraIds
for (int i = 0; i < numAllCameras; i++) {
// TODO: Only suppot HALs that supports API2 directly now
bool camera2Support = false;
serviceRet = cs->supportsCameraApi(i, hardware::ICameraService::API_VERSION_2,
&camera2Support);
char buf[kMaxCameraIdLen];
if (camera2Support) {
numCameras++;
mCameraIds.insert(i);
snprintf(buf, sizeof(buf), "%d", i);
size_t cameraIdSize = strlen(buf) + 1;
char *cameraId = new char[cameraIdSize];
if (!cameraId) {
ALOGE("Allocate memory for ACameraIdList failed!");
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
}
strlcpy(cameraId, buf, cameraIdSize);
cameraIds.push(cameraId);
}
}
mCachedCameraIdList.numCameras = numCameras;
mCachedCameraIdList.cameraIds = new const char*[numCameras];
if (!mCachedCameraIdList.cameraIds) {
ALOGE("Allocate memory for ACameraIdList failed!");
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
}
for (int i = 0; i < numCameras; i++) {
mCachedCameraIdList.cameraIds[i] = cameraIds[i];
}
}
*cameraIdList = &mCachedCameraIdList;
return ACAMERA_OK;
}
camera_status_t
ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
Mutex::Autolock _l(mLock);
ACameraIdList* cachedList;
camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
if (ret != ACAMERA_OK) {
ALOGE("Get camera ID list failed! err: %d", ret);
return ret;
}
int numCameras = cachedList->numCameras;
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!");
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
}
for (int i = 0; i < numCameras; i++) {
const char* src = cachedList->cameraIds[i];
size_t dstSize = strlen(src) + 1;
char* dst = new char[dstSize];
if (!dst) {
ALOGE("Allocate memory for ACameraIdList failed!");
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 ++) {
delete[] cameraIdList->cameraIds[i];
}
delete[] cameraIdList->cameraIds;
}
delete cameraIdList;
}
}
camera_status_t ACameraManager::getCameraCharacteristics(
const char *cameraIdStr, ACameraMetadata **characteristics) {
Mutex::Autolock _l(mLock);
ACameraIdList* cachedList;
// Make sure mCameraIds is initialized
camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
if (ret != ACAMERA_OK) {
ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
return ret;
}
int cameraId = atoi(cameraIdStr);
if (mCameraIds.count(cameraId) == 0) {
ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
CameraMetadata rawMetadata;
binder::Status serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
if (!serviceRet.isOk()) {
ALOGE("Get camera characteristics from camera service failed: %s",
serviceRet.toString8().string());
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) {
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;
}
std::unique_ptr<ACameraMetadata> chars(rawChars);
rawChars = nullptr;
ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
int id = atoi(cameraId);
sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
sp<hardware::camera2::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
binder::Status serviceRet = cs->connectDevice(
callbacks, id, String16(""),
hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
if (!serviceRet.isOk()) {
ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().string());
// Convert serviceRet to camera_status_t
switch(serviceRet.serviceSpecificErrorCode()) {
case hardware::ICameraService::ERROR_DISCONNECTED:
ret = ACAMERA_ERROR_CAMERA_DISCONNECTED;
break;
case hardware::ICameraService::ERROR_CAMERA_IN_USE:
ret = ACAMERA_ERROR_CAMERA_IN_USE;
break;
case hardware::ICameraService::ERROR_MAX_CAMERAS_IN_USE:
ret = ACAMERA_ERROR_MAX_CAMERA_IN_USE;
break;
case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
ret = ACAMERA_ERROR_INVALID_PARAMETER;
break;
case hardware::ICameraService::ERROR_DEPRECATED_HAL:
// Should not reach here since we filtered legacy HALs earlier
ret = ACAMERA_ERROR_INVALID_PARAMETER;
break;
case hardware::ICameraService::ERROR_DISABLED:
ret = ACAMERA_ERROR_CAMERA_DISABLED;
break;
case hardware::ICameraService::ERROR_PERMISSION_DENIED:
ret = ACAMERA_ERROR_PERMISSION_DENIED;
break;
case hardware::ICameraService::ERROR_INVALID_OPERATION:
default:
ret = ACAMERA_ERROR_UNKNOWN;
break;
}
delete device;
return ret;
}
if (deviceRemote == nullptr) {
ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
delete device;
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
device->setRemoteDevice(deviceRemote);
*outDevice = device;
return ACAMERA_OK;
}
ACameraManager::~ACameraManager() {
Mutex::Autolock _l(mLock);
if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
delete[] mCachedCameraIdList.cameraIds[i];
}
delete[] mCachedCameraIdList.cameraIds;
}
}