本文转载自:http://blog.chinaunix.net/uid-2630593-id-3307176.html

Android Camera 采用C/S架构,client 与server两个独立的线程之间使用Binder通信,这已经是众所周知的了。这里将介绍Camera从设备开机,到进入相机应用是如何完成初始化工作的。

首先既然Camera是利用binder通信,它肯定要将它的service注册到ServiceManager里面,以备后续Client引用,那么这一步是在哪里进行的呢?细心的人会发现,在frameworks\base\media\mediaserver\Main_MediaServer.cpp下有个main函数,可以用来注册媒体服务。没错就是在这里,CameraService完成了服务的注册

int main(int argc, char** argv) { sp proc(ProcessState::self()); sp sm = defaultServiceManager(); LOGI("ServiceManager: %p", sm.get()); waitBeforeAdding( String16("media.audio_flinger") ); AudioFlinger::instantiate(); waitBeforeAdding( String16("media.player") ); MediaPlayerService::instantiate(); waitBeforeAdding( String16("media.camera") ); CameraService::instantiate(); waitBeforeAdding( String16("media.audio_policy") ); AudioPolicyService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); }

可是我们到CameraService文件里面却找不到instantiate()这个函数,它在哪?继续追到它的一个父类BinderService

static void instantiate() { publish(); }
static status_t publish() { sp sm(defaultServiceManager()); return sm->addService(String16(SERVICE::getServiceName()), new SERVICE()); }

可以发现在publish()函数中,CameraService完成服务的注册 。这里面有个SERVICE,源码中有说明

template
这表示SERVICE是个模板,这里是注册CameraService,所以可以用CameraService代替

return sm->addService(String16(CameraService::getServiceName()), new CameraService());
好了这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。

Main_MediaServer主函数由init.rc在启动是调用,所以在设备开机的时候Camera就会注册一个服务,用作binder通信。

service media /system/bin/mediaserver class main user media group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc ioprio rt 4

Binder服务已注册,那接下来就看看client如何连上server端,并打开camera模块。

咱们先从camera app的源码入手。在onCreate()函数中专门有一个open Camera的线程

public void onCreate(Bundle icicle) {

......

mCameraOpenThread.start();

}

再看看mCameraOpenThread

Thread mCameraOpenThread = new Thread(new Runnable() {
        public void run() {
            try {
                qcameraUtilProfile("open camera");
                mCameraDevice = Util.openCamera(Camera.this, mCameraId);
                qcameraUtilProfile("camera opended");
            } catch (CameraHardwareException e) {
                mOpenCameraFail = true;
            } catch (CameraDisabledException e) {
                mCameraDisabled = true;
            }
        }
    });

继续追Util.openCamera

return CameraHolder.instance().open(cameraId)

又来了个CameraHolder,该类用一个实例openCamera

public synchronized android.hardware.Camera open(int cameraId)
            throws CameraHardwareException {

mCameraDevice = android.hardware.Camera.open(cameraId);

return mCameraDevice;

}

在这里就开始进入framework层了,调用frameworks\base\core\java\android\hardware\Camera.java类的open方法 。

public static Camera open(){

return new Camera(i);

}

这里调用了Camera的构造函数,在看看构造函数

Camera(int cameraId){

native_setup(new WeakReference(this), cameraId)

}

好,终于来到JNI了

继续看camera的JNI文件android_hardware_camera.cpp

static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId)
{
    sp camera = Camera::connect(cameraId);

sp context = new JNICameraContext(env, weak_this, clazz, camera);
    camera->setListener(context);

}

JNI函数里面,我们找到Camera C/S架构的客户端了,它调用connect函数向服务器发送连接请求。JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息

看看客户端的connect函数有什么

sp Camera::connect(int cameraId)
{
    LOGV("connect");
    sp c = new Camera();
    const sp& cs = getCameraService();
    if (cs != 0) {
        c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        c.clear();
    }
    return c;
}

先看标红的第一句,通过getCameraService()函数获取一个Camera服务实例。

const sp& Camera::getCameraService()
{
    if (mCameraService.get() == 0) {
        sp sm = defaultServiceManager();
        sp binder;
        do {
            binder = sm->getService(String16("media.camera"));
            if (binder != 0)
                break;
            LOGW("CameraService not published, waiting...");
            usleep(500000); // 0.5 s
        } while(true);

mCameraService = interface_cast(binder);
    }
    LOGE_IF(mCameraService==0, "no CameraService!?");
    return mCameraService;
}

可以看出,该CameraService实例是通过binder获取的,由binder机制可以知道,该服务就是CameraService一个实例。

c->mCamera = cs->connect(c, cameraId);

然后执行服务端的connect()函数,并返回一个ICamera对象赋值给Camera 的mCamera, 服务端connect()返回的其实是它内部类client的一个实例。

sp CameraService::connect(){

hardware = new CameraHardwareInterface(camera_device_name);
    if (hardware->initialize(&mModule->common) != OK) {
        hardware.clear();
        return NULL;
    }

client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
    mClient[cameraId] = client;
    LOG1("CameraService::connect X");
    return client;

}

先实例化Camera Hal接口 hardware,hardware调用initialize()进入HAL层打开Camear驱动

