camera server的启动过程

1,camera service 的启动过程:

/frameworks/av/camera/cameraserver/ 

//main_cameraserver.cpp
#define LOG_TAG "cameraserver"
//#define LOG_NDEBUG 0

// from LOCAL_C_INCLUDES
#include "CameraService.h"

using namespace android;

int main(int argc __unused, char** argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("ServiceManager: %p", sm.get());
    CameraService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}
可是我们到CameraService文件里面却找不到instantiate()这个函数,它在哪?继续追到它的一个父类BinderService,
//CameraService.h
class CameraService :
    public BinderService<CameraService>,
    public BnCameraService
{
    class Client;
    friend class BinderService<CameraService>;
public:
    static char const* getServiceName() { return "media.camera"; }
    .....

    .....

}

从以上定义可以看出CameraService 继承于BinderService,所以CameraService::instantiate(); 其实是调用BinderService中的instantiate。

 BinderService的定义在frameworks/av/base/include/binder/BinderService.h中

扫描二维码关注公众号,回复: 3670901 查看本文章

// ---------------------------------------------------------------------------
namespace Android {

template<typename SERVICE>
class BinderService
{
public:
    static status_t publish() {
        sp<IServiceManager> sm(defaultServiceManager());
       return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
    }
    static void publishAndJoinThreadPool() {
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }

    static void instantiate() { publish(); }

    static status_t shutdown() {
        return NO_ERROR;
    }
};

}; // namespace android

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

template<typename SERVICE>
这表示SERVICE是个模板,这里是注册CameraService,所以可以用CameraService代替
return sm->addService(String16(CameraService::getServiceName()), new CameraService());
这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。


//cameraserver.rc
service cameraserver /system/bin/cameraserver
    class main
    user cameraserver
    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks
也就是说只要加载了cameraserver.rc文件,服务就开始启动了,
就会往main_cameraserer.cpp的入口函数中执行,因为mk文件中定义了这个模块为cameraserver

//Android.mk
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    main_cameraserver.cpp//源文件

LOCAL_SHARED_LIBRARIES := \//依赖库
    libcameraservice \
    libcutils \
    libutils \
    libbinder \
    libcamera_client

LOCAL_MODULE:= cameraserver//模块名
LOCAL_32_BIT_ONLY := true//只支持32位

LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter//一些编译条件,N版本在编译这一块也作出了很大的改动,有机会再研究下

LOCAL_INIT_RC := cameraserver.rc

include $(BUILD_EXECUTABLE)//执行文件


那么谁来调用cameraserver.rc?
首先要看这个文件编译出来放到手机的那个位置。

/build/core/base_rules.mk

# Rule to install the module's companion init.rc.
my_init_rc := $(LOCAL_INIT_RC_$(my_32_64_bit_suffix))
my_init_rc_src :=
my_init_rc_installed :=
ifndef my_init_rc
my_init_rc := $(LOCAL_INIT_RC)
# Make sure we don't define the rule twice in multilib module.
LOCAL_INIT_RC :=
endif
ifdef my_init_rc
my_init_rc_src := $(LOCAL_PATH)/$(my_init_rc)
########安装位置定义
my_init_rc_installed := $(TARGET_OUT$(partition_tag)_ETC)/init/$(notdir $(my_init_rc_src))
$(my_init_rc_installed) : $(my_init_rc_src) | $(ACP)
    @echo "Install: $@"
    $(copy-file-to-new-target)

$(my_register_name) : $(my_init_rc_installed)

大致可以看出一些端倪,应该是放在xxx/etc/init目录下,这个xxx根据什么看判断,partition_tag变量
ifdef LOCAL_IS_HOST_MODULE
    partition_tag :=
  else
  ifeq (true,$(LOCAL_PROPRIETARY_MODULE))
    partition_tag := _VENDOR
  else ifeq (true,$(LOCAL_OEM_MODULE))
    partition_tag := _OEM
  else ifeq (true,$(LOCAL_ODM_MODULE))
    partition_tag := _ODM
  else
    # The definition of should-install-to-system will be different depending
    # on which goal (e.g., sdk or just droid) is being built.
    partition_tag := $(if $(call should-install-to-system,$(my_module_tags)),,_DATA)
  endif

cameraserver应该是系统所有的,不是oem或者odm特有,存放在system/etc/init目录下。
  
  接下面看看这个文件 
/system/core/init/readme.txt

One may specify paths in the mount_all command line to have it import
.rc files at the specified paths instead of the default ones listed above.
This is primarily for supporting factory mode and other non-standard boot
modes.  The three default paths should be used for the normal boot process.

