前面咱們詳細分析了從應用層調用CameraManager的openCamera的方法來打開相機的邏輯,上次的分析咱們來到了CameraServer進程當中,可是尚未真正看到open操做設備節點來實現真正打開的邏輯,遺留的問題也就是從frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp文件中的status_t Camera3Device::initialize(sp<CameraProviderManager> manager)方法的status_t res = manager->openSession(mId.string(), this, /*out*/ &session);這句代碼進去後進行的處理。android
咱們知道,Android的內核是Linux內核,Linux上全部的設備都被抽象成文件節點,對設備的操做都變成了對文件節點的操做,很是方便,咱們openCamera的邏輯最終確定也是經過open系統函數來打開camera的文件節點,而open系統調用的處理就是對應的camera驅動了。session
好,咱們回到正文,status_t res = manager->openSession(mId.string(), this, /*out*/ &session);這句邏輯中的manager是一個sp<CameraProviderManager>對象,那咱們就來看一下frameworks\av\services\camera\libcameraservice\common\CameraProviderManager.cpp文件中的openSession方法的實現,源碼以下:app
status_t CameraProviderManager::openSession(const std::string &id,
const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id,
/*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
Status status;
hardware::Return<void> ret;
ret = deviceInfo3->mInterface->open(callback, [&status, &session]
(Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
status = s;
if (status == Status::OK) {
*session = cameraSession;
}
});
if (!ret.isOk()) {
ALOGE("%s: Transaction error opening a session for camera device %s: %s",
__FUNCTION__, id.c_str(), ret.description().c_str());
return DEAD_OBJECT;
}
return mapToStatusT(status);
}
該方法中根據傳入的最小和最大版本號調用findDeviceInfoLocked方法獲取到一個DeviceInfo對象,其中的邏輯比較簡單,源碼以下:dom
CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
const std::string& id,
hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
for (auto& provider : mProviders) {
for (auto& deviceInfo : provider->mDevices) {
if (deviceInfo->mId == id &&
minVersion <= deviceInfo->mVersion && maxVersion >= deviceInfo->mVersion) {
return deviceInfo.get();
}
}
}
return nullptr;
}
能夠看到,該方法的邏輯就是對成員變量mProviders進行遍歷,判斷每一個DeviceInfo的id值、最小版本、最大版本號是否符合傳入的最小和最大版本,符合的話,就返回該對象,那咱們就要問一下了,mProviders中的值是何時添加的呢?咱們大概追究一下,它是在CameraService進行啓動時,初始化CameraProviderManager對象的邏輯中,經過addProviderLocked方法生成具體的DeviceInfo對象,添加到mProviders成員變量中的。addProviderLocked方法的源碼以下:socket
status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == newProvider) {
ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,
newProvider.c_str());
return ALREADY_EXISTS;
}
}
sp<provider::V2_4::ICameraProvider> interface;
interface = mServiceProxy->getService(newProvider);
if (interface == nullptr) {
if (expected) {
ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
newProvider.c_str());
return BAD_VALUE;
} else {
return OK;
}
}
sp<ProviderInfo> providerInfo =
new ProviderInfo(newProvider, interface, this);
status_t res = providerInfo->initialize();
if (res != OK) {
return res;
}
mProviders.push_back(providerInfo);
return OK;
}
這個方法中有一個很是重要的對象,就是interface = mServiceProxy->getService(newProvider)邏輯返回的interface,它又是一個binder對象,獲取camera屬性、數量等實質性的方法都是經過它來完成的,獲取成功後,以它爲參數構造一個ProviderInfo對象,最後添加到mProviders成員變量當中。ide
好了,咱們回到openSession方法當中,找到deviceInfo對象以後,而後調用deviceInfo3->mInterface->open,而它的成員變量mInterface就是在前面咱們說構造ProviderInfo時獲取到的binder對象了,它其實是hardware\interfaces\camera\device\3.2\default\CameraDevice.cpp對象了,來到這裏,咱們就進入了CameraDaemon進程當中,兩個進程的通訊是經過HIDL,其實仍是binder進程間通訊機制,只是它是用來提供給HAL層服務的,因此和AIDL相似,取了個HIDL的名字。這裏須要說一下,爲是什麼是3.2下面的這個類呢?由於咱們在調用openSession方法時,傳入的第二個參數const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback和第三個參數sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session就能夠很是明顯的看出來,當前調用的版本是V3_2。接下來,咱們就來看一下CameraDevice.cpp類的open方法的實現,源碼以下:函數
Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
Status status = initStatus();
sp<CameraDeviceSession> session = nullptr;
if (callback == nullptr) {
ALOGE("%s: cannot open camera %s. callback is null!",
__FUNCTION__, mCameraId.c_str());
_hidl_cb(Status::ILLEGAL_ARGUMENT, session);
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, session);
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<hw_device_t**>(&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 = new CameraDeviceSession(
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;
mLock.unlock();
}
_hidl_cb(status, session);
return Void();
}
咱們先來看一下該方法的參數,第一個是callback對象,它的使用方法和咱們以前講的應用層調用openCamera時在CameraManager中傳入的binder類型的callback是同樣的,Server端拿到這個callback以後,就能夠針對須要的節點事件回調應用層,而這裏是在CameraDaemon回調CameraServer,道理是同樣的。這個callback參數最終賦值給HAL層中的CameraDeviceSession類的mResultBatcher成員變量了;第二個參數是open_cb類型,從它的命名中能夠看出來,它也是一個回調函數,很是方便,就像一個函數指針同樣,它在CameraProviderManager一側中像一個結構體同樣傳了過來,當CameraDevice類中的open執行完成後,就會將session對象做爲參數回傳到CameraProviderManager這一側,咱們就拿到了session,後續對camera的操做都是經過這個sesson對象來進行中轉完成的。CameraProviderManager這一側傳入的結構體以下:oop
咱們繼續閱讀代碼,open方法中先判斷status,正常的話,接着調用res = mModule->open(mCameraId.c_str(), reinterpret_cast<hw_device_t**>(&device))來執行相機的打開操做,mModule對象是CameraDevice類的成員變量,它是在CameraDevice的構造函數中傳入的,而CameraDevice類的對象是在hardware\interfaces\camera\provider\2.4\default\CameraProvider.cpp文件中的getCameraDeviceInterface_V3_x方法中構造的,該方法也是CameraDaemon進程爲CameraServer進程提供的,當添加相機設備時,CameraServer就須要查詢和獲取camera設備,也就會使用到這個接口,getCameraDeviceInterface_V3_x方法源碼以下:fetch
Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
const hidl_string& cameraDeviceName, 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> device =
new android::hardware::camera::device::V3_2::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();
}
能夠看到,在構造CameraDevice對象時,傳入的第一個參數mModule,它也是CameraProvider類的成員變量,它的定義在hardware\interfaces\camera\provider\2.4\default\CameraProvider.h頭文件中,源碼以下:ui
它是一個CameraModule對象,那麼咱們接下來就看看hardware\interfaces\camera\common\1.0\default\CameraModule.cpp類的open方法,來看看它是如何處理的。它的open方法源碼以下:
int CameraModule::open(const char* id, struct hw_device_t** device) {
int res;
ATRACE_BEGIN("camera_module->open");
res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
ATRACE_END();
return res;
}
該方法很是簡潔,就是調用mModule類的common.methods的open方法處理,它的mModule也是在CameraModule類的構造函數中傳入的,而CameraModule的構造方法是在CameraProvider類的initialize()方法中調用的,源碼以下:
bool CameraProvider::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;
}
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;
mCameraIds.add(cameraIdStr);
// initialize mCameraDeviceNames and mOpenLegacySupported
mOpenLegacySupported[cameraIdStr] = false;
int deviceVersion = mModule->getDeviceVersion(i);
mCameraDeviceNames.add(
std::make_pair(cameraIdStr,
getHidlDeviceName(cameraIdStr, deviceVersion)));
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);
mCameraDeviceNames.add(
std::make_pair(cameraIdStr,
getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
} 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__);
}
}
}
return false; // mInitFailed
}
這裏構造CameraModule時傳入的參數rawModule就是在該方法一開始時,經過調用int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule)獲取到的,看到這裏你們是否是以爲有些熟悉,CAMERA_HARDWARE_MODULE_ID就是HAL層定義的module,從這裏往下就和對應的設備廠商有密切關係了,固然具體的實現也就差異很大了,而不像咱們前面到這裏,不分廠商,全部設備,只要是android都是通用的。好了,我這裏下載的8.0源碼中提供了三個廠商的實現,分別命名爲google、huawei、lge,截圖以下:
google目錄下具體的實現使用的是高通的設備,咱們就來看看這個是怎麼實現的。高通相機中的hw_module_t、camera_module_t兩個結構體定義在device\google\marlin\camera\QCamera2\QCamera2Hal.cpp文件中,在CameraProvider類的initialize()方法中調用hw_get_module獲取到的就是這裏定義的camera_module_t,它也就是構造CameraModule時傳入的參數,好了,回到CameraModule類的open方法中,繼續調用它的common(這裏就是camera_module_t結構體的第一個成員變量common了,它指向camera_common結構體)的methods(就是static hw_module_t camera_common結構體的倒數第三個屬性methods了,它指向&qcamera::QCamera2Factory::mModuleMethods)的open方法,咱們仍是以goole目錄下高通的實現爲例,繼續看一下QCamera2Factory類的mModuleMethods的定義,device\google\marlin\camera\QCamera2\QCamera2Factory.cpp文件中的mModuleMethods定義源碼以下:
struct hw_module_methods_t QCamera2Factory::mModuleMethods = {
.open = QCamera2Factory::camera_device_open,
};
這裏的open又指向了QCamera2Factory類的camera_device_open方法,該方法的源碼以下:
int QCamera2Factory::camera_device_open(
const struct hw_module_t *module, const char *id,
struct hw_device_t **hw_device)
{
int rc = NO_ERROR;
if (module != &HAL_MODULE_INFO_SYM.common) {
LOGE("Invalid module. Trying to open %p, expect %p",
module, &HAL_MODULE_INFO_SYM.common);
return INVALID_OPERATION;
}
if (!id) {
LOGE("Invalid camera id");
return BAD_VALUE;
}
if(gQCameraMuxer)
rc = gQCameraMuxer->camera_device_open(module, id, hw_device);
else
rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
return rc;
}
這裏先判斷成員變量gQCameraMuxer是否爲空,它是在QCamera2Factory類的構造函數中,判斷若是當前爲雙攝(bDualCamera爲true,它是經過配置項persist.camera.dual.camera獲取的)的狀況下獲取的,這裏咱們假設它不爲空,那麼就調用rc = gQCameraMuxer->camera_device_open(module, id, hw_device)來繼續打開camera,gQCameraMuxer的類型爲QCameraMuxer,接下來看一下device\google\marlin\camera\QCamera2\HAL\QCameraMuxer.cpp類中的camera_device_open方法的實現,源碼以下:
int QCameraMuxer::camera_device_open(
__unused const struct hw_module_t *module, const char *id,
struct hw_device_t **hw_device)
{
int rc = NO_ERROR;
LOGH("id= %d",atoi(id));
if (!id) {
LOGE("Invalid camera id");
return BAD_VALUE;
}
rc = gMuxer->cameraDeviceOpen(atoi(id), hw_device);
LOGH("id= %d, rc: %d", atoi(id), rc);
return rc;
}
該方法的邏輯也很是簡潔,參數正確,就接着調用gMuxer變量的cameraDeviceOpen方法來處理,gMuxer就是當前類的實例,它的cameraDeviceOpen方法的源碼以下:
int QCameraMuxer::cameraDeviceOpen(int camera_id,
struct hw_device_t **hw_device)
{
int rc = NO_ERROR;
uint32_t phyId = 0;
qcamera_logical_descriptor_t *cam = NULL;
if (camera_id < 0 || camera_id >= m_nLogicalCameras) {
LOGE("Camera id %d not found!", camera_id);
return -ENODEV;
}
if ( NULL == m_pLogicalCamera) {
LOGE("Hal descriptor table is not initialized!");
return NO_INIT;
}
char prop[PROPERTY_VALUE_MAX];
property_get("persist.camera.dc.frame.sync", prop, "1");
m_bFrameSyncEnabled = atoi(prop);
// Get logical camera
cam = &m_pLogicalCamera[camera_id];
if (m_pLogicalCamera[camera_id].device_version ==
CAMERA_DEVICE_API_VERSION_1_0) {
// HW Dev Holders
hw_device_t *hw_dev[cam->numCameras];
if (m_pPhyCamera[cam->pId[0]].type != CAM_TYPE_MAIN) {
LOGE("Physical camera at index 0 is not main!");
return UNKNOWN_ERROR;
}
// Open all physical cameras
for (uint32_t i = 0; i < cam->numCameras; i++) {
phyId = cam->pId[i];
QCamera2HardwareInterface *hw =
new QCamera2HardwareInterface((uint32_t)phyId);
if (!hw) {
LOGE("Allocation of hardware interface failed");
return NO_MEMORY;
}
hw_dev[i] = NULL;
// Make Camera HWI aware of its mode
cam_sync_related_sensors_event_info_t info;
info.sync_control = CAM_SYNC_RELATED_SENSORS_ON;
info.mode = m_pPhyCamera[phyId].mode;
info.type = m_pPhyCamera[phyId].type;
rc = hw->setRelatedCamSyncInfo(&info);
hw->setFrameSyncEnabled(m_bFrameSyncEnabled);
if (rc != NO_ERROR) {
LOGE("setRelatedCamSyncInfo failed %d", rc);
delete hw;
return rc;
}
rc = hw->openCamera(&hw_dev[i]);
if (rc != NO_ERROR) {
delete hw;
return rc;
}
hw->getCameraSessionId(&m_pPhyCamera[phyId].camera_server_id);
m_pPhyCamera[phyId].dev = reinterpret_cast<camera_device_t*>(hw_dev[i]);
m_pPhyCamera[phyId].hwi = hw;
cam->sId[i] = m_pPhyCamera[phyId].camera_server_id;
LOGH("camera id %d server id : %d hw device %x, hw %x",
phyId, cam->sId[i], hw_dev[i], hw);
}
} else {
LOGE("Device version for camera id %d invalid %d",
camera_id, m_pLogicalCamera[camera_id].device_version);
return BAD_VALUE;
}
cam->dev.common.tag = HARDWARE_DEVICE_TAG;
cam->dev.common.version = HARDWARE_DEVICE_API_VERSION(1, 0);
cam->dev.common.close = close_camera_device;
cam->dev.ops = &mCameraMuxerOps;
cam->dev.priv = (void*)cam;
*hw_device = &cam->dev.common;
return rc;
}
該方法中最重要的就是中間的for循環了,先構造QCamera2HardwareInterface對象,而後調用它的openCamera方法打開camera,接下來就看一下device\google\marlin\camera\QCamera2\HAL3\QCamera3HWI.cpp類的openCamera方法的實現,源碼以下:
int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
int rc = 0;
if (mState != CLOSED) {
*hw_device = NULL;
return PERMISSION_DENIED;
}
m_perfLock.lock_acq();
LOGI("[KPI Perf]: E PROFILE_OPEN_CAMERA camera id %d",
mCameraId);
rc = openCamera();
if (rc == 0) {
*hw_device = &mCameraDevice.common;
} else
*hw_device = NULL;
m_perfLock.lock_rel();
LOGI("[KPI Perf]: X PROFILE_OPEN_CAMERA camera id %d, rc: %d",
mCameraId, rc);
if (rc == NO_ERROR) {
mState = OPENED;
}
return rc;
}
它又是轉調另外一個openCamera方法來處理的,源碼以下:
int QCamera3HardwareInterface::openCamera()
{
int rc = 0;
char value[PROPERTY_VALUE_MAX];
KPI_ATRACE_CALL();
if (mCameraHandle) {
LOGE("Failure: Camera already opened");
return ALREADY_EXISTS;
}
rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId);
if (rc < 0) {
LOGE("Failed to reserve flash for camera id: %d",
mCameraId);
return UNKNOWN_ERROR;
}
rc = camera_open((uint8_t)mCameraId, &mCameraHandle);
if (rc) {
LOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle);
return rc;
}
if (!mCameraHandle) {
LOGE("camera_open failed. mCameraHandle = %p", mCameraHandle);
return -ENODEV;
}
rc = mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,
camEvtHandle, (void *)this);
if (rc < 0) {
LOGE("Error, failed to register event callback");
/* Not closing camera here since it is already handled in destructor */
return FAILED_TRANSACTION;
}
mExifParams.debug_params =
(mm_jpeg_debug_exif_params_t *) malloc (sizeof(mm_jpeg_debug_exif_params_t));
if (mExifParams.debug_params) {
memset(mExifParams.debug_params, 0, sizeof(mm_jpeg_debug_exif_params_t));
} else {
LOGE("Out of Memory. Allocation failed for 3A debug exif params");
return NO_MEMORY;
}
mFirstConfiguration = true;
//Notify display HAL that a camera session is active.
//But avoid calling the same during bootup because camera service might open/close
//cameras at boot time during its initialization and display service will also internally
//wait for camera service to initialize first while calling this display API, resulting in a
//deadlock situation. Since boot time camera open/close calls are made only to fetch
//capabilities, no need of this display bw optimization.
//Use "service.bootanim.exit" property to know boot status.
property_get("service.bootanim.exit", value, "0");
if (atoi(value) == 1) {
pthread_mutex_lock(&gCamLock);
if (gNumCameraSessions++ == 0) {
setCameraLaunchStatus(true);
}
pthread_mutex_unlock(&gCamLock);
}
//fill the session id needed while linking dual cam
pthread_mutex_lock(&gCamLock);
rc = mCameraHandle->ops->get_session_id(mCameraHandle->camera_handle,
&sessionId[mCameraId]);
pthread_mutex_unlock(&gCamLock);
if (rc < 0) {
LOGE("Error, failed to get sessiion id");
return UNKNOWN_ERROR;
} else {
//Allocate related cam sync buffer
//this is needed for the payload that goes along with bundling cmd for related
//camera use cases
m_pRelCamSyncHeap = new QCamera3HeapMemory(1);
rc = m_pRelCamSyncHeap->allocate(sizeof(cam_sync_related_sensors_event_info_t));
if(rc != OK) {
rc = NO_MEMORY;
LOGE("Dualcam: Failed to allocate Related cam sync Heap memory");
return NO_MEMORY;
}
//Map memory for related cam sync buffer
rc = mCameraHandle->ops->map_buf(mCameraHandle->camera_handle,
CAM_MAPPING_BUF_TYPE_SYNC_RELATED_SENSORS_BUF,
m_pRelCamSyncHeap->getFd(0),
sizeof(cam_sync_related_sensors_event_info_t),
m_pRelCamSyncHeap->getPtr(0));
if(rc < 0) {
LOGE("Dualcam: failed to map Related cam sync buffer");
rc = FAILED_TRANSACTION;
return NO_MEMORY;
}
m_pRelCamSyncBuf =
(cam_sync_related_sensors_event_info_t*) DATA_PTR(m_pRelCamSyncHeap,0);
}
LOGH("mCameraId=%d",mCameraId);
return NO_ERROR;
}
這裏又轉調camera_open方法來處理,camera_open方法的實現是在device\google\marlin\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.c文件中,源碼以下:
int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)
{
int32_t rc = 0;
mm_camera_obj_t *cam_obj = NULL;
#ifdef QCAMERA_REDEFINE_LOG
mm_camera_set_dbg_log_properties();
#endif
LOGD("E camera_idx = %d\n", camera_idx);
if (camera_idx >= g_cam_ctrl.num_cam) {
LOGE("Invalid camera_idx (%d)", camera_idx);
return -EINVAL;
}
pthread_mutex_lock(&g_intf_lock);
/* opened already */
if(NULL != g_cam_ctrl.cam_obj[camera_idx]) {
/* Add reference */
g_cam_ctrl.cam_obj[camera_idx]->ref_count++;
pthread_mutex_unlock(&g_intf_lock);
LOGD("opened alreadyn");
*camera_vtbl = &g_cam_ctrl.cam_obj[camera_idx]->vtbl;
return rc;
}
cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));
if(NULL == cam_obj) {
pthread_mutex_unlock(&g_intf_lock);
LOGE("no mem");
return -EINVAL;
}
/* initialize camera obj */
memset(cam_obj, 0, sizeof(mm_camera_obj_t));
cam_obj->ctrl_fd = -1;
cam_obj->ds_fd = -1;
cam_obj->ref_count++;
cam_obj->my_hdl = mm_camera_util_generate_handler(camera_idx);
cam_obj->vtbl.camera_handle = cam_obj->my_hdl; /* set handler */
cam_obj->vtbl.ops = &mm_camera_ops;
pthread_mutex_init(&cam_obj->cam_lock, NULL);
/* unlock global interface lock, if not, in dual camera use case,
* current open will block operation of another opened camera obj*/
pthread_mutex_lock(&cam_obj->cam_lock);
pthread_mutex_unlock(&g_intf_lock);
rc = mm_camera_open(cam_obj);
pthread_mutex_lock(&g_intf_lock);
if (rc != 0) {
LOGE("mm_camera_open err = %d", rc);
pthread_mutex_destroy(&cam_obj->cam_lock);
g_cam_ctrl.cam_obj[camera_idx] = NULL;
free(cam_obj);
cam_obj = NULL;
pthread_mutex_unlock(&g_intf_lock);
*camera_vtbl = NULL;
return rc;
} else {
LOGD("Open succeded\n");
g_cam_ctrl.cam_obj[camera_idx] = cam_obj;
pthread_mutex_unlock(&g_intf_lock);
*camera_vtbl = &cam_obj->vtbl;
return 0;
}
}
這裏調用malloc給方法變量分配內存,memset初始化,而後接着調用mm_camera_open繼續處理,mm_camera_open方法的實如今device\google\marlin\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.c文件中,源碼以下:
int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{
char dev_name[MM_CAMERA_DEV_NAME_LEN];
int32_t rc = 0;
int8_t n_try=MM_CAMERA_DEV_OPEN_TRIES;
uint8_t sleep_msec=MM_CAMERA_DEV_OPEN_RETRY_SLEEP;
int cam_idx = 0;
const char *dev_name_value = NULL;
int l_errno = 0;
LOGD("begin\n");
if (NULL == my_obj) {
goto on_error;
}
dev_name_value = mm_camera_util_get_dev_name(my_obj->my_hdl);
if (NULL == dev_name_value) {
goto on_error;
}
snprintf(dev_name, sizeof(dev_name), "/dev/%s",
dev_name_value);
sscanf(dev_name, "/dev/video%d", &cam_idx);
LOGD("dev name = %s, cam_idx = %d", dev_name, cam_idx);
do{
n_try--;
errno = 0;
my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
l_errno = errno;
LOGD("ctrl_fd = %d, errno == %d", my_obj->ctrl_fd, l_errno);
if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 )) {
break;
}
LOGE("Failed with %s error, retrying after %d milli-seconds",
strerror(errno), sleep_msec);
usleep(sleep_msec * 1000U);
}while (n_try > 0);
if (my_obj->ctrl_fd < 0) {
LOGE("cannot open control fd of '%s' (%s)\n",
dev_name, strerror(l_errno));
if (l_errno == EBUSY)
rc = -EUSERS;
else
rc = -1;
goto on_error;
} else {
mm_camera_get_session_id(my_obj, &my_obj->sessionid);
LOGH("Camera Opened id = %d sessionid = %d", cam_idx, my_obj->sessionid);
}
#ifdef DAEMON_PRESENT
/* open domain socket*/
n_try = MM_CAMERA_DEV_OPEN_TRIES;
do {
n_try--;
my_obj->ds_fd = mm_camera_socket_create(cam_idx, MM_CAMERA_SOCK_TYPE_UDP);
l_errno = errno;
LOGD("ds_fd = %d, errno = %d", my_obj->ds_fd, l_errno);
if((my_obj->ds_fd >= 0) || (n_try <= 0 )) {
LOGD("opened, break out while loop");
break;
}
LOGD("failed with I/O error retrying after %d milli-seconds",
sleep_msec);
usleep(sleep_msec * 1000U);
} while (n_try > 0);
if (my_obj->ds_fd < 0) {
LOGE("cannot open domain socket fd of '%s'(%s)\n",
dev_name, strerror(l_errno));
rc = -1;
goto on_error;
}
#else /* DAEMON_PRESENT */
cam_status_t cam_status;
cam_status = mm_camera_module_open_session(my_obj->sessionid,
mm_camera_module_event_handler);
if (cam_status < 0) {
LOGE("Failed to open session");
if (cam_status == CAM_STATUS_BUSY) {
rc = -EUSERS;
} else {
rc = -1;
}
goto on_error;
}
#endif /* DAEMON_PRESENT */
pthread_mutex_init(&my_obj->msg_lock, NULL);
pthread_mutex_init(&my_obj->cb_lock, NULL);
pthread_mutex_init(&my_obj->evt_lock, NULL);
PTHREAD_COND_INIT(&my_obj->evt_cond);
LOGD("Launch evt Thread in Cam Open");
snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Dispatch");
mm_camera_cmd_thread_launch(&my_obj->evt_thread,
mm_camera_dispatch_app_event,
(void *)my_obj);
/* launch event poll thread
* we will add evt fd into event poll thread upon user first register for evt */
LOGD("Launch evt Poll Thread in Cam Open");
snprintf(my_obj->evt_poll_thread.threadName, THREAD_NAME_SIZE, "CAM_evntPoll");
mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,
MM_CAMERA_POLL_TYPE_EVT);
mm_camera_evt_sub(my_obj, TRUE);
/* unlock cam_lock, we need release global intf_lock in camera_open(),
* in order not block operation of other Camera in dual camera use case.*/
pthread_mutex_unlock(&my_obj->cam_lock);
LOGD("end (rc = %d)\n", rc);
return rc;
on_error:
if (NULL == dev_name_value) {
LOGE("Invalid device name\n");
rc = -1;
}
if (NULL == my_obj) {
LOGE("Invalid camera object\n");
rc = -1;
} else {
if (my_obj->ctrl_fd >= 0) {
close(my_obj->ctrl_fd);
my_obj->ctrl_fd = -1;
}
#ifdef DAEMON_PRESENT
if (my_obj->ds_fd >= 0) {
mm_camera_socket_close(my_obj->ds_fd);
my_obj->ds_fd = -1;
}
#endif
}
/* unlock cam_lock, we need release global intf_lock in camera_open(),
* in order not block operation of other Camera in dual camera use case.*/
pthread_mutex_unlock(&my_obj->cam_lock);
return rc;
}
到這裏,終於看到了open的系統調用,HAL端也就是從這裏進入內核,調用驅動來處理的,這裏你們能夠看到,是經過do/while循環來處理的,有一個重試機制,重試次數n_try不斷的減少,當它等於0時,相機設備還未正常打開,就退出do/while循環了,它的初值爲MM_CAMERA_DEV_OPEN_TRIES,該宏定義的值爲20,在do判斷中,只要if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 ))條件中有一個成立,就跳出循環,(my_obj->ctrl_fd >= 0)的意思是就camera打開成功,返回的FD有效;(errno != EIO && errno != ETIMEDOUT)的意思是未出現IO或者超時錯誤;(n_try <= 0 )意思是重試次數已用完,打開成功後,還要進行一些其餘初始化的操做。
到這裏,openCamera纔算完成了,你們能夠看到,中間的過程真是複雜,固然咱們所分析的部分尚未包含驅動部分,想要搞清楚整個邏輯,仍是要花費很大的氣力的,也但願咱們搞技術的同事,可以認認真真的靜下心來專心搞技術,以此來提高咱們的能力。
好了,今天就到這裏,休息一下!