1. 程式人生 > >Android7.1 [Camera] CameraService啟動原始碼分析

Android7.1 [Camera] CameraService啟動原始碼分析

原始碼平臺:rk3399

 

摘要:

1.拷貝cameraserver.rc編譯拷貝到system/etc/init目錄

2.啟動cameraserver服務

 

摘要1:cameraserver.rc編譯拷貝到system/etc/init目錄

android 系統啟動完bootloader後,會啟動核心,核心啟動完後,會啟動檔案系統,很多服務也是在這時候啟動起來,CameraService的啟動在frameworks/av/camera/cameraserver/cameraserver.rc檔案

service cameraserver /system/bin/cameraserver
    class main
    user cameraserver
    group audio camera input drmrpc readproc
    ioprio rt 4
    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

這個檔案會在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

LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter

LOCAL_INIT_RC := cameraserver.rc #這裡指定編譯為LOCAL_INIT_RC

include $(BUILD_EXECUTABLE)

其中LOCAL_INIT_RC := cameraserver.rc這個LOCAL_INIT_RC在編譯的時候,build/core/base_rules.mk會將這個檔案直接拷貝到/system/etc/init目錄下,

# 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)) #這裡指定的install路徑就是/system/etc/init/目錄
$(my_init_rc_installed) : $(my_init_rc_src) | $(ACP)
    @echo "Install: 
[email protected]
" $(copy-file-to-new-target) $(my_register_name) : $(my_init_rc_installed) endif # my_init_rc endif # !LOCAL_UNINSTALLABLE_MODULE

摘要2.啟動cameraserver服務

       system/core/init/init.cpp根據/init.rc啟動一個無限迴圈的程序,也就是init程序,init程序會等待一些命令拋進來執行.載入到fstab.rk30board後,這個檔案會掛載各個分割槽,掛載分割槽的後,會掃描執行分割槽下的指定目錄,在system/core/init/builtins.cpp,do_mount_all函式會根據fstab.rk30board檔案掛載各個分割槽,具體怎麼掛載這裡不描述,最終會匯入並解析rc檔案

/* mount_all <fstab> [ <path> ]* [--<options>]*
 *
 * This function might request a reboot, in which case it will
 * not return.
 */    
static int do_mount_all(const std::vector<std::string>& args) {
    std::size_t na = 0; 
    bool import_rc = true;    
    bool queue_event = true;  
    int mount_mode = MOUNT_MODE_DEFAULT; 
    const char* fstabfile = args[1].c_str();
    std::size_t path_arg_end = args.size();

    for (na = args.size() - 1; na > 1; --na) {
        if (args[na] == "--early") {        
             path_arg_end = na;             
             queue_event = false;           
             mount_mode = MOUNT_MODE_EARLY;
        } else if (args[na] == "--late") { 
            path_arg_end = na;
            import_rc = false;
            mount_mode = MOUNT_MODE_LATE;
        }
    }  

    /* 這裡會先讀取根目錄的fstab.rk30board 檔案
       這個檔案指定了要掛載的各個分割槽,包括system分割槽 */
    int ret =  mount_fstab(fstabfile, mount_mode);

    /* 分割槽掛載出來後,開始搜尋匯入rc檔案 */
    if (import_rc) {
        /* Paths of .rc files are specified at the 2nd argument and beyond */
        import_late(args, 2, path_arg_end);
    }  

    if (queue_event) {
        /* queue_fs_event will queue event based on mount_fstab return code
         * and return processed return code*/
        ret = queue_fs_event(ret); 
    }  

    return ret;
}

/* Imports .rc files from the specified paths. Default ones are applied if none is given.
 *
 * start_index: index of the first path in the args list
 */
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
    Parser& parser = Parser::GetInstance();
    if (end_index <= start_index) {
        // Use the default set if no path is given
        static const std::vector<std::string> init_directories = {
            "/system/etc/init",
            "/vendor/etc/init",
            "/odm/etc/init"
        };   

        for (const auto& dir : init_directories) {
            parser.ParseConfig(dir);
        }    
    } else {
        for (size_t i = start_index; i < end_index; ++i) {
            parser.ParseConfig(args[i]);
        }    
    }    
}

        其中也會解析到/system/etc/init/cameraserver.rc檔案.具體的解析過程可以看init目錄下的原始碼,這裡直接簡單講解下過程