status_t initialize(hw_module_t *module)
    {
        LOGI("Opening camera %s", mName.string());
        int rc = module->methods->open(module, mName.string(),
                                       (hw_device_t **)&mDevice);
        if (rc != OK) {
            LOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }

module->methods->open(module, mName.string(),
                                       (hw_device_t **)&mDevice)这一句作用就是打开Camera底层驱动

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) < 0
) {
        LOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }
 
}

了解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()返回client的时候,就表明客户端和服务端连接建立。Camera完成初始化,可以进行拍照和preview等动作。一个看似简单Camera初始化的过程,研究起来却也让人费劲啊。。。

下面是整个过程的时序图

 

Android4.0 Camera架构初始化流程【转】的更多相关文章

  1. Android 4.0 Camera架构分析之Camera初始化

    Android Camera 采用C/S架构,client 与server两个独立的线程之间使用Binder通信,这已经是众所周知的了.这里将介绍Camera从设备开机,到进入相机应用是如何完成初始化 ...

  2. [RK3288][Android6.0] Display驱动初始化流程小结【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/52584903 Platform: RK3288OS: Android 6.0Kernel: ...

  3. Android 5.1 Camera 架构学习之Camera初始化

    Android Camera 采用C/S架构,client 与server两个独立的线程之间(CameraService)使用Binder通信. 一 CameraService的注册. 1.手机开机后 ...

  4. 【8.0.0_r4】AMS架构与流程分析

    AMS主要用来管理应用程序的生命周期,以及其核心组件,包括Activity,Service,Provider,Broadcast,Task等 之前整体架构如下图(O上已经废弃) 新的架构比较直接,简化 ...

  5. 【开源】OSharp3.3框架解说系列(7.1):初始化流程概述

    OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...

  6. android4.0 FaceDetection笔记

    这几天研究了下andoid4.0.3的FaceDetection这里写一下大致的流程,方便日后查阅. 相关说明可以在这里找到: frameworks/base/docs/html/guide/topi ...

  7. Ubuntu12.04下载Android4.0.1源码全过程,附若干问题解决[转]

    学校里一直在做应用层开发,考虑到日后就业问题,这次决定研究源码和驱动,并进行编译.没想到就下载源码这一步折腾了我整整两天,期间遇到很多问题,哎,记录于此,希望日后再下源码的人不要再走无谓的弯路了.事实 ...

  8. Android 的Camera架构介绍

    http://java-admin.iteye.com/blog/452464   第一部分 Camera概述Android的Camera包含取景器(viewfinder)和拍摄照片的功能.目前And ...

  9. [2013.7.5新鲜出炉] Ubuntu12.04下载Android4.0.1源码全过程----------------折腾两天,终于下好,附若干问题解决

    本文转至 http://blog.csdn.net/yanzi1225627/article/details/9255457 下载源码这一步折腾了我整整两天,期间遇到很多问题,哎,记录于此,希望日后再 ...

随机推荐

  1. js中箭头函数 及 针对箭头函数this指向问题引出的单体模式

    ES6允许使用“箭头”(=>)定义函数 var f = a = > a //等同于 var f = function(a){ return a; } 如果箭头函数不需要参数或需要多个参数, ...

  2. Python 多列数据存储

    zip()函数 zip函数可以把多个列表相加成一个tuple(元组) a = [1,2,3,4] b = [11,22,33,44] c = [111,222,333,444] A = list(zi ...

  3. 剑指offer-包含min函数的栈-栈和队列-python

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)).   # -*- coding:utf-8 -*- class Solution: de ...

  4. iOS 设备尺寸以及图标尺寸

    iPhone 4和iPod Touch 4有一个新的特性:在屏幕尺寸不变的前提下,分辨率提升一倍(320 x 480 => 640 x 960).苹果将这个特性命名为Retina. 用苹果的话讲 ...

  5. MySQL索引优化(索引两表优化案例)

    建表SQL CREATE TABLE IF NOT EXISTS `class` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `card` INT ...

  6. Docker守护式容器的创建和登录

    创建守护式容器 如果对于一个需要长期运行的容器来说,我们可以创建一个守护式容器(后台运行的容器). 创建(-d)并运行(-i)守护式容器命令如下(容器名称不能重复): docker run -id - ...

  7. 为什么你不看好家教O2O

    伴随着科技的不断进步,大众创业的激情在不断的燃烧着,于是又很多的朋友会往家教这条路上走.就有了家教O2O的出现,很多的人都在抢占市场,可是,为什么你不看好家教O2O? 家教O2O虽然能够帮助附近的朋友 ...

  8. egretios包接微信/facebook登录

    ios包有了,现在需要登录,就先使用微信登录吧,后继加一个facebook登录. 根据我的理解,先预测一下应该是怎么回事吧. 首先应该是要去微信的公共平台注册一下,说我的应用是什么应用,要填写企业信息 ...

  9. Java并发——原子变量和原子操作

    很多情况下我们只是需要一个简单的.高效的.线程安全的递增递减方案.注意,这里有三个条件:简单,意味着程序员尽可能少的操作底层或者实现起来要比较容易:高效意味着耗用资源要少,程序处理速度要快:线程安全也 ...

  10. git如何将本地文件关联到远程服务器

    很多时候,当我们关联git服务器的时候,本地都有可能会有一些开发的东西需要同步上去.那怎么样设置同步呢!跟我来做,简易配置: git本地关联远程项目:      第一步:选择目录           ...