The intention of these directories is as follows
   1) /system/etc/init/ is for core system items such as
      SurfaceFlinger, MediaService, and logcatd.
   2) /vendor/etc/init/ is for SoC vendor items such as actions or
      daemons needed for core SoC functionality.
   3) /odm/etc/init/ is for device manufacturer items such as
      actions or daemons needed for motion sensor or other peripheral
      functionality.
显然是在执行“mount_all“的时候,CameraServer启动 ~ ,找到启动的位置,这一点和之前的版本是有很大差别的

2,client到service的连接

Clinet端

看看客户端的connect函数有什么? connenct()函数的实现在libcamera_client.so中实现。它的源码在以下路径中:frameworks/av/camera/Camera.cpp

sp<Camera> Camera::connect(int cameraId)
{
    LOGV("connect");
    sp<Camera> c = new Camera();
    const sp<ICameraService>& cs = getCameraService();//获取CameraService实例
    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;
}

其中通过const sp<ICameraService>& cs =getCameraService(); 获取CameraService实例,进入getCameraService( )中。

getCameraService( )源码文件如下:frameworks/av/camera/Camera.cpp

// establish binder interface to camera service

const sp<ICameraService>& Camera::getCameraService()
{
    Mutex::Autolock _l(mLock);
    if (mCameraService.get() == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        ....................
        binder->linkToDeath(mDeathNotifier);
        mCameraService = interface_cast<ICameraService>(binder);
    }
    LOGE_IF(mCameraService==0, "no CameraService!?");
    return mCameraService;
}
CameraService实例通过binder获取的,mCameraService即为CameraService的实例。

service端

service端的实现在库libcameraservice.so中。

回到sp<Camera> Camera::connect(int cameraId)中

c->mCamera = cs->connect(c, cameraId);
即:执行service的connect()函数,并且返回ICamera对象,赋值给Camera的mCamera,服务端connect()返回的是他内部类的一个实例。

service的connect()函数定义库文件libcameraservice.so中实现。

connect( )源码路径:frameworks/av/services/camera/libcameraservice/CameraService.cpp

sp<ICamera> CameraService::connect(
        const sp<ICameraClient>& cameraClient, int cameraId) {
    int callingPid = getCallingPid();
    sp<CameraHardwareInterface> hardware = NULL;
    ....................

    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驱动。最后new Client()返回给Client端。

3,HAL层

在Service端通过调用initialize()进入HAL层打开Camear驱动。initialize()的实现在CameraHardwareInterface中,其源码如下:

frameworks/av/services/camera/libcameraservice/CameraHardwareInterface.h

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->method->open()方法真正打开Camera设备,其中module是由它的调用者(serivce端:hardware->initialize(&mModule->common) )传过来的参数。该module的定义在以下路径:frameworks/av/services/camera/libcameraservice/CameraHardwareInterface.h

class CameraService :
    public BinderService<CameraService>,
    public BnCameraService
{

    class Client : public BnCamera
    {
    public:
        ......

    private:

        .....

    };

    camera_module_t *mModule;

};

此处还必须找到camera_module_t 的定义,以更好的理解整个运行流程,通过追根溯源找到了camera_module_t 定义,

camera_module_t的定义在以下路径:hardware/av/include/hardware/camera_common.h中,定义如下

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;
其中包含get_number_of_cameras方法和get_camera_info方法用于获取camera info

另外hw_module_t common;这个选项十分重要,此处应重点关注,因为是使用hw_module_t结构体中的open()方法打开设备文件的

继续找到hw_module_t 结构体的定义。在以下路径:hardware/libhardware/include/hardware/hardware.h,代码如下:

struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_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.
 */
typedef struct hw_module_t {
    ......................
    /** Modules methods */
    struct hw_module_methods_t* methods;
     ......................
    
} hw_module_t;
 

同样,找到hw_module_methods_t这个结构体的定义,代码如下:

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
} hw_module_methods_t;

hw_module_methods_t 结构体中只有open()一个方法,用于打开camera driver,实现与硬件层的交互。

open()是一个函数指针,对open()赋值的代码如下:/hardware/qcom/camera/QualcommCamera.cpp

static hw_module_methods_t camera_module_methods = {

open:camera_device_open,

};

其中camera_device_open()函数调用流程如下:

上图可知,在HAL层的module->methods->open(module, mName.string(), (hw_device_t **)&mDevice)回调,最终会调用到函数mm_camera__epen()。

int32_t mm_camera_open(mm_camera_obj_t *my_obj,  mm_camera_op_mode_type_t  op_mode)