1.init.cpp會例項一個Parser,這個Parser添加了service,on,import三個SectionParser,這三個SectionParser解析出是否是server,還是on的section時,就用對應的解析器解析了

2.上面說的解析器具體有3個,但import實際上匯入後,還是呼叫service或者action的解析器,service和action的解析器都是繼承SectionParser的

3.service的解析器會針對每個選項進行解析,比如:

Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    static const Map option_handlers = { 
        {"class",       {1,     1,    &Service::HandleClass}},
        {"console",     {0,     0,    &Service::HandleConsole}},
        {"critical",    {0,     0,    &Service::HandleCritical}},
        {"disabled",    {0,     0,    &Service::HandleDisabled}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
        {"ioprio",      {2,     2,    &Service::HandleIoprio}},
        {"keycodes",    {1,     kMax, &Service::HandleKeycodes}},
        {"oneshot",     {0,     0,    &Service::HandleOneshot}},
        {"onrestart",   {1,     kMax, &Service::HandleOnrestart}},
        {"seclabel",    {1,     1,    &Service::HandleSeclabel}},
        {"setenv",      {2,     2,    &Service::HandleSetenv}},
        {"socket",      {3,     6,    &Service::HandleSocket}},
        {"user",        {1,     1,    &Service::HandleUser}},
        {"writepid",    {1,     kMax, &Service::HandleWritepid}},
    };  
    return option_handlers;
}

所以對於cameraserver

service cameraserver /system/bin/cameraserver
    class main
    user cameraserver
    group audio camera input drmrpc readproc
    ioprio rt 4
    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

每一行的都有對於的處理函式../service.cpp 的start函式根據配置啟動服務,啟動服務時在核心列印

NOTICE("Starting service '%s'...\n", name_.c_str());

rk3399-x24:/ # dmesg | grep "Starting service"
[    3.351255] init: Starting service 'ueventd'...
[    3.900692] init: Starting service 'healthd'...
[    3.902384] init: Starting service 'zygote'...
[    3.903117] init: Starting service 'zygote_secondary'...
[    3.903727] init: Starting service 'lmkd'...
[    3.904320] init: Starting service 'servicemanager'...
[    3.905270] init: Starting service 'surfaceflinger'...
[    3.906341] init: Starting service 'vold'...
[    3.957724] init: Starting service 'debuggerd'...
[    3.958596] init: Starting service 'debuggerd64'...
[    4.259461] init: Starting service 'exec 1 (/system/bin/tzdatacheck)'...
[    4.286239] init: Starting service 'logd'...
[    4.287204] init: Starting service 'logd-reinit'...
[    4.304512] init: Starting service 'console'...
[    4.305094] init: Starting service 'adbd'...
[    4.306347] init: Starting service 'ril-daemon'...
[    4.307179] init: Starting service 'drmservice'...
[    4.308131] init: Starting service 'akmd'...
[    4.317428] init: Starting service 'audioserver'...
[    4.321919] init: Starting service 'cameraserver'...   cameraserver服務
[    4.322659] init: Starting service 'drm'...
[    4.323364] init: Starting service 'installd'...
[    4.324265] init: Starting service 'keystore'...
[    4.327250] init: Starting service 'mediacodec'...
[    4.327986] init: Starting service 'mediadrm'...
[    4.328601] init: Starting service 'mediaextractor'...
[    4.329469] init: Starting service 'media'...
[    4.330048] init: Starting service 'netd'...
[    4.331389] init: Starting service 'gatekeeperd'...
[    4.342622] init: Starting service 'perfprofd'...
[    5.409223] init: Starting service 'bootanim'...
[   11.399632] init: Starting service 'mode_switch'...
[   11.402586] init: Starting service 'exec 3 (/system/bin/bootstat)'...
[   11.421041] init: Starting service 'exec 4 (/system/bin/bootstat)'...
[   11.430231] init: Starting service 'exec 5 (/system/bin/bootstat)'...
[   11.441745] init: Starting service 'exec 6 (/system/bin/bootstat)'...

至此,cameraserver的服務就啟動起來了