【Camera专题】Sprd-基于log的Camera流程分析1-【Open流程】

一、前言

天苍苍,野茫茫,风吹草低见牛羊!
高通的旗舰机项目基本搞定,就等6月底上市了,期望能卖得不错吧!
这半年做高通项目,学习到许多关于Camera的知识,当然还需要深入去学习!
不过,下半年要做展讯旗舰机器,又要开始踩展讯的坑!
前段时间写了一下Sprd的Camera流程分析,感觉之前写得不太详细,
因此,打算基于log分析源码,对整个架构更加深入的学习!

二、Open流程

1.整体架构

7163557-e133970465ec4cbb.png
架构

整体架构图可知,这个流程

APP层->Framework层->通过Binder机制与Service进程通信
->CameraService->通过JNI->调用到HAL层->Kernel层

这也是本文的分析思路!
PS:由于CameraService会在开机的时候就初始化,因此我们优先简单分析!

2.log分析-【开机第一次启动Camera:冷启动】

2.1 CameraService的启动-开机初始化
开机时,就会初始化CameraService,这里就是你可以看到的跟Camera相关的第一行log

  • 2.1.1 log


    7163557-6cd18b615655013c.png
    image.png
  • 2.1.2源码
    frameworks/av/services/camera/libcameraservice/CameraService.cpp

CameraService::CameraService()
    :mSoundRef(0), mModule(0)
{
    //这里就是我们开机时,打印的Cameralog,getpid获取进程号:223
    ALOGI("CameraService started (pid=%d)", getpid());
    gCameraService = this;

    for (size_t i = 0; i < MAX_CAMERAS; ++i) {
        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
    }    

    this->camera_device_status_change = android::camera_device_status_change;
}

开机时,CameraService就会启动,进行初始化,具体的细节就不去追究。
流程:
CameraService: CameraService started (pid=223)//进程号:223
CameraService: CameraService::onFirstRef //第一次启动,执行以下动作

  • 1.CameraService: Loaded "Sprd Camera HAL3" camera module //加载HAL3 module
  • 2.CameraService: setCameraFree cameraId=0和cameraId=1 //设置camera当前的状态
  • 3.CameraDeviceFactory::registerService(this) 注册服务
void CameraService::onFirstRef()
{
    LOG1("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 {
        //加载HAL3 module
        ALOGI("Loaded \"%s\" camera module", mModule->common.name);
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        //设置camera当前状态为空闲
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }

        if (mModule->common.module_api_version >=
                CAMERA_MODULE_API_VERSION_2_1) {
            mModule->set_callbacks(this);
        }

        getVendorTagOps();
        //注册Camera服务
        CameraDeviceFactory::registerService(this);
    }
}

这里为什么要设置camera的状态呢?

void CameraService::setCameraFree(int cameraId) {
    //写入0表示camera处于空闲状态  
    android_atomic_write(0, &mBusy[cameraId]);
    ALOGV("setCameraFree cameraId=%d", cameraId);
}
void CameraService::setCameraBusy(int cameraId) {
    //写入1表示camera处于繁忙状态
    android_atomic_write(1, &mBusy[cameraId]);
    ALOGV("setCameraBusy cameraId=%d", cameraId);
}

我们需要这个busy位的原因是一个新的CameraService::connect()请求
可能在前一个客户端析构函数尚未运行或正在运行时进入仍在运行。
如果前一个client(客户端)的最后一个强引用已经消失,
但是析构函数还没有完成,我们不应该允许new Client
因为我们需要等待前面的客户端首先销毁硬件。


因此:
CameraService: setCameraFree cameraId=1
CameraService: setCameraBusy cameraId=1
会成对出现,初始化的时候,会设置成free,
打开摄像头时,会设置成busy,
关闭摄像头时,状态又会设置成free。

另外:说一下 getNumberOfCameras()函数

7163557-4d2ef444cf5e0113.png

7163557-b67b7145041692a7.png

getNumberOfCameras=2表示的是系统支持前摄和后摄,
并不代表你的Android设备有2个摄像头,也许只有前摄,或者后摄!
也许你的系统还可能支持前副摄像、后副摄像
那么应该在** kCameraInfo数组**再添加2个

这里CameraService开机的初始化就简单分析完了
既然是开机,所以接下来第一次打开Camera属于冷启动
需要初始化很多东西,这就是为啥冷启动会慢的原因!