{
      .......................................
        snprintf(dev_name, sizeof(dev_name), "/dev/%s", m_camera_util_get_dev_name(my_obj));
        do{
                n_try--;
                my_obj->ctrl_fd  = open(dev_name,O_RDWR | O_NONBLOCK);
            ...................
        }while(n_try>0);

        ....................
        return rc;
}

这个将调用系统调用open()的方法,打开设备节点dev/video0(后置相机),/dev/video2(前置相机),这个顺序是和内核在启动的是和
video的注册顺序相关的。

注意:这里的系统调用open()函数是应用层的,它最终对应内核层(驱动)的open函数为msm_open(),如下:

/kernel/drivers/media/video/msm/msm.c

static struct v4l2_file_operations g_msm_fops = {
     .owner   = THIS_MODULE,
     .open    = msm_open,
    .poll    = msm_poll,
    .mmap    = msm_mmap,
    .release = msm_close,
    .ioctl      = video_ioctl2,
};

msm_open()具体分析见第6节驱动层。

回到前面,设备节点dev/video0(后置相机),/dev/video2(前置相机)这个节点是在哪儿注册的呢?

4.驱动层

该节对摄像头驱动层进行分析,以高通平台为例。

/dev/目录下的摄像头注册是由驱动程序完成,在函数msm_cam_dev_ini( )中实现,源码在如下文件中:/kernel/drivers/media/video/msm/msm.c   

其中,video_reister_device()完成摄像头节点的注册。

pvdev->ops = &g_msm_fops,则是向应用层提供打开摄像头Sensor的接口函数。

源码如下:/kernel/drivers/media/video/msm/msm.c

HAL层的open方法最终会调用的内核驱动层的msm_open()函数。

msm_open()源码文件为:/kernel/drivers/media/video/msm/msm.c

static int msm_open(struct file *f)
{
    ......................

    /* Now we really have to activate the camera */
    D("%s: call mctl_open\n", __func__);
   rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);//打开相机
   if (rc < 0) {
       pr_err("%s: HW open failed rc = 0x%x\n",   __func__, rc);
       goto mctl_open_failed;
   }
   pmctl->pcam_ptr = pcam;
   ........................
   if (pcam->use_count == 1) {
       rc =msm_send_open_server(pcam);//后面进行分析
      ...............
   } 
   ........................
}

msm_send_openserver()在后面进行分析。

msm_open()调用mctl_open(),mctl_open()是真正打开相机的地方,当时它同样是一个函数指针,对该函数指针进行赋值在文件/kernel/drivers/media/video/msm/msm_mctl.c中,如下:

/* this function plug in the implementation of a v4l2_subdev */

int msm_mctl_init(struct msm_cam_v4l2_device *pcam)
{

    ...........

    /* init module operations*/

    pmctl->mctl_open = msm_mctl_open;

pmctl->mctl_cmd = msm_mctl_cmd;

pmctl->mctl_release = msm_mctl_release;

...........

}

msm_mctl_open()的源码在如下文件中:/kernel/drivers/media/msm/msm_mctl.c

static int msm_mctl_open(struct msm_cam_media_controller *p_mctl, const char *const apps_id)

{

..............................

/* then sensor - move sub dev later */

rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);

...............................

}


 

msm_mctl_open()函数调用v412_subdev_call( ),该函数中的s_power又是一个函数指针,通过回调调用函数msm_sensor_power(),对该函数指针的赋值操作的源码如下:/kernel/drivers/media/video/msm/sensor/s5k4e1_v4l2.c

static struct v4l2_subdev_core_ops s5k4e1_subdev_core_ops = {

.ioctl = msm_sensor_subdev_ioctl,

.s_power = msm_sensor_power,

};
 


 

通过调用msm_sensor_power( )完成Camera的Sensor上电操作。

但是,此时camera并没有进行初始化,只是上电并读取ID而已,那么sensor又是在什么时候进行初始化的呢?继续进行分析............

在之前打开了/dev/video0 的节点,在 msm_open( ) 函数中,最后会去调用msm_send_open_server( ),这个函数会去唤醒我们用户空间的config 线程,msm_send_open_server( )源码如下:/kernel/drivers/media/video/msm/msm.c

