Android 5.1 Camera 架构学习之Camera初始化
Android Camera 采用C/S架构,client 与server两个独立的线程之间(CameraService)使用Binder通信。
一 CameraService的注册。
1.手机开机后,会走init.rc流程,init.rc会启动MediaServer Service。
- service media /system/bin/mediaserver
- class main
- user root ####
- # google default ####
- # user media ####
- group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
- # google default ####
- # group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####
- ioprio rt 4
2.MediaServer的main函数位于frameworks/base/media/mediaserver/main_mediaserver.cpp中。
在Main_MediaServer.cpp的main函数中,CameraService完成了注册
- int main(int argc __unused, char** argv)
- {
- signal(SIGPIPE, SIG_IGN);
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "") > ) && (atoi(value) == );
- pid_t childPid;
- ..............................
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- #ifdef MTK_AOSP_ENHANCEMENT
- MemoryDumper::instantiate();
- #endif
- CameraService::instantiate();
- ......................................
3. instantiate的实现在CameraService的父类中,
- namespace android {
- template<typename SERVICE>
- class BinderService
- {
- public:
- static status_t publish(bool allowIsolated = false) {
- sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(
- String16(SERVICE::getServiceName()),
- new SERVICE(), allowIsolated);
- }
- static void publishAndJoinThreadPool(bool allowIsolated = false) {
- publish(allowIsolated);
- joinThreadPool();
- }
- static void instantiate() { publish(); }
- static status_t shutdown() { return NO_ERROR; }
- private:
- static void joinThreadPool() {
- sp<ProcessState> ps(ProcessState::self());
- ps->startThreadPool();
- ps->giveThreadPoolName();
- IPCThreadState::self()->joinThreadPool();
- }
- };
- }; // namespace android
可以发现在publish()函数中,CameraService完成服务的注册 。SERVICE是个模板,这里是注册CameraService,所以可用CameraService代替
return sm->addService(String16(CameraService::getServiceName()), new CameraService());
这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。
二 client如何连上server端,并打开camera模块
1.Client如何连接到server端。
我们从Camera.open()开始往framework进行分析,调用frameworks\base\core\java\android\hardware\Camera.java类的open方法 。
- public static Camera open() {
- ............................................
- return new Camera(cameraId);
- .............................................
- }
这里调用了Camera的构造函数,在构造函数中调用了cameraInitVersion
- private int cameraInitVersion(int cameraId, int halVersion) {
- ..................................................
- return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
- }
此后进入JNI层android_hardware_camera.cpp
- // connect to camera service
- static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
- {
- .......................
- camera = Camera::connect(cameraId, clientName,
- Camera::USE_CALLING_UID);
- ......................
- sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
- ...........................
- camera->setListener(context);
- ..........................
- }
JNI函数里面,我们找到Camera C/S架构的客户端了(即红色加粗的那个Camera),它调用connect函数向服务端发送连接请求。JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息
- sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
- int clientUid)
- {
- return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
- }
- template <typename TCam, typename TCamTraits>
- sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
- const String16& clientPackageName,
- int clientUid)
- {
- ALOGV("%s: connect", __FUNCTION__);
- sp<TCam> c = new TCam(cameraId);
- sp<TCamCallbacks> cl = c;
- status_t status = NO_ERROR;
- const sp<ICameraService>& cs = getCameraService();
- if (cs != ) {
- TCamConnectService fnConnectService = TCamTraits::fnConnectService;
- status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- /*out*/ c->mCamera);
- }
- if (status == OK && c->mCamera != ) {
- c->mCamera->asBinder()->linkToDeath(c);
- c->mStatus = NO_ERROR;
- } else {
- ALOGW("An error occurred while connecting to camera: %d", cameraId);
- c.clear();
- }
- return c;
- }
- // establish binder interface to camera service
- template <typename TCam, typename TCamTraits>
- const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
- {
- Mutex::Autolock _l(gLock);
- if (gCameraService.get() == ) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16(kCameraServiceName));
- if (binder != ) {
- break;
- }
- ALOGW("CameraService not published, waiting...");
- usleep(kCameraServicePollDelay);
- } while(true);
- if (gDeathNotifier == NULL) {
- gDeathNotifier = new DeathNotifier();
- }
- binder->linkToDeath(gDeathNotifier);
- gCameraService = interface_cast<ICameraService>(binder);
- }
- ALOGE_IF(gCameraService == , "no CameraService!?");
- return gCameraService;
- }
此处终于获得CameraService实例了,该CameraService实例是通过binder获取的。
再来看fnConnectService是什么,
在Camera.cpp中,有
- CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
- &ICameraService::connect;
这样也就是说fnConnectService就是使用CameraService调用connect,从这里开始,终于从进入了服务端的流程:
- status_t CameraService::connect(
- const sp<ICameraClient>& cameraClient,
- int cameraId,
- const String16& clientPackageName,
- int clientUid,
- /*out*/
- sp<ICamera>& device) {
- .........................
- status_t status = validateConnect(cameraId, /*inout*/clientUid);
- ..................................
- if (!canConnectUnsafe(cameraId, clientPackageName,
- cameraClient->asBinder(),
- /*out*/clientTmp)) {
- return -EBUSY;
- }
- status = connectHelperLocked(/*out*/client,
- cameraClient,
- cameraId,
- clientPackageName,
- clientUid,
- callingPid);
device = client;
- return OK;
- }
- status_t CameraService::connectHelperLocked(
- /*out*/
- sp<Client>& client,
- /*in*/
- const sp<ICameraClient>& cameraClient,
- int cameraId,
- const String16& clientPackageName,
- int clientUid,
- int callingPid,
- int halVersion,
- bool legacyMode) {
- ....................................
- client = new CameraClient(this, cameraClient,
- clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid(), legacyMode);
- ....................................
status_t status = connectFinishUnsafe(client, client->getRemote());
............................................- }
在connectHelpLocked,CameraService返回一个其实是它内部类的client——CameraClient。(注意此client是CameraService内部的CameraClient,不是Camera客户端),此client还赋值给了device,而这个device,就是在客户端CameraBase.cpp中c->mCamera,
- status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- /*out*/ c->mCamera);
而这个c->mCamera就是每一次客户端Camera.cpp中调用一些函数(如preview/takepicture)时的mCamera,这样每一次客户端调用preview/takepicture,就直接调用的是CameraClient中的相关函数。这样就真正建立了客户端和服务端的关系。如Camera.cpp中的startPreview
- // start preview mode
- status_t Camera::startPreview()
- {
- ALOGV("startPreview");
- sp <ICamera> c = mCamera;
- if (c == ) return NO_INIT;
- return c->startPreview();
- }
其实直接就会调用到CameraService中CameraClient.cpp中
- // start preview mode
- status_t CameraClient::startPreview() {
- LOG1("startPreview (pid %d)", getCallingPid());
- return startCameraMode(CAMERA_PREVIEW_MODE);
- }
2.service端(其实就是CameraClient)的初始化和运行过程。
刚才我们知道,camera客户端与服务端的调用关系,就是camera.cpp中的函数,对应到CameraClient中的函数。下面我们再看看CameraClient的初始化过程。
在connectFinishUnsafe中,
- status_t status = client->initialize(mModule);
我们再来看CameraClient类的initialize函数
- status_t CameraClient::initialize(camera_module_t *module) {
- int callingPid = getCallingPid();
- status_t res;
- mHardware = new CameraHardwareInterface(camera_device_name);
- res = mHardware->initialize(&module->common);
- }
CameraClient的初始化就是:先实例化Camera Hal接口 CameraHardwareInterface,CameraHardwareInterface调用initialize()进入HAL层打开Camera底层驱动
- status_t initialize(hw_module_t *module)
- {
- ALOGI("Opening camera %s", mName.string());
- camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
- camera_info info;
- status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
- if (res != OK) return res;
- int rc = OK;
- if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
- info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
- // Open higher version camera device as HAL1.0 device.
- rc = cameraModule->open_legacy(module, mName.string(),
- CAMERA_DEVICE_API_VERSION_1_0,
- (hw_device_t **)&mDevice);
- } else {
- rc = CameraService::filterOpenErrorCode(module->methods->open(
- module, mName.string(), (hw_device_t **)&mDevice));
- }
- if (rc != OK) {
- ALOGE("Could not open camera %s: %d", mName.string(), rc);
- return rc;
- }
- initHalPreviewWindow();
- return rc;
- }
hardware->initialize(&mModule->common)中mModule模块是一个结构体camera_module_t,他是怎么初始化的呢?我们发现CameraService里面有个函数
- void CameraService::onFirstRef()
- {
- BnCameraService::onFirstRef();
- if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
- (const hw_module_t **)&mModule) < ) {
- LOGE("Could not load camera HAL module");
- mNumberOfCameras = ;
- }
- }
了解HAL层的都知道hw_get_module函数就是用来获取模块的Hal stub,这里通过CAMERA_HARDWARE_MODULE_ID 获取Camera Hal层的代理stub,并赋值给mModule,后面就可通过操作mModule完成对Camera模块的控制。那么onFirstRef()函数又是何时调用的?
onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时调用。就是当 有sp包装的类初始化的时候调用,那么camera是何时调用的呢?可以发现在
客户端发起连接时候
sp Camera::connect(int cameraId)
{
LOGV("connect");
sp c = new Camera();
const sp& cs = getCameraService();
}
这个时候初始化了一个CameraService实例,且用Sp包装,这个时候sp将新增计数,相应的CameraService实例里面onFirstRef()函数完成调用。
CameraService::connect()即实例化CameraClient并打开驱动,返回CameraClient的时候,就表明客户端和服务端连接建立。Camera完成初始化。
总结:Camera的初始化流程简单的说就是:
->先是系统注册CameraService的服务
->AP层调用Camera.open()
->Camera.java调用JNI native_setup()
->JNI层调用 android_hardware_Camera_native_setup
-> HAL 客户端(Camera.cpp)调用connect与服务端(CameraService.cpp)连接,并得到CameraService中的CameraClient的一个实例
->服务端CameraClient的初始化,实例化Camera Hal接口 CameraHardwareInterface
->CameraHardwareInterface 打开Camera驱动,初始化完毕
最终的结果就是客户端会得到一个服务端CameraService中的CameraClient的一个实例,客户端的每一个函数操作其实最终都是调用CameraClient的函数
参考文档:
Android 4.0 Camera架构分析之Camera初始化 http://blog.csdn.net/dnfchan/article/details/7594590
Android 5.1 Camera Framework源码
Android 5.1 Camera 架构学习之Camera初始化的更多相关文章
- Android 4.0 Camera架构分析之Camera初始化
Android Camera 采用C/S架构,client 与server两个独立的线程之间使用Binder通信,这已经是众所周知的了.这里将介绍Camera从设备开机,到进入相机应用是如何完成初始化 ...
- sc7731 Android 5.1 Camera 学习之一Camera 两个对象
众所周知,在Android中Camera采用了C/S架构,其中Camera server 与 Camera client之间通过Android Binder IPC机制进行通信.在Camera实现的框 ...
- Android 的Camera架构介绍
http://java-admin.iteye.com/blog/452464 第一部分 Camera概述Android的Camera包含取景器(viewfinder)和拍摄照片的功能.目前And ...
- Andriod4.2 Camera 架构与实现
1.Camera架构包括客户端和服务端,他们之间的通信采用Binder机制实现. Camera的实现主要包括本地代码和Java代码两个层次: Camera本地框架: frameworks/native ...
- Android4.0 Camera架构初始化流程【转】
本文转载自:http://blog.chinaunix.net/uid-2630593-id-3307176.html Android Camera 采用C/S架构,client 与server两个独 ...
- 一样的Android,不一样的学习
这几年,Android开始慢慢流行起来,很多项目也开始涉及这部分内容,所以学习Android也就变的很有意义了. 学什么 学习Android应该学什么,很多人有不同的见解.一般程序员可能只是学习And ...
- ZT Android4.2蓝牙基础架构学习
Android4.2蓝牙基础架构学习 分类: Jellybean Bluetooth Bluetooth 2013-10-13 23:58 863人阅读 评论(3) 收藏 举报 androidblue ...
- MVP架构学习
MVP架构学习 M:数据层(数据库,文件,网络等...) V:UI层(Activity,Fragment,View以及子类,Adapter以及子类) P:中介,关联UI层和数据层,因为V和M是相互看不 ...
- Android开发-浅谈架构(二)
写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...
随机推荐
- window.open()提交POST数据
window.open(URL,name,specs,replace) > Details 我们一般都是通过window.open(url, name, specs)以GET方式让浏览器打开 ...
- java 属性
//非静态类 不能定义静态属性/方法/静态类, 可以定义静态常量属性. public class A{ public class B{ public static String _str; //❌, ...
- NOIP[2015] 运输计划
传送门 题目描述 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球 ...
- 反射-b
Class pkClass=NSClassFromString(@"PKAddPassesViewController"); if (pkClass) { NS ...
- SpEL快速入门
Spring表达式语言(简称SpEL)是一种鱼JSP2 EL功能类似的变道时语言,它可以在运行时查询和操作对象图.与JSP 2的EL相比,SpEL功能更加强大,它甚至支持方法的调用和基本字符串模板. ...
- WINDOWS自启动程序的10大隐身之所
Windows启动时通常会有一大堆程序自动启动.不要以为管好了“开始→程序→启动”菜单就万事大吉,实际上,在Windows XP/2K中,让Windows自动启动程序的办法很多,下文告诉你最重要的两个 ...
- XJOI——NOIP2015提高组模拟题19-day1——观光旅行
http://www.hzxjhs.com:83/contest/493/problem/3 [题目大意] 给定一个有n(n<=500000)个点,m(1<=500000)条边的无向图.给 ...
- CSS伪元素before和after
今天发现很多国外的网站和框架设计都用到了before和after,之前使用的比较少,今天试了下觉得还是很有意思的~ 说明 1. :before 和 :after将在内容元素的前后插入额外的元素::be ...
- 标准简单SP模板(sql server)
CREATE Procedure eSP_ChangeStart --eSP_ChangeStart 64 @ID int, Output As Declare ), @ID_Max int Begi ...
- ubuntu14.04 制作U盘启动文件
1.制作U盘启动文件 网上搜索:U盘安装Ubuntu 12.10 图文教程(ultraiso) http://www.jb51.net/os/94398.html 2. 重启,按Del(或F2)进BI ...