以TI的platform为例子,也就是这两个文件
/path/to/aosp/frameworks/av/services/camera/libcameraservice/CameraHardwareInterface.h
和
/path/to/aosp/hardware/ti/omap4xxx/camera/CameraHal.cpp
是如何关联的。
谁来加载camera.$platform$.so,这个是真正的HAL的实现,里面实际最终会去调用Driver(中间透过rpmsg-omx1)。
好突然,可能你现在还不知道camera.$platform$.so是什么?是这样的,但是到你看到后面你就会发现Vendor的HAL实现是包成一个so档的,也就是这个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void CameraService::onFirstRef() { BnCameraService::onFirstRef(); if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, ( const hw_module_t **)&mModule) < 0 ) { ALOGE( "Could not load camera HAL module" ); mNumberOfCameras = 0 ; } else { mNumberOfCameras = mModule->get_number_of_cameras(); if (mNumberOfCameras > MAX_CAMERAS) { ALOGE( "Number of cameras(%d) > MAX_CAMERAS(%d)." , mNumberOfCameras, MAX_CAMERAS); mNumberOfCameras = MAX_CAMERAS; } for ( int i = 0 ; i < mNumberOfCameras; i++) { setCameraFree(i); } } } |
在/path/to/aosp/hardware/libhardware/hardware.c当中有下面这些方法
1 | hw_get_module( const char *id, const struct hw_module_t **module) // 这里定义的是hw_module_t,但是Vendor HAL当中实现的是camera_module_t |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* Loop through the configuration variants looking for a module */ for (i= 0 ; i<HAL_VARIANT_KEYS_COUNT+ 1 ; i++) { if (i < HAL_VARIANT_KEYS_COUNT) { if (property_get(variant_keys[i], prop, NULL) == 0 ) { continue ; } snprintf(path, sizeof(path), "%s/%s.%s.so" , HAL_LIBRARY_PATH2, name, prop); if (access(path, R_OK) == 0 ) break ; snprintf(path, sizeof(path), "%s/%s.%s.so" , HAL_LIBRARY_PATH1, name, prop); if (access(path, R_OK) == 0 ) break ; } else { snprintf(path, sizeof(path), "%s/%s.default.so" , HAL_LIBRARY_PATH1, name); if (access(path, R_OK) == 0 ) break ; } } |
1 2 3 4 5 6 7 8 9 10 | static const char *variant_keys[] = { "ro.hardware" , /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board" , "ro.board.platform" , "ro.arch" }; static const int HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/sizeof(variant_keys[ 0 ])); |
/path/to/aosp/out/target/product/panda/system/build.prop
这里面有platform或者arch相关的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */ handle = dlopen(path, RTLD_NOW); /* Get the address of the struct hal_module_info. */ const char *sym = HAL_MODULE_INFO_SYM_AS_STR; hmi = (struct hw_module_t *)dlsym(handle, sym); if (hmi == NULL) { ALOGE( "load: couldn't find symbol %s" , sym); status = -EINVAL; goto done; } *pHmi = hmi; // 动态加载Vendor HAL之后要返回这个hw_module_t结构体供Android Service/HAL层使用 |
这个load出来的HAL_MODULE_INFO_SYM_AS_STR是什么?
先看它是什么,定义位于hardware.h当中
1 2 3 4 5 6 7 8 9 | /** * Name of the hal_module_info */ #define HAL_MODULE_INFO_SYM HMI /** * Name of the hal_module_info as a string */ #define HAL_MODULE_INFO_SYM_AS_STR "HMI" |
理论上来说dlsym就是会去load一个名字为”HMI”的变量/函数,也就是说在Vendor HAL当中必然有名字为”HMI”的这样一个东西。
看看hw_module_t的定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; /** * The API version of the implemented module. The module owner is * responsible for updating the version when a module interface has * changed. * * The derived modules such as gralloc and audio own and manage this field. * The module user must interpret the version field to decide whether or * not to inter-operate with the supplied module implementation. * For example, SurfaceFlinger is responsible for making sure that * it knows how to manage different versions of the gralloc-module API, * and AudioFlinger must know how to do the same for audio-module API. * * The module API version should include a major and a minor component. * For example, version 1.0 could be represented as 0x0100. This format * implies that versions 0x0100-0x01ff are all API-compatible. * * In the future, libhardware will expose a hw_get_module_version() * (or equivalent) function that will take minimum/maximum supported * versions as arguments and would be able to reject modules with * versions outside of the supplied range. */ uint16_t module_api_version; #define version_major module_api_version /** * version_major/version_minor defines are supplied here for temporary * source code compatibility. They will be removed in the next version. * ALL clients must convert to the new version format. */ /** * The API version of the HAL module interface. This is meant to * version the hw_module_t, hw_module_methods_t, and hw_device_t * structures and definitions. * * The HAL interface owns this field. Module users/implementations * must NOT rely on this value for version information. * * Presently, 0 is the only valid value. */ uint16_t hal_api_version; #define version_minor hal_api_version /** Identifier of module */ const char *id; /** Name of this module */ const char *name; /** Author/owner/implementor of the module */ const char *author; /** Modules methods */ struct hw_module_methods_t* methods; /** module's dso */ void * dso; /** padding to 128 bytes, reserved for future use */ uint32_t reserved[ 32 - 7 ]; } hw_module_t; |
定义位于hardware.h当中
对于TI的hardware来讲,load的就是camera.omap4.so(也就是前面所说的camera.$platform$.so)的名字为HMI的结构体。
这个需要仔细看下才能发现HAL_MODULE_INFO_SYM实际就是HMI,hardware.h当中定义的那个macro。
HMI位于
/path/to/aosp/hardware/ti/omap4xxx/camera/CameraHal_Module.cpp
当中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | camera_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1 , version_minor: 0 , id: CAMERA_HARDWARE_MODULE_ID, name: "TI OMAP CameraHal Module" , author: "TI" , methods: &camera_module_methods, dso: NULL, /* remove compilation warnings */ reserved: { 0 }, /* remove compilation warnings */ }, get_number_of_cameras: camera_get_number_of_cameras, get_camera_info: camera_get_camera_info, }; |
通过’arm-eabi-objdump’ -t camera.omap4.so | grep ‘HMI’
也可以验证这一点
而再仔细看看这个common实际上就是hw_module_t这个结构体,这也就印证了前面hw_module_t定义的地方所说的
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
这里需要注意的是hardware.h当中定义的都是hw_module_t,但是Vendor HAL实现的都是自己的xxx_module_t,比如方法定义的类型和实际类型不一样,这个能工作有什么样的奥秘?
其实就是指针的第一个地址,Vendor HAL当中定义的结构必须要求第一个域是hw_module_t,这样地址就可以对应起来。
总之Android使用的这种技法需要理解,要不然都无法知道他们之间是怎么串起来的,指针强大,但小心使用,否则也可能伤身!
camera_device_t和hw_device_t也是一样的用法!
1 | #define CAMERA_HARDWARE_MODULE_ID "camera" |
定义位于camera_common.h当中
其他一些使用到的宏之类的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #ifndef _LINUX_LIMITS_H #define _LINUX_LIMITS_H #define NR_OPEN 1024 #define NGROUPS_MAX 65536 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define ARG_MAX 131072 #define CHILD_MAX 999 #define OPEN_MAX 256 #define LINK_MAX 127 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define MAX_CANON 255 #define MAX_INPUT 255 #define NAME_MAX 255 #define PATH_MAX 4096 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define PIPE_BUF 4096 #define XATTR_NAME_MAX 255 #define XATTR_SIZE_MAX 65536 #define XATTR_LIST_MAX 65536 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ #define RTSIG_MAX 32 #endif |
对于Camera HAL来说,你需要找到
1 2 3 4 5 6 7 8 9 10 | typedef struct camera_device { /** * camera_device.common.version must be in the range * HARDWARE_DEVICE_API_VERSION(0,0)-(1,FF). CAMERA_DEVICE_API_VERSION_1_0 is * recommended. */ hw_device_t common; camera_device_ops_t *ops; void *priv; } camera_device_t; |
位于camera.h当中
1 2 3 4 5 | typedef struct camera_module { hw_module_t common; int (*get_number_of_cameras)( void ); int (*get_camera_info)( int camera_id, struct camera_info *info); } camera_module_t; |
位于camera_common.h当中
扫平这些障碍之后,后面就会顺利多了。
比如takePicture这个动作,在CameraHal_Module当中会被于CameraHal关联起来,上层调用就会进入到CameraHal当中对应的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | status_t CameraHal::takePicture( ) { status_t ret = NO_ERROR; CameraFrame frame; CameraAdapter::BuffersDescriptor desc; int burst; const char *valstr = NULL; unsigned int bufferCount = 1 ; Mutex::Autolock lock(mLock); # if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS gettimeofday(&mStartCapture, NULL); #endif LOG_FUNCTION_NAME; if (!previewEnabled() && !mDisplayPaused) { LOG_FUNCTION_NAME_EXIT; CAMHAL_LOGEA( "Preview not started..." ); return NO_INIT; } // return error if we are already capturing if ( (mCameraAdapter->getState() == CameraAdapter::CAPTURE_STATE && mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE) || (mCameraAdapter->getState() == CameraAdapter::VIDEO_CAPTURE_STATE && mCameraAdapter->getNextState() != CameraAdapter::VIDEO_STATE) ) { CAMHAL_LOGEA( "Already capturing an image..." ); return NO_INIT; } // we only support video snapshot if we are in video mode (recording hint is set) valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); if ( (mCameraAdapter->getState() == CameraAdapter::VIDEO_STATE) && (valstr && strcmp(valstr, TICameraParameters::VIDEO_MODE)) ) { CAMHAL_LOGEA( "Trying to capture while recording without recording hint set..." ); return INVALID_OPERATION; } if ( !mBracketingRunning ) { if ( NO_ERROR == ret ) { burst = mParameters.getInt(TICameraParameters::KEY_BURST); } //Allocate all buffers only in burst capture case if ( burst > 1 ) { bufferCount = CameraHal::NO_BUFFERS_IMAGE_CAPTURE; if ( NULL != mAppCallbackNotifier.get() ) { mAppCallbackNotifier->setBurst( true ); } } else { if ( NULL != mAppCallbackNotifier.get() ) { mAppCallbackNotifier->setBurst( false ); } } // 这就是为什么我们正常拍照,preview就会stop住,拍完一张之后需要去startPreview // pause preview during normal image capture // do not pause preview if recording (video state) if (NO_ERROR == ret && NULL != mDisplayAdapter.get() && burst < 1 ) { if (mCameraAdapter->getState() != CameraAdapter::VIDEO_STATE) { mDisplayPaused = true ; mPreviewEnabled = false ; ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); // since preview is paused we should stop sending preview frames too if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) { mAppCallbackNotifier->disableMsgType (CAMERA_MSG_PREVIEW_FRAME); } } # if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS mDisplayAdapter->setSnapshotTimeRef(&mStartCapture); #endif } // if we taking video snapshot... if ((NO_ERROR == ret) && (mCameraAdapter->getState() == CameraAdapter::VIDEO_STATE)) { // enable post view frames if not already enabled so we can internally // save snapshot frames for generating thumbnail if ((mMsgEnabled & CAMERA_MSG_POSTVIEW_FRAME) == 0 ) { mAppCallbackNotifier->enableMsgType(CAMERA_MSG_POSTVIEW_FRAME); } } if ( (NO_ERROR == ret) && (NULL != mCameraAdapter) ) { if ( NO_ERROR == ret ) ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, ( int ) &frame, bufferCount); if ( NO_ERROR != ret ) { CAMHAL_LOGEB( "CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x" , ret); } } if ( NO_ERROR == ret ) { mParameters.getPictureSize(( int * ) &frame.mWidth, ( int * ) &frame.mHeight); // 分配buffer ret = allocImageBufs(frame.mWidth, frame.mHeight, frame.mLength, mParameters.getPictureFormat(), bufferCount); if ( NO_ERROR != ret ) { CAMHAL_LOGEB( "allocImageBufs returned error 0x%x" , ret); } } if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) { desc.mBuffers = mImageBufs; desc.mOffsets = mImageOffsets; desc.mFd = mImageFd; desc.mLength = mImageLength; desc.mCount = ( size_t ) bufferCount; desc.mMaxQueueable = ( size_t ) bufferCount; ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE, ( int ) &desc); } } if ( ( NO_ERROR == ret ) && ( NULL != mCameraAdapter ) ) { # if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS //pass capture timestamp along with the camera adapter command ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE, ( int ) &mStartCapture); # else ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE); #endif } return ret; } |
经过BaseCameraAdapter(这个当中的takePicture实现只是Stub)会到
status_t OMXCameraAdapter::takePicture(),然后会将该动作加入到Command队列当中去执行,最终实现在OMXCapture::startImageCapture()当中。
这里就会透过OMX_FillThisBuffer压入buffer到capture port,当capture完成之后会收到FillBufferDone这个callback,进入回调函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | OMX_ERRORTYPE OMXCameraAdapter::OMXCameraGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData ) { OMX_ERRORTYPE eError = OMX_ErrorUndefined; for ( int i = 0 ; i < 5 ; ++i ) { if ( i > 0 ) { // sleep for 100 ms before next attempt usleep( 100000 ); } // setup key parameters to send to Ducati during init OMX_CALLBACKTYPE oCallbacks; // initialize the callback handles // 注册callback oCallbacks.EventHandler = android::OMXCameraAdapterEventHandler; oCallbacks.EmptyBufferDone = android::OMXCameraAdapterEmptyBufferDone; oCallbacks.FillBufferDone = android::OMXCameraAdapterFillBufferDone; // get handle eError = OMX_GetHandle(handle, (OMX_STRING) "OMX.TI.DUCATI1.VIDEO.CAMERA" , pAppData, &oCallbacks); // 注意这个library,实际就是/path/to/aosp/hardware/ti/omap4xxx/domx/omx_proxy_component/omx_camera/src/omx_proxy_camera.c // 最终通过pRPCCtx->fd_omx = open("/dev/rpmsg-omx1", O_RDWR);跟底层交互 if ( eError == OMX_ErrorNone ) { return OMX_ErrorNone; } CAMHAL_LOGEB( "OMX_GetHandle() failed, error: 0x%x" , eError); } *handle = 0 ; return eError; } |
有了回调函数就会一直往上层传,最终就用户就得到了拍摄的照片数据。
CameraAdapter_Factory(size_t sensor_index)在OMXCameraAdapter当中。
另外TI Omap还有实现一套通过V4L2交互的方式,只是默认没有启用。
它是经过V4LCameraAdapter::UseBuffersPreview
最终会走向V4L2中去
而CameraAdapter_Factory()在V4LCameraAdapter当中。