/*send open command to server*/
static int msm_send_open_server(struct msm_cam_v4l2_device *pcam)
{
     int rc = 0;
      struct msm_ctrl_cmd ctrlcmd;
     D("%s qid %d\n", __func__, pcam->server_queue_idx);
     ctrlcmd.type            = MSM_V4L2_OPEN;
     ctrlcmd.timeout_ms = 10000;
     ctrlcmd.length         = strnlen(g_server_dev.config_info.config_dev_name[0],MAX_DEV_NAME_LEN)+1;
     ctrlcmd.value        = (char *)g_server_dev.config_info.config_dev_name[0];
     ctrlcmd.vnode_id = pcam->vnode_id;
     ctrlcmd.queue_idx = pcam->server_queue_idx;
     ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
     /* send command to config thread in usersspace, and get return value */
     rc = msm_server_control(&g_server_dev, &ctrlcmd);
     return rc;
}

在这个函数中我们需要注意这个timeout的时间限制,它是要求我们的请求必须在10s内完成,否则config线程就会超时,从而导致相机将无法使用,只能通过重启来修复。

msm_server_control( )函数会向用户空间的config线程发送指令MSM_V4L2_OPEN(即代码中的ctrlcmd.type = SM_V4L2_OPEN),这是用户空间的线程会被激活,调用用户空间的函数qcamsvr_process_server_node_event( ),源码如下:\vendor\qcom\proprietary\mm-camera\server\core\qcamsvr.c

static int qcamsvr_process_server_node_event( struct config_thread_arguments *config_arg,

                            struct msm_mctl_node_info *mctl_node_info, gesture_info_t *p_gesture_info)
{
    ..................................
    if (ctrl->type == MSM_V4L2_OPEN) {
    CDBG("MSM_V4L2_OPEN is received\n");
    snprintf(config_arg->config_name, MAX_DEV_NAME_LEN, "%s",(char  *)event_data.isp_data.ctrl.value);
    CDBG("%s: OPEN %s\n", __func__, config_arg->config_name);

    .........................
       if ((tmp_mctl_struct->handle = create_v4l2_conf_thread(config_arg)) == NULL) {

           CDBG_ERROR("%s:  create_v4l2_conf_thread  failed",  __func__);

           ctrl->status  =  CAM_CTRL_FAILED;
           v4l2_ioctl.ioctl_ptr  =  ctrl;
           goto  error_config_thread_creation;
        }
      .........................
    }
    ....................................
}

从以上代码可知,用户空间在这个地方收到了我们内核的请求后,接着会调用create_v4l2_conf_thread( )创建用户空间 config 线程。

现整个过程又回到用户空间..............

5.又见用户空间

在/dev/目录下有个设备节点文件./msm_camera/config0,即/dev/msm_camera/config0,这个文件的主要作用是打开它后,用它来完成Sensor的初始化。对于该节点主要关心两个问题:

①什么时候被创建?

    在函数msm_camera_probe(),源码路径为:/kernel/drivers/media/msm/msm.c,主要是通过如下两条语句进行创建:

msm_class = class_create(THIS_MODULE, "msm_camera");

 device_config = device_create(msm_class, NULL, devno,NULL, "%s%d",device_name, dev_num);//其中device_name = "config",dev_num = 0

②什么时候打开?具体分析见下。

由上面的分析可知,当内核驱动向用户空间发送SM_V4L2_OPEN请求,调用create_v4l2_conf_thread( )函数创建用户空间 config 线程,该函数的源码如下:\vendor\qcom\proprietary\mm-camera\server\core\mctl\mctl.c

void *create_v4l2_conf_thread(struct config_thread_arguments* arg)
{
    .................................
    rc = pthread_create(&pme->cam_mctl_thread_id, NULL, cam_mctl_thread, pme);
   ...........................
}

它创建一个线程,然后该线程执行的函数为cam_mctl_thread( ),然后它又调用mctl_init( ),即cam_mctl_thread( ) -----> mctl_init( )。mctl_init()源码如下:

/vendor/qcom/proprietary/mm-camera/server/core/mctl/mctl.c

int mctl_init(m_ctrl_t* pme)
{
    ..........................
    CDBG("%s: dev name is %s\n", __func__, config_device);
    p_cfg_ctrl->camfd = open(config_device, O_RDWR);
    ..............................
    mctl_proc_init_ops(p_cfg_ctrl);
   s_comp_ops = &p_cfg_ctrl->comp_ops[MCTL_COMPID_SENSOR];
   if(!s_comp_ops->handle) {        

       sensor_init_data_t sensor_init_data;
       tmp_handle = sensor_client_open(s_comp_ops);
       ...........................
    }
   ...................................
   if (s_comp_ops->init) {

        rc  =s_comp_ops->init(s_comp_ops->handle, &p_cfg_ctrl->ops, &sensor_init_data);
        .......................

    }

   ....................................

}