2.2 APP层 和 Framwork层

  • 2.2.1 log


    7163557-01e1c0d601c98fc1.png
  • 2.2.2 源码
    APP这一块,懂得一些基本知识,
    由于学的不够深,Framwork也没研究过,
    因此就不做深入分析,以免误人子弟。
    以上就是你能看到的log!
    最后这里可以看到调用到getSensorStaticInfo这个Hal层的方法!

2.3 Hal层

  • 2.3.1 log


    7163557-1b748e6c4d562bd1.png

getSensorStaticInfo函数主要用来读取Sensor的信息,看源码分析!
由于是开机第
一次启动时,调用getSensorStaticInfo失败了,why?

先打开后摄,因为没有后摄,所以获取信息失败了

后面又重新调用一次getSensorStaticInfo,然后获取到sensor info

然后打开前摄,有摄,能获取到sensor信息

  • 2.3.2 源码
    vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3Setting.cpp
int SprdCamera3Setting::getSensorStaticInfo(int32_t cameraId) {
    struct sensor_drv_context *sensor_cxt = NULL;
···省略源码
    //因为是开机第一次运行,这里肯定是失败的,不会跑进去
    if (alreadyGetSensorStaticInfo[cameraId] != 0) { 
        HAL_LOGI("already get sensor info");
        return 0;
    }    

    HAL_LOGI("E");//可以看到这个log打印了
···省略源码
    ret = sensor_open_common(sensor_cxt, cameraId, 0);
    if (ret) {
        //这里的log打印了,我们跟进sensor_open_common函数去看
        HAL_LOGE("open camera (%d) failed", cameraId);
        setLargestSensorSize(cameraId, default_sensor_max_sizes[cameraId].width,
                             default_sensor_max_sizes[cameraId].height);
        goto exit;
    }
···后面先这些省略不看
}

这里我们继续跟进sensor_open_common函数去看
vendor/sprd/modules/libcamera/sensor/sensor_drv_u.c
打开Camera的步骤
NOTE:when open camera,you should do the following steps.
步骤1.register all sensor for the following first open sensor.
第一次打开摄像头的时候,注册所有的sensor

步骤2.if first open sensor failed, identify module list to save sensor index.
如果第一次打开失败,重新identify 所有的sensor并保存起来
步骤3.try open sensor second time.
尝试重新打开sensor
步骤4.if 3 steps failed,sensor open failed.
如果步骤3失败了,那么sensor打开失败

来看源码:

cmr_int sensor_open_common(struct sensor_drv_context *sensor_cxt,
                           cmr_u32 sensor_id, cmr_uint is_autotest) {
    ATRACE_BEGIN(__FUNCTION__);
···
    //这条log打印了
    SENSOR_LOGI("0, start,id %d autotest %ld", sensor_id, is_autotest);

    /* init ctx, exif, load sensor file, open hw driver with sensor id.*/
    ret_val = sensor_context_init(sensor_cxt, sensor_id, is_autotest);
···
    /* create sensor process thread. */
    ret_val = sensor_create_ctrl_thread(sensor_cxt);
    /*这个函数会 打印 sns_drv_u: 1593, sensor_create_ctrl_thread: is_inited 0*/
···
    /* create the hw obj of kernel driver. */
···
    /*该函数 打印 hw_sensor: 107, hw_sensor_drv_create: sensor_id:0*/
    fd_sensor = hw_sensor_drv_create(&input_ptr, &hw_drv_handle);
     /*该函数会继续调用_hw_sensor_dev_init函数 */
    sensor_cxt->fd_sensor = fd_sensor;
    sensor_cxt->hw_drv_handle = hw_drv_handle;
    sensor_cxt->sensor_hw_handler = hw_drv_handle;

    /*load all the sensor ICs' info according the indexs stored in sensor idx file*/
    /*根据存储在sensor idx文件中的索引 加载传感器ICs的所有信息*/
    sensor_load_idx_inf_file(sensor_cxt);
    if (sensor_cxt->sensor_identified) {
        //这里调用sns_load_drv -> 里面继续调用sensor_get_match_info -> sensor_get_module_tab
        if (SENSOR_SUCCESS == sns_load_drv(sensor_cxt, SENSOR_MAIN)){
            sensor_num++;
        }
    if (SENSOR_SUCCESS == sns_load_drv(sensor_cxt, SENSOR_SUB)) {
            sensor_num++;
        }
···
        SENSOR_LOGI("1 is identify, register OK");
        /*first open sensor*/
        ret_val = sensor_open(sensor_cxt, sensor_id);
        if (ret_val != SENSOR_SUCCESS) {
            SENSOR_LOGI("first open sensor failed,start identify");
        }

    /* scan the devices in cfg list and find out the correct sensor driver */
    if ((!sensor_cxt->sensor_identified) || (ret_val != SENSOR_SUCCESS)) {
        sensor_num = 0;
        SENSOR_LOGI("register sensor fail, start identify");
        if (sensor_identify(sensor_cxt, SENSOR_MAIN))
            sensor_num++;
        if (sensor_identify(sensor_cxt, SENSOR_SUB))
            sensor_num++;
···
        /*再一次打开*/
        ret_val = sensor_open(sensor_cxt, sensor_id);
    }
    sensor_cxt->sensor_identified = SCI_TRUE;
    //保存识别到的摄像头信息,后续再打开摄像头,直接读idx文件即可
    sensor_save_idx_inf_file(sensor_cxt);
    sensor_rid_save_sensor_info(sensor_cxt);

···
    SENSOR_LOGI("total camera number %d", sensor_num);

init_exit:
    if (SENSOR_SUCCESS != ret_val) {
        //打开摄像头失败,删除相关资源
        sensor_destroy_ctrl_thread(sensor_cxt);
        hw_sensor_drv_delete(hw_drv_handle);
        sensor_cxt->hw_drv_handle = NULL;
        sensor_cxt->sensor_hw_handler = NULL;
    }
    return ret_val;
}

加了很多注释,就不在赘述。
根据源码,我们继续看具体的log


7163557-d24c9e507cef745f.png
第一段log
7163557-baf6c9484e58911a.png
第一段log续

这份log执行的就是步骤1和步骤2
步骤1.register all sensor for the following first open sensor.
第一次打开摄像头的时候,注册所有的sensor

步骤2.if first open sensor failed, identify module list to save sensor index.
如果第一次打开失败,重新identify 所有的sensor并保存相关信息

7163557-01c410f0c127ccbb.png
第二段log

加载的cfg表格源码
vendor/sprd/modules/libcamera/sensor/sensor_cfg.c

7163557-0bbcfd737562c2ec.png

sp2609宏定义的位置
device/sprd/sharkle/sp9820e_xtc_i17/BoardConfig.mk

#camera sensor type
#CAMERA_SENSOR_TYPE_BACK := "SP2609"
CAMERA_SENSOR_TYPE_FRONT := "SP2609"
#CAMERA_SENSOR_TYPE_BACK_EXT :=
#CAMERA_SENSOR_TYPE_FRONT_EXT :=

接下来调用
sns_ops->create_handle(&sns_init_para,&sensor_cxt->sns_ic_drv_handle);
这个函数如下

7163557-a041f44e88fc7e35.png

继续看log

7163557-a4b651d156e0653d.png
第二段log续
7163557-5bd39ae1b6312c84.png
第二段log续2
7163557-28a687bba9671773.png
第三段log
7163557-d0e67f9bfb6afa53.png
第三段log续2
7163557-fb814f9c43069e58.png
第四段log
7163557-d96ca899bc7a76f2.png
第四段log续2
7163557-51c946c137de7ff0.png
第5段log
7163557-5f100393d868fd07.png
第6段
7163557-e98b1b9e91c83b0f.png
第7段log

步骤3.try open sensor second time.
尝试重新打开sensor
步骤4.if 3 steps failed,sensor open failed.
如果步骤3失败了,那么sensor打开失败

第一次Camera启动分析就结束了

3.log分析-【第二次启动分析】

7163557-e327be0ad4446f83.png
log 1
7163557-1653ace8422512f5.png
log 2
7163557-d51af2b38f1cd28b.png
log 3
7163557-ee6ac5a0c89f95b6.png
log 4
7163557-339d59c01f48cc5e.png
log 5
7163557-48ba5c3af59d6183.png
log 6
7163557-59c96fff5de482d2.png
log 7

总结

对比第一次冷启动热启动
第一次冷启动主要是多了CameraService的创建,
还有getSensorStaticinfo时,先去search所有的camera信息,保存起来,
后续再次打开Camera,直接从缓存读取信息,因此冷启动慢,热启动快。

其他的调用流程都是一致的!

Stay Hungry,Stay Foolish!

转载于:https://www.jianshu.com/p/d745fe4800da

猜你喜欢

转载自blog.csdn.net/weixin_34301132/article/details/91170087