open()函数打开/dev/camera/config0节点后,随后调用sensor_client_open()函数,最有调用s_comp_ops->init()函数, 该函数利用config0节点去完成sensor的初始化工作。sensor_client_open()完成函数指针_comp_ops->init()的赋值,源码如下:

/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor_interface.c

uint32_t sensor_client_open(module_ops_t *ops)
{
    .....................

    ops->handle = (uint32_t)sensor_client->handle;

   ops->init = sensor_client_init;

    ops->set_params = sensor_client_set_params;

    ops->get_params = sensor_client_get_params;

    ops->process = NULL;

    ops->abort  =  NULL;

    ops->destroy= sensor_client_destroy;

    ............................

}

因此,调用s_comp_ops->init(),实际是调用的函数sensor_client_init()函数,然后该函数会调用到sensor_init(),

即s_comp_ops->init() --> sensor_client_init() ---> sensor_init()。sensor_init( )的源码如下:

/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor.c

int8_t sensor_init(sensor_ctrl_t *sctrl)
{
    struct msm_camsensor_info sinfo;
    ......................
    sensor_common_parm_init(sctrl);
    rc = ioctl(sctrl->sfd, MSM_CAM_IOCTL_GET_SENSOR_INFO, &sinfo);
    ........................
   sctrl->start = &sensors[cnt];
   rc = sctrl->start->s_start(sctrl);
   if (sctrl->sensor.out_data.sensor_output.output_format == SENSOR_BAYER) {
        rc = sensor_load_chromatix(sctrl);
        ........................
   }
   ........................
}

在sensor_init()函数中,利用系统调用ioctl(),获取sensor的信息(包括sensor的类型yuv or raw,af enable ? 闪光灯类型,sensor名等)。

其中:rc = sctrl->start->s_start(sctrl);

s_start()会调用s5k4e1_process_start(),对于函数指针s_start()的赋值,是用过一个宏定义进行的,具体参照文件/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/sensor.c中的源码。

rc = sensor_load_chromatix(sctrl);

这条语句就会去加载我们的库文件了(仅仅针对RAW sensor)。

现分析函数s5k4e1_process_start(),源码如下:/vendor/qcom/proprietary/mm-camera/server/hardware/sensor/s5k4e1/s5k4e1_u.c

int8_t s5k4e1_process_start(void *ctrl)

{
   sensor_ctrl_t *sctrl = (sensor_ctrl_t *) ctrl;
   sctrl->fn_table = &s5k4e1_func_tbl;
   sctrl->sensor.inputformat = s5k4e1_inputformat;
   sctrl->sensor.crop_info = s5k4e1_cropinfo;
   sctrl->sensor.mode_res = s5k4e1_mode_res;
   sensor_util_get_output_info(sctrl);
   sctrl->sensor.op_mode = SENSOR_MODE_VIDEO;
   sctrl->sensor.out_data.sensor_output.connection_mode = SENSOR_MIPI_CSI;
   sctrl->sensor.out_data.sensor_output.output_format = SENSOR_BAYER;
   sctrl->sensor.out_data.sensor_output.raw_output = SENSOR_10_BIT_DIRECT;
   sctrl->sensor.out_data.aec_info.max_gain = 16.0;
   sctrl->sensor.out_data.aec_info.max_linecount = sctrl->sensor.output_info[sctrl->sensor.
   mode_res[SENSOR_MODE_PREVIEW]].frame_length_lines * 24;
   sctrl->sensor.snapshot_exp_wait_frames = 1;
   sctrl->sensor.out_data.lens_info.focal_length = 3.49;
   sctrl->sensor.out_data.lens_info.pix_size = 1.4;
   sctrl->sensor.out_data.lens_info.f_number = 2.2;
   sctrl->sensor.out_data.lens_info.total_f_dist = 1.97;
   sctrl->sensor.out_data.lens_info.hor_view_angle = 54.8;
   sctrl->sensor.out_data.lens_info.ver_view_angle = 42.5;
   sensor_util_config(sctrl);
    return TRUE;
}

其中:

sensor_util_get_output_info(sctrl);这条语句调用到内核获取长宽等

sensor_util_config(sctrl);这条语句调用到内核完成初始化

至此,整个摄像头open过程分析完成。

到此为止,很容易看出:

Android中Camera的调用流程可分为以下几个层次:
Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camera HAL->Camera Driver --> 通过消息内核驱动激活用户空间,完成Sensor初始化 ---> open完成

http://blog.csdn.net/unicornkylin/article/details/13293295

这部分内容来至于:

https://www.cnblogs.com/zzb-Dream-90Time/p/6524203.html

猜你喜欢

转载自blog.csdn.net/chaosxcc/article/details/83242348