主頁 > 移動端開發 > Android系統啟動流程分析

Android系統啟動流程分析

2021-10-11 16:18:39 移動端開發

前言

寫這篇blog背景是專案在做系統啟動耗時優化,之前看了兩遍羅升陽大神《Android系統源代碼情景分析》都只是看了,沒有實踐,沒有運用到專案中,因此借專案在做系統優化的機會,再次將Android系統的啟動流程細細的在擼一遍,邊擼邊思考哪些點可以優化,

**宣告:**由于家里面的代碼是去年下的,去年還在做Android O(android-8.0.0_r1)的系統專案,如果博客中有方法在你的代碼中找不到,要么選擇和我一起看Android O的R1版本代碼,要么可以嘗試找找你下載版本的原始碼是否有對我博客中的代碼進行封裝,因為我經常發現google會將代碼在不同版本中封裝,大致流程肯定是完全一樣的,

**說明:**這篇博客著實有點長,我本來想分幾篇寫的,但是感覺分幾篇就不完整了,分散了心里始終感覺哪里不對頭,所有就沒分散,**我不能保證你一定能看完這篇博客,但是我可以保證你看完這篇博客,你肯定會對Android系統啟動有更深的理解,**為了方便理解,我先丟兩張圖,先看圖有個直觀的認識,再看方法實作了什么功能更容易理解,也更容易在跟蹤方法呼叫迷糊時找到調入的地方,

如果看不清楚,原圖下載傳送門:系統啟動分析

在這里插入圖片描述

在這里插入圖片描述

1.Android系統大致啟動流程

第一步: 啟動電源以及系統啟動
當電源按下,引導芯片代碼開始從預定義的地方(固化在ROM)開始執行,加載引導程式到RAM,然后 執行引導程式,

第二步:引導程式
引導程式是在Android作業系統開始運行前的一個小程式,引導程式是運行的第一個程式,因此它是針 對特定的主板與芯片的,設備制造商要么使用很受歡迎的引導程式比如redboot、uboot、qi bootloader或者開發自己的引導程式,它不是Android作業系統的一部分,引導程式是OEM廠商或者運 營商加鎖和限制的地方,
引導程式分兩個階段執行,
第一個階段,檢測外部的RAM以及加載對第二階段有用的程式;
第二階段,引導程式設定網路、記憶體等等,這些對于運行內核是必要的,為了達到特殊的目標,引導程 序可以根據配置引數或者輸入資料設定內核,
Android引導程式可以在\bootable\bootloader\legacy\usbloader找到,傳統的加載器包含兩個檔案, 需要在這里說明:
init.s初始化堆疊,清零BBS段,呼叫main.c的_main()函式;
main.c初始化硬體(鬧鐘、主板、鍵盤、控制臺),創建linux標簽

第三步:內核
Android內核與桌面linux內核啟動的方式差不多,內核啟動時,設定快取、被保護存盤器、計劃串列, 加載驅動,當內核完成系統設定,它首先在系統檔案中尋找”init”檔案,然后啟動root行程或者系統的第 一個行程

第四步:init行程
init行程是Linux系統中用戶空間的第一個行程,行程號固定為1,Kernel啟動后,在用戶空間啟動init進 程,并呼叫init中的main()方法執行init行程的職責,

第五步:啟動zygote行程,通過zygote啟動SystemServer,當服務都啟動完成之后,啟動Lancher App,然后退出開機影片,我們就可以看到桌面應用,此時啟動程序就結束了,

2.啟動init行程

init行程是Android系統中及其重要的第一個行程,是由內核拉起來的第一個用戶行程,

init行程主要完成了三件事情,

  • 創建和掛載啟動所需要的檔案目錄
  • 初始化和啟動屬性服務
  • 決議init.rc組態檔并啟動Zygote行程
// \system\core\init\init.cpp main()
/* 
* 1.C++中主函式有兩個引數,第一個引數argc表示引數個數,第二個引數是引數串列,也就是具體 的引數 
* 2.init的main函式有兩個其它入口,一是引數中有ueventd,進入ueventd_main,二是引數中 有watchdogd,進入watchdogd_main 
*/ 
int main(int argc, char** argv) {
    /* 
    * 1.strcmp是String的一個函式,比較字串,相等回傳0 
    * 2.C++中0也可以表示false 
    * 3.basename是C庫中的一個函式,得到特定的路徑中的最后一個'/'后面的內容, 
    * 比如/sdcard/miui_recovery/backup,得到的結果是backup 
    */
    if (!strcmp(basename(argv[0]), "ueventd")) {
        //當argv[0]的內容為ueventd 時,strcmp的值為0,!strcmp為1 
		//1表示true,也就執行ueventd_main,ueventd主要是負責設備節點的創建、權限設定等一系列作業
        return ueventd_main(argc, argv);
    }

    if (!strcmp(basename(argv[0]), "watchdogd")) {
        //watchdogd俗稱看門狗,用于 系統出問題時重啟系統
        return watchdogd_main(argc, argv);
    }

    if (REBOOT_BOOTLOADER_ON_PANIC) {
        //初始化重啟系統的處理信號,內部通過sigaction 注冊信號,當監聽到該信號時重啟系統
        install_reboot_signal_handlers();
    }

    add_environment("PATH", _PATH_DEFPATH);

    // 查看是否有環境變數INIT_SECOND_STAGE
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    // 1.init的main方法會執行兩次,由is_first_stage控制,first_stage就是第一階段要做的事
    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now();

        // Clear the umask.
        //清空檔案權限
        umask(0);

        // Get the basic filesystem setup we need put together in the initramdisk
        // on / and then we'll let the rc file figure out the rest.
        //mount是用來掛載檔案系統的,mount屬于Linux系統呼叫
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);;//創建目錄,第一個引數是目錄路徑,第二個是讀寫權限
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        #define MAKE_STR(x) __STRING(x)
        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
        // Don't expose the raw commandline to unprivileged processes.
        chmod("/proc/cmdline", 0440);//用于修改檔案/目錄的讀寫權限
        gid_t groups[] = { AID_READPROC };
        // 用來將list陣列中所標明的組加入到目前行程的組設定中
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
        //mknod用于創建Linux中的設備檔案
        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));

        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
        // talk to the outside world...
        //將標準輸入輸出重定向到"/sys/fs/selinux/null"
        InitKernelLogging(argv);

        LOG(INFO) << "init first stage started!";

        if (!DoFirstStageMount()) {
            LOG(ERROR) << "Failed to mount required partitions early ...";
            panic();
        }

        //Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和dm-verity, 
		//原理都是對二進制檔案進行簽名,在系統啟動時進行認證,確保系統運行的是合法的二進制鏡像檔案, 
		//其中認證的范圍涵蓋:bootloader,boot.img,system.img
        // 通過呼叫FsManagerAvbHandle::Open()->FsManagerAvbOps::AvbSlotVerify->avb_slot_verify最終去驗證每個磁區,
        // 當驗證成功之后,會將版本資訊寫到環境變數 INIT_AVB_VERSION 中
        SetInitAvbVersionInRecovery();

        // Set up SELinux, loading the SELinux policy.
        //加載SELinux policy,也就是安全策略,
        selinux_initialize(true);

        // We're in the kernel domain, so re-exec init to transition to the init domain now
        // that the SELinux policy has been loaded.
        // 我們執行第一遍init的main方法是在kernel domain,所以要重新執行init檔案,切換到加載了selinux策略的init domain,
        if (restorecon("/init") == -1) {
            PLOG(ERROR) << "restorecon failed";
            security_failure();
        }

        // 設定進入第二階段標志位,進入第二階段
        setenv("INIT_SECOND_STAGE", "true", 1);

        static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
        uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
        setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);

        char* path = argv[0];
        char* args[] = { path, nullptr };
        // 重新執行init,由于標志位置為了,因此再次執行init會進入階段,
        execv(path, args);

        // execv() only returns if an error happened, in which case we
        // panic and never fall through this conditional.
        PLOG(ERROR) << "execv(\"" << path << "\") failed";
        security_failure();
    }

    // At this point we're in the second stage of init.
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);

    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

    //初始化屬性系統,并從指定檔案讀取屬性
    // bionic/libc/bionic/system_properties.c
    // __system_property_area_init->map_prop_area_rw->打開/dev/__properties__檔案->并且映射128kb空間大小記憶體來存屬性鍵值對,
    property_init();

    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    //接下來的一系列操作都是從各個檔案讀取一些屬性,然后通過property_set設定系統屬性
    // 1.這句英文的大概意思是,如果引數同時從命令列和DT傳過來,DT的優先級總是大于命令列的,
    // 2.DT即device-tree,中文意思是設備樹,這里面記錄自己的硬體配置和系統運行引數,參考http://www.wowotech.net/linux_kenrel/why-dt.html
    process_kernel_dt();//處理DT屬性
    process_kernel_cmdline();//處理命令列屬性

    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    export_kernel_boot_props();//處理其他的一些屬性

    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));

    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    // 將avb版本設定到系統屬性中
    if (avb_version) property_set("ro.boot.avb_version", avb_version);

    // Clean up our environment.
    // 清除環境變數
    unsetenv("INIT_SECOND_STAGE");
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");

    // Now set up SELinux for second stage.
    selinux_initialize(false);
    selinux_restore_context();

    //創建epoll實體,并回傳epoll的檔案描述符
    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(ERROR) << "epoll_create1 failed";
        exit(1);
    }

    // 主要是創建handler處理子行程終止信號,創建一個匿名 socket并注冊到epoll進行監聽
    signal_handler_init();

    // 從檔案中加載一些屬性,讀取usb配置
    // 涉及到的檔案,/system/etc/prop.default,/odm/default.prop,/vendor/default.prop
    property_load_boot_defaults();
    export_oem_lock_status();// 設定ro.boot.flash.locked 屬性
    start_property_service();//開啟一個socket監聽系統屬性的設定
    set_usb_controller();//設定sys.usb.controller 屬性

    //init.rc檔案中方法映射,例如“class_start”-> "do_class_start"
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);//將function_map存放到Action中作 為成員屬性

    // 使用不同的parse決議init.rc檔案中的不同欄位,并且將service保存在servicelist中
    Parser& parser = Parser::GetInstance();
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        // 以下目錄的所有rc檔案默認都會被決議
        parser.ParseConfig("/init.rc");
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) parser.DumpState();//列印一些當前Parser的資訊,默認是不執行的

    ActionManager& am = ActionManager::GetInstance();

    // QueueEventTrigger用于觸發Action,這里觸發early-init事件
    am.QueueEventTrigger("early-init");

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    //QueueBuiltinAction用于添加Action,第一個引數是 Action要執行的Command,第二個是Trigger
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");

    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1; //epoll超時時間,相當于阻塞時間

        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            am.ExecuteOneCommand();//執行一個command
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            restart_processes();

            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }

            // If there's more work to do, wake up again immediately.
            //當還有命令要執行時,將epoll_timeout_ms設定為0
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }

        epoll_event ev;
        /* 
        * 1.epoll_wait與epoll_create1、epoll_ctl是一起使用的 
        * 2.epoll_create1用于創建epoll的檔案描述符,epoll_ctl、epoll_wait都把它創建的fd作為第一個引數傳入 
        * 3.epoll_ctl用于操作epoll,EPOLL_CTL_ADD:注冊新的fd到epfd中, 
        EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件,EPOLL_CTL_DEL:從epfd中洗掉一個fd; 
        * 4.epoll_wait用于等待事件的產生,epoll_ctl呼叫EPOLL_CTL_ADD時會傳入需要監聽什么型別的事件, 
        *比如EPOLLIN表示監聽fd可讀,當該fd有可讀的資料時,呼叫epoll_wait經過epoll_timeout_ms時間就會把該事件的資訊回傳給&ev 
        */
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            //當有event回傳時,取出 ev.data.ptr(之前epoll_ctl注冊時的回呼函式),直接執行 
            //在signal_handler_init和start_property_service有注冊兩個fd的監聽,一個用于監聽SIGCHLD(子行程結束信號),一個用于監聽屬性設定
            ((void (*)()) ev.data.ptr)();
        }
    }

    return 0;
}

3.決議init.rc

init.rc是一個非常重要的組態檔,它是由Android初始化語言(Android Init Language)撰寫的腳本,它主要包含五種型別陳述句:Action(Action中包含了一系列的Command)、Commands(init語言中的命令)、Services(由init行程啟動的服務)、Options(對服務進行配置的選項)和Import(引入其他組態檔),init.rc的配置代碼如下所示,

# \system\core\rootdir\init.rc 
on init # L41
	sysclktz 0
   # Mix device-specific information into the entropy pool    
   copy /proc/cmdline /dev/urandom
   copy /default.prop /dev/urandom
   ...
   
on <trigger> [&& <trigger>]* //設定觸發器     
	<command>
    <command> //動作觸發之后要執行的命令
    
service <name> <pathname> [ <argument> ]* #<service的名字><執行程式路徑><傳遞引數>
    <option>  #Options是Services的引數配置. 它們影響Service如何運行及運行時機     
    group <groupname> [ <groupname>\* ] #在啟動Service前將group改為第一個 groupname,第一個groupname是必須有的,默認值為root(或許默認值是無),第二個groupname可以不設定,用于追加組(通過 setgroups)
    priority <priority> #設定行程優先級. 在-20~19之間,默認值是0,能過 setpriority實作
    socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ] #創建 一個unix域的socket,名字叫/dev/socket/name , 并將fd回傳給Service. type 只能是 "dgram", "stream" or "seqpacket".
3.1 Action

Action: 通過觸發器trigger,即以on開頭的陳述句來決定執行相應的service的時機,具體有如下時機:

  • on early-init; 在初始化早期階段觸發;
  • on init; 在初始化階段觸發;
  • on late-init; 在初始化晚期階段觸發;
  • on boot/charger: 當系統啟動/充電時觸發,還包含其他情況,此處不一一列舉;
  • on property:=: 當屬性值滿足條件時觸發
3.2 Service

服務Service,以 service開頭,由init行程啟動,一般運行在init的一個子行程,所以啟動service前需要判斷對應的可執行檔案是否存在,init生成的子行程,定義在rc檔案,其中每一個service在啟動時會通過 fork方式生成子行程,
例如: service servicemanager /system/bin/servicemanager代表的是服務名為 servicemanager,服務執行的路徑為/system/bin/servicemanager,

3.3 Command

下面列舉常用的命令:

  • class_start <service_class_name>: 啟動屬于同一個class的所有服務;
  • start <service_name>: 啟動指定的服務,若已啟動則跳過;
  • stop <service_name>: 停止正在運行的服務
  • setprop :設定屬性值
  • mkdir :創建指定目錄
  • symlink <sym_link>: 創建連接到的<sym_link>符號鏈接;
  • write : 向檔案path中寫入字串;
  • exec: fork并執行,會阻塞init行程直到程式完畢;
  • exprot:設定環境變數;
  • loglevel :設定log級別
3.4 Options

Options是Service的可選項,與service配合使用

  • disabled: 不隨class自動啟動,只有根據service名才啟動;
  • oneshot: service退出后不再重啟;
  • user/group: 設定執行服務的用戶/用戶組,默認都是root;
  • class:設定所屬的類名,當所屬類啟動/退出時,服務也啟動/停止,默認為default; onrestart:當服務重啟時執行相應命令;
  • socket: 創建名為 /dev/socket/的socket
  • critical: 在規定時間內該service不斷重啟,則系統會重啟并進入恢復模式
  • default: 意味著disabled=false,oneshot=false,critical=false,

下面看看zygote的rc腳本

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote -- start-system-server
   class main    
   priority -20    
   user root
   group root readproc reserved_disk    
   socket zygote stream 660 root system
   onrestart write /sys/android_power/request_state wake
   onrestart write /sys/power/state on
   onrestart restart audioserver
   onrestart restart cameraserver
   onrestart restart media
   onrestart restart netd
   onrestart restart wificond
   writepid /dev/cpuset/foreground/tasks
3.5 逐行決議腳本
// system\core\init\init_parser.cpp
void Parser::ParseData(const std::string& filename, const std::string& data) {
    //TODO: Use a parser with const input and remove this copy
    std::vector<char> data_copy(data.begin(), data.end());
    data_copy.push_back('\0');

    parse_state state;
    state.filename = filename.c_str();
    state.line = 0;
    state.ptr = &data_copy[0];
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    std::vector<std::string> args;

    for (;;) {
        switch (next_token(&state)) {
        case T_EOF:
            if (section_parser) {
                // 結束決議
                section_parser->EndSection();
            }
            return;
        case T_NEWLINE:
            state.line++;
            if (args.empty()) {
                break;
            }
            if (section_parsers_.count(args[0])) {
                if (section_parser) {
                    section_parser->EndSection();
                }
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
                // 逐行決議
                if (!section_parser->ParseSection(args, &ret_err)) {
                    parse_error(&state, "%s\n", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) {
                std::string ret_err;
                if (!section_parser->ParseLineSection(args, state.filename,
                                                      state.line, &ret_err)) {
                    parse_error(&state, "%s\n", ret_err.c_str());
                }
            }
            args.clear();
            break;
        case T_TEXT:
            args.emplace_back(state.text);
            break;
        }
    }
}
// \system\core\init\service.cpp 
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,                                            const std::string& filename, int line) {
   if (args.size() < 3) {
       return Error() << "services must have a name and a program";  }
   const std::string& name = args[1];    if (!IsValidName(name)) {
       return Error() << "invalid service name '" << name << "'";  }
   Subcontext* restart_action_subcontext = nullptr;    if (subcontexts_) {
       for (auto& subcontext : *subcontexts_) {
           if (StartsWith(filename, subcontext.path_prefix())) {                restart_action_subcontext = &subcontext;
               break;        }
     }  }
   std::vector<std::string> str_args(args.begin() + 2, args.end());
   service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);//構建出一個service物件
   return Success(); }
// \system\core\init\service.cpp 
void ServiceParser::EndSection() {
    if (service_) {
        // 如果上面決議的service不為空,就加入到ServiceManager中
        ServiceManager::GetInstance().AddService(std::move(service_));
    }
}

上面決議完成后,接下來就是啟動Service,這里我們以啟動Zygote來分析

# \system\core\rootdir\init.rc L680 
on nonencrypted
   class_start main #class_start是一個命令,通過do_class_start函式處理    
   class_start 	late_start
# system\core\init\builtins.cpp
static Result<Success> do_class_start(const BuiltinArguments& args) {    
   // Starting a class does not start services which are explicitly disabled.
   // They must  be started individually.
   for (const auto& service : ServiceList::GetInstance()) {        
       if (service->classnames().count(args[1])) {
           // 呼叫剛剛注冊的service的StartIfNotDisabled()方法
           if (auto result = service->StartIfNotDisabled(); !result) {
               LOG(ERROR) << "Could not start service '" << service->name()                           << "' as part of class '" << args[1] << "': " << result.error();
      	 }      
       }
	 }
   return Success(); 
}
// \system\core\init\service.cpp 
Result<Success> Service::StartIfNotDisabled() {
   if (!(flags_ & SVC_DISABLED)) {        
       return Start();
   } else {
       flags_ |= SVC_DISABLED_START;  }
   	   return Success();
}
bool Service::Start() {
    // Starting a service removes it from the disabled or reset state and
    // immediately takes it out of the restarting state if it was in there.
    flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));

    // 如果service已經啟動了,就不啟動了
    if (flags_ & SVC_RUNNING) {
        return false;
    }

    ......

    struct stat sb;
    //判斷需要啟動的service的對應的執行檔案是否存在,不存在則不啟動service
    if (stat(args_[0].c_str(), &sb) == -1) {
        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
        flags_ |= SVC_DISABLED;
        return false;
    }

    std::string scon;
    if (!seclabel_.empty()) {
        scon = seclabel_;
    } else {
        LOG(INFO) << "computing context for service '" << name_ << "'";
        scon = ComputeContextFromExecutable(name_, args_[0]);
        if (scon == "") {
            return false;
        }
    }

    LOG(INFO) << "starting service '" << name_ << "'...";
	//如果子行程沒有啟動,則呼叫fork函式創建子行程
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }

    if (pid == 0) {//當期代碼邏輯在子行程中運行
        umask(077);

        if (namespace_flags_ & CLONE_NEWPID) {
            // This will fork again to run an init process inside the PID
            // namespace.
            SetUpPidNamespace(name_);
        }

        for (const auto& ei : envvars_) {
            add_environment(ei.name.c_str(), ei.value.c_str());
        }

        std::for_each(descriptors_.begin(), descriptors_.end(),
                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));

        // See if there were "writepid" instructions to write to files under /dev/cpuset/.
        auto cpuset_predicate = [](const std::string& path) {
            return android::base::StartsWith(path, "/dev/cpuset/");
        };
        auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
        if (iter == writepid_files_.end()) {
            // There were no "writepid" instructions for cpusets, check if the system default
            // cpuset is specified to be used for the process.
            std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", "");
            if (!default_cpuset.empty()) {
                // Make sure the cpuset name starts and ends with '/'.
                // A single '/' means the 'root' cpuset.
                if (default_cpuset.front() != '/') {
                    default_cpuset.insert(0, 1, '/');
                }
                if (default_cpuset.back() != '/') {
                    default_cpuset.push_back('/');
                }
                writepid_files_.push_back(
                    StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str()));
            }
        }
        std::string pid_str = StringPrintf("%d", getpid());
        for (const auto& file : writepid_files_) {
            if (!WriteStringToFile(pid_str, file)) {
                PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
            }
        }

        if (ioprio_class_ != IoSchedClass_NONE) {
            if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
                PLOG(ERROR) << "failed to set pid " << getpid()
                            << " ioprio=" << ioprio_class_ << "," << ioprio_pri_;
            }
        }

        if (needs_console) {
            setsid();
            OpenConsole();
        } else {
            ZapStdio();
        }

        // As requested, set our gid, supplemental gids, uid, context, and
        // priority. Aborts on failure.
        SetProcessAttributes();

        std::vector<char*> strs;
        //呼叫execv函式,啟動sevice子行程
        ExpandArgs(args_, &strs);
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }

        _exit(127);
    }

    ......
}

4.zygote啟動

上面看到了決議了init.rc之后就可以啟動服務,下面我們來看看zygote是如何啟動的,啟動起來干了什么事情,

4.1 Zygote簡述

Zygote是一個C/S模型,Zygote行程作為服務端,它主要負責創建Java虛擬機,加載系統資源,啟動SystemServer行程,以及在后續運行程序中啟動普通的應用程式,其他行程作為客戶端向它發 出“范訓”請求,而Zygote接收到這個請求后就“范訓”出一個新的行程,比如,當點擊Launcher里的 應用程式圖示去啟動一個新的應用程式行程時,這個請求會到達框架層的核心服務 ActivityManagerService中,當AMS收到這個請求后,它通過呼叫Process類發出一個“范訓”子進 程的Socket請求,而Zygote監聽到這個請求后就立刻fork一個新的行程出來,

zygote的啟動腳本檔案是:init.zygoteXX.rc,在init.rc中會參考該rc檔案

import /init.${ro.zygote}.rc

${ro.zygote} 會被替換成 ro.zyogte 的屬性值,這個是由不同的硬體廠商自己定制的, 有四個值,

  • zygote32: zygote 行程對應的執行程式是 app_process (純 32bit 模式)
  • zygote64: zygote 行程對應的執行程式是 app_process64 (純 64bit 模式)
  • zygote32_64: 啟動兩個 zygote 行程 (名為 zygote 和 zygote_secondary),對應的執行程式分別 是 app_process32 (主模式)
  • zygote64_32: 啟動兩個 zygote 行程 (名為 zygote 和 zygote_secondary),對應的執行程式分別 是 app_process64 (主模式)、app_process32
4.2 啟動runtime
# 位置:system\core\rootdir\init.rc  L560
start zygote
# It is recommended to put unnecessary data/ initialization from post-fs- data
# to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted
   # A/B update verifier that marks a successful boot.    exec_start update_verifier_nonencrypted
   start netd
   start zygote
   start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported   # A/B update verifier that marks a successful boot.   exec_start update_verifier_nonencrypted
   start netd
   start zygote
   start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
   # A/B update verifier that marks a successful boot.    exec_start update_verifier_nonencrypted
   start netd
   start zygote
   start zygote_secondary

無論是否啟動FDE/FBE加密,都依賴zygote-start,zygote-start 是在 on late-init 中觸發的,

# Mount filesystems and start core system services.
on late-init
   trigger early-fs
   # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
   # '--early' can be specified to skip entries with 'latemount'.    
   # /system and /vendor must be mounted by the end of the fs stage,    
   # while /data is optional.
   trigger fs
   trigger post-fs
   
   # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter    
   # to only mount entries with 'latemount'. This is needed if '--early' is    
   # specified in the previous mount_all command on the fs stage.
   # With /system mounted and properties form /system + /factory available,    
   # some services can be started.
   trigger late-fs
   # Now we can mount /data. File encryption requires keymaster to decrypt    
   # /data, which in turn can only be loaded when system properties are present.
   trigger post-fs-data
   # Now we can start zygote for devices with file based encryption
   
   trigger zygote-start #zygote-start 是在on late-init 中觸發的,
   # Load persist properties and override properties (if enabled) from /data.
   trigger load_persist_props_action
   # Remove a file to wake up anything waiting for firmware.
   trigger firmware_mounts_complete
   trigger early-boot
   trigger boot
if (bootmode == "charger") {
    am.QueueEventTrigger("charger");    
} else {
    am.QueueEventTrigger("late-init");  
}

不是充電模式,就觸發late-init,最后觸發start zygote,

app_processXX位置\frameworks\base\cmds\app_process目錄下

4.3 zygote啟動代碼分析

位置\frameworks\base\cmds\app_process\app_main.cpp
在app_main.cpp的main函式中,主要做的事情就是引數決議. 這個函式有兩種啟動模式:

  1. 一種是zygote模式,也就是初始化zygote行程,傳遞的引數有–start-system-server --socket- name=zygote,前者表示啟動SystemServer,后者指定socket的名稱
  2. 一種是application模式,也就是啟動普通應用程式,傳遞的引數有class名字以及class帶的引數
    兩者最終都是呼叫AppRuntime物件的start函式,加載ZygoteInit或RuntimeInit兩個Java類,并將之前 整理的引數傳入進去
// \frameworks\base\cmds\app_process\app_main.cpp main()  L280 
    if (strcmp(arg, "--zygote") == 0) {
        // 如果rc腳本傳入的--zygote引數,就將zygote設定為true,
        zygote = true;
        niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) {            
        startSystemServer = true;
    } else if (strcmp(arg, "--application") == 0) {
        application = true;      
    }

	......
    if (zygote) {
      //這些Java的應用都是通過AppRuntime.start(className)開始的
      //其實AppRuntime是AndroidRuntime的子類,它主要實作了幾個回呼函式,而start()方法是實作在AndroidRuntime這個方法類里
       runtime.start("com.android.internal.os.ZygoteInit", args, zygote);    
    } else if (className) {
       runtime.start("com.android.internal.os.RuntimeInit", args, zygote);    
    }  
// \frameworks\base\core\jni\androidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    static const String8 startSystemServer("start-system-server");

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }

    // 獲取環境變數,確認系統根目錄
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    // 啟動虛擬機
    //startVM的前半部分是在處理虛擬機的啟動引數,處理完配置引數后,會呼叫libart.so提供 的一個介面:JNI_CreateJavaVM函式
    // 在創建虛擬機的時候,首先會通過Runtime的create方法創建單例的Runtime物件,runtime負責提供art虛擬機的運行時環境,然后呼叫其init方法來初始化虛擬機,
    // 創建虛擬機一共做了五個事情:
    // 1.new gc::heap(),創建Heap物件,這是虛擬機管理對記憶體的起點, 
    // 2.new JavaVmExt(),創建Java虛擬機實體,
    // 3.Thread::attach(),attach主執行緒 
    // 4.創建ClassLinker
    // 5.初始化ClassLinker,成功attach到runtime環境后,創建ClassLinker實體負責管理java class
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    // 回呼虛擬機創建成功,決議類名,并且找到對應的Class物件,
    onVmCreated(env);

    /*
     * Register android functions.
     */
    // 注冊jni方法,以便java層可以呼叫
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    // 創建main方法中的兩個引數
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 呼叫main()啟動對應的行程,如果是zygoteinit就呼叫zygoteinit的main方法啟動zygote
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);

    ......
}
// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
// 虛擬機創建好之后,創建java Runtime.
public static final void main(String[] argv) {
        enableDdms();
        if (argv.length == 2 && argv[1].equals("application")) {
            if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
            //將System.out 和    System.err 輸出重定向到Android 的Log系統(定義在android.util.Log)
            redirectLogStreams();
        } else {
            if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
        }

        // commonInit(): 初始化了一下系統屬性,其中最重要的一點就是設定了一個未捕捉例外的 handler,當代碼有任何未知例外,就會執行它,
        commonInit();

        /*
         * Now that we're running in interpreted code, call back into native code
         * to run the system.
         */
    	// 回呼native java Runtime已經啟動完畢
        nativeFinishInit();

        if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
    }
// \frameworks\base\core\jni\androidRuntime.cpp nativeFinishInit() L225 
/** Code written in the Java Programming Language calls here from main(). */
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz){
   // 調到要啟動的行程中
   gCurRuntime->onStarted(); 
}
// \frameworks\base\cmds\app_process\app_main.cpp
virtual void onStarted()
{
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();

    AndroidRuntime* ar = AndroidRuntime::getRuntime();
    // 呼叫ZygoteInit的main方法.回應到runtime.start("...ZygoteInit")
    ar->callMain(mClassName, mClass, mArgs);

    IPCThreadState::self()->stopProcess();
    hardware::IPCThreadState::self()->stopProcess();
}
4.3 啟動zygote
public static void main(String argv[]) {
    	// 創建一個LocalServerSocket,等待AMS發起fork子行程通知
        ZygoteServer zygoteServer = new ZygoteServer();

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        try {
            // Report Zygote start time to tron unless it is a runtime restart
            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
                MetricsLogger.histogram(null, "boot_zygote_init",
                        (int) SystemClock.elapsedRealtime());
            }

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            BootTimingsTraceLog bootTimingsTraceLog = new BootTimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                // zygote.rc腳本傳參啟動systemserver
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    // 在zygoteXX.rc腳本可以加--enable-lazy-preload引數來懶加載資源和class類
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            zygoteServer.registerServerSocket(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            // 如果沒有懶加載,就加載class和資源
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            //主動進行一次資源GC
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            // Set seccomp policy
            Seccomp.setPolicy();

            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
                // 啟動systemserver
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
            // 死回圈等待socket有資料讀入
            zygoteServer.runSelectLoop(abiList);

            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            // 通過拋例外的方式來呼叫子行程的main可以清空呼叫堆疊,
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

我們可以看到Zygote啟動一共干了如下幾個事情:

  • 啟動LocalServerSocket
  • 加載class和各種資源
  • 啟動systemserver
  • runSelectLoop中epoll等待客戶端socket連接
  • 根據客戶端傳過來的引數,在run()中反射呼叫ActivityThread的main()方法來啟動app行程,

下面我們來分別看一下以上幾個方法中做了什么,

4.3.1 加載class和各種資源
static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
    	// 將ICU資料通常由軟參考保存固定在記憶體中,如果沒有這一點,那么當Zygote GC在gcAndFinalize()中運行時,將收集在類預加載程序中直接創建的參考,
        beginIcuCachePinning();
        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
        bootTimingsTraceLog.traceBegin("PreloadClasses");
    	// 加載類
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("PreloadResources");
    	// 加載資源
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
    	// 加載OpenGL
        preloadOpenGL();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    	// 加載共享庫
        preloadSharedLibraries();
    	// 加載內置字體
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endIcuCachePinning();
    	// 注冊AndroidKeysReprovider并預熱已注冊的程式,
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

其中只有類加載、資源和字體加載有必要分析一下,因為在做精細系統啟動優化的時候可能會涉及到該部分內容,其他的就預加載就是單純的加載,

4.3.1.1 preloadClasses();

// 預加載類的路徑
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";

private static void preloadClasses() {
        final VMRuntime runtime = VMRuntime.getRuntime();

        InputStream is;
        try {
            // 通過流讀入需要預加載的類
            is = new FileInputStream(PRELOADED_CLASSES);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
            return;
        }

       ......

        try {
            BufferedReader br
                = new BufferedReader(new InputStreamReader(is), 256);
			// 一下代碼決議并且加載類
            int count = 0;
            String line;
            while ((line = br.readLine()) != null) {
                // Skip comments and blank lines.
                line = line.trim();
                if (line.startsWith("#") || line.equals("")) {
                    continue;
                }

                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
                try {
                    if (false) {
                        Log.v(TAG, "Preloading " + line + "...");
                    }
                    // Load and explicitly initialize the given class. Use
                    // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
                    // (to derive the caller's class-loader). Use true to force initialization, and
                    // null for the boot classpath class-loader (could as well cache the
                    // class-loader of this class in a variable).
                    // null代表使用Bootstrap ClassLoader最高級引導類加載器加載,加載后的類保存在該類加載器中,之后的類加載都會依托雙親委托機制,不重復加載相同的類,
                    Class.forName(line, true, null);
                    count++;
                } catch (ClassNotFoundException e) {
              ......
    }

4.3.1.2 preloadResources();

private static void preloadResources() {
    final VMRuntime runtime = VMRuntime.getRuntime();
	try {
        mResources = Resources.getSystem();
        mResources.startPreloading();
        if (PRELOAD_RESOURCES) {
            Log.i(TAG, "Preloading resources...");

            long startTime = SystemClock.uptimeMillis();
            TypedArray ar = mResources.obtainTypedArray(
                    com.android.internal.R.array.preloaded_drawables);
            // 更具索引id加載圖片資源
            int N = preloadDrawables(ar);
            ar.recycle();
            ......
}

4.3.1.3 preloadTextResources();

private static void preloadTextResources() {
    // 加載字體到map中
    Hyphenator.init();
    // 創建畫筆,設定默認字體
    TextView.preloadFontCache();
}
// frameworks\base\core\java\android\text\Hyphenator.java
public static void init() {
        sMap.put(null, null);

    	// 需要支持的語言
        for (int i = 0; i < AVAILABLE_LANGUAGES.length; i++) {
            HyphenationData data = AVAILABLE_LANGUAGES[i];
            // 加載對應語言的字體
            Hyphenator h = loadHyphenator(data);
            if (h != null) {
                sMap.put(Locale.forLanguageTag(data.mLanguageTag), h);
            }
        }

        for (int i = 0; i < LOCALE_FALLBACK_DATA.length; i++) {
            String language = LOCALE_FALLBACK_DATA[i][0];
            String fallback = LOCALE_FALLBACK_DATA[i][1];
            // 決議后的語言保存到map中
            sMap.put(Locale.forLanguageTag(language), sMap.get(Locale.forLanguageTag(fallback)));
        }
    }
private static final HyphenationData[] AVAILABLE_LANGUAGES = {
        new HyphenationData("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Assamese
        new HyphenationData("bg", 2, 2), // Bulgarian
        new HyphenationData("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Bengali
        new HyphenationData("cu", 1, 2), // Church Slavonic
        ......
        new HyphenationData("pt", 2, 3), // Portuguese
        new HyphenationData("sl", 2, 2), // Slovenian
        new HyphenationData("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Tamil
        new HyphenationData("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX), // Telugu
        new HyphenationData("tk", 2, 2), // Turkmen
        new HyphenationData("und-Ethi", 1, 1), // Any language in Ethiopic script
    };
4.3.2 啟動systemserver
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller, RuntimeException {
        ......
        /* Hardcoded command line to start the system server */
        // 設定systemserver啟動引數
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            // 創建子行程
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            // 在子行程中執行SystemServer代碼
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }
private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws Zygote.MethodAndArgsCaller {

        ......
		
        // 如果systemserver類已經被加載了,命中if;否則創建類加載器并且啟動引數傳給systemserver行程,首次我們分析SystemServer沒有被夾在的情況
        if (parsedArgs.invokeWith != null) {
            String[] args = parsedArgs.remainingArgs;
            // If we have a non-null system server class path, we'll have to duplicate the
            // existing arguments and append the classpath to it. ART will handle the classpath
            // correctly when we exec a new process.
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(args, 0, amendedArgs, 2, args.length);
                args = amendedArgs;
            }

            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                // 創建類加載器
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
				// 將當前執行的執行緒與類加載器系結,即設成主執行緒
                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            // 將剩余的引數傳給Systemserver執行緒
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }

        /* should never reach here */
    }
public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
    	// 此方法中就會去通過反射呼叫main方法了,留一下點懸念,待會兒啟動APP分析的時候詳細看下面的呼叫,此處我們理解就是呼叫了SystemServer的main(),在新的行程中拉起了systemserver,具體SystemServer中干了什么,專門用一章來分析,
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
4.3.3 runSelectLoop()
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

    	// 增加Zygote的socket服務端的fd為監聽物件,
        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);

        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                // 如果有POLLIN事件,并且遍歷的不是最后一個ZygoteConnection進入else
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    // 獲取ZygoteConnection,其實ZygoteConnection就可以理解成一個socket客戶端,因為在創建的時候持有一個socket,
                    // 執行ZygoteConnection的runOnce()方法
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }
// frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {

        ......
         // 該方法前面的都不用管,就是獲取啟動引數和一些權限校驗
			// fork一個子行程
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }

        try {
            if (pid == 0) {
                // in child
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                // 處理子行程預啟動的事務,關閉客戶端socket,并且重新開啟標準io
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                // should never get here, the child is expected to either
                // throw Zygote.MethodAndArgsCaller or exec().
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
// frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws Zygote.MethodAndArgsCaller {
        /**
         * By the time we get here, the native code has closed the two actual Zygote
         * socket connections, and substituted /dev/null in their place.  The LocalSocket
         * objects still need to be closed properly.
         */

    	// 關閉客戶端socket
        closeSocket();
        ......

        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            // 通過zygote行程啟動的行程,在此方法中呼叫待啟動行程的main方法
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
// frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
    	// 設定一些runtime引數,并且呼叫帶啟動行程的main方法
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
// frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
    	// 讓帶啟動的行程堆大小最大只能占0.75 * 最大堆記憶體
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());
            // let the process exit
            return;
        }

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
    	// 反射得到待執行的類和得到其中的main(),最終通過拋例外的方式,回到zygoteInit的main方法中
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

反射得到待執行的類和得到其中的main(),最終通過拋例外的方式,回到zygoteInit的main方法中!!

反射得到待執行的類和得到其中的main(),最終通過拋例外的方式,回到zygoteInit的main方法中!!

反射得到待執行的類和得到其中的main(),最終通過拋例外的方式,回到zygoteInit的main方法中!!

重要的事情說三遍!

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

以上代碼沒什么好說的,一眼就可以看懂,回傳得到main方法之后,將main()和引數封裝到MethodAndArgsCaller中,清堆疊回傳ZygoteInit.main(),

4.3.4 caller.run();

從4.3.3小節我們拿到了待執行應用的main()和啟動引數,然后經過caller.run()真正的來呼叫main()執行帶啟動應用的代碼,

// frameworks\base\core\java\com\android\internal\os\Zygote.java
public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                // 反射呼叫main方法
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

應用啟動的真相終于被挖出來了,此處ActivityThread的main方法被呼叫,一個應用就正式被啟動起來了!!!!

此處并沒有完,我們上面講到了SystemServer啟動程序還沒有將,需要單獨拿一章來講,本來想單獨開一篇帖子來敘述,但是單獨開一篇就感覺這篇啟動分析的文章斷了,所以還是繼續往下分析吧,

5. SystemServer啟動

在這里插入圖片描述

System Server 是Zygote fork 的第一個Java 行程, 這個行程非常重要,因為他們有很多的系統執行緒, 提供所有核心的系統服務,它們都是運行在system_server的行程 里,還有很多“Binder-x”的執行緒,它們是各個Service為了回應應用程式遠程呼叫請求而創建的,除此之 外,還有很多內部的執行緒,比如 ”UI thread”, “InputReader”, “InputDispatch” 等等,

從4.3.2小節我們看到了Zygote呼叫了StartSystemServer來啟動SystemServer,我們只分析到了呼叫到SystemServer的main方法就沒有分析了,因此,我們在該章專門敘述呼叫main()之后發生了什么故事,

// frameworks\base\services\java\com\android\server\SystemServer.java
public static void main(String[] args) {
        new SystemServer().run();
    }

public SystemServer() {
    // Check for factory test mode.
    mFactoryTestMode = FactoryTest.getMode();
    // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
    // 正常啟動mRuntimeRestart為false
    mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
}

main()中方法很簡單,真正有內容的在run()中,其中run()方法中重點干了四個事情:

  • 初始化必要的SystemServer環境引數
  • 啟動引導服務
  • 啟動核心服務
  • 啟動其他服務
 private void run() {
        try {
            traceBeginAndSlog("InitBeforeStartServices");
            // If a device's clock is before 1970 (before 0), a lot of
            // APIs crash dealing with negative numbers, notably
            // java.io.File#setLastModified, so instead we fake it and
            // hope that time from cell towers or NTP fixes it shortly.
            // 初始化系統時間
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            //
            // Default the timezone property to GMT if not set.
            //
            // 設定時區
            String timezoneProperty =  SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                Slog.w(TAG, "Timezone not set; setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");
            }

            // If the system has "persist.sys.language" and friends set, replace them with
            // "persist.sys.locale". Note that the default locale at this point is calculated
            // using the "-Duser.locale" command line flag. That flag is usually populated by
            // AndroidRuntime using the same set of system properties, but only the system_server
            // and system apps are allowed to set them.
            //
            // NOTE: Most changes made here will need an equivalent change to
            // core/jni/AndroidRuntime.cpp
            // 設定語言
            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();

                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            // The system server should never make non-oneway calls
            Binder.setWarnOnBlocking(true);

            // Here we go!
            Slog.i(TAG, "Entered the Android system server!");
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if (!mRuntimeRestart) {
                MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
            }

            // In case the runtime switched since last boot (such as when
            // the old runtime was removed in an OTA), set the system
            // property so that it is in sync. We can | xq oqi't do this in
            // libnativehelper's JniInvocation::Init code where we already
            // had to fallback to a different runtime because it is
            // running as root and we need to be the system user to set
            // the property. http://b/11463182
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            // Enable the sampling profiler.
            if (SamplingProfilerIntegration.isEnabled()) {
                SamplingProfilerIntegration.start();
                mProfilerSnapshotTimer = new Timer();
                mProfilerSnapshotTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            SamplingProfilerIntegration.writeSnapshot("system_server", null);
                        }
                    }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
            }

            // Mmmmmm... more memory!
            VMRuntime.getRuntime().clearGrowthLimit();

            // The system server has to run all of the time, so it needs to be
            // as efficient as possible with its memory usage.
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

            // Some devices rely on runtime fingerprint generation, so make sure
            // we've defined it before booting further.
            Build.ensureFingerprintProperty();

            // Within the system server, it is an error to access Environment paths without
            // explicitly specifying a user.
            Environment.setUserRequired(true);

            // Within the system server, any incoming Bundles should be defused
            // to avoid throwing BadParcelableException.
            BaseBundle.setShouldDefuse(true);

            // Ensure binder calls into the system always run at foreground priority.
            BinderInternal.disableBackgroundScheduling(true);

            // Increase the number of binder threads in system_server
            BinderInternal.setMaxThreads(sMaxBinderThreads);

            // Prepare the main looper thread (this thread).
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();

            // Initialize native services.
            System.loadLibrary("android_servers");

            // Check whether we failed to shut down last time we tried.
            // This call may not return.
            performPendingShutdown();

            //=======以上方法就是初始化系統的一些環境,看方法名都知道干了什么====
            
            //=======以下開始實際干活了=====================================
            // Initialize the system context.
            // 創建系統句柄,有了該句柄后面的服務才能拿到系統資源
            createSystemContext();

            // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            // 啟動引導服務
            startBootstrapServices();
            // 啟動核心服務
            startCoreServices();
            // 啟動其他服務
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }

        // For debug builds, log event loop stalls to dropbox for analysis.
        if (StrictMode.conditionallyEnableDebugLogging()) {
            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
        }
        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
            final int MAX_UPTIME_MILLIS = 60 * 1000;
            if (uptimeMillis > MAX_UPTIME_MILLIS) {
                Slog.wtf(SYSTEM_SERVER_TIMING_TAG,
                        "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
            }
        }

        // Loop forever.
     	// 死回圈等待其他客戶端來獲取服務,回應客戶端請求,
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
5.1 createSystemContext()

初始化必要的SystemServer環境引數,比如系統時間、默認時區、語言、load一些Library等等, 初始化Looper,我們在主執行緒中使用到的looper就是在SystemServer中進行初始化的
初始化Context,只有初始化一個Context才能進行啟動Service等操作

private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

        final Context systemUiContext = activityThread.getSystemUiContext();
        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
    }

ActivitThread是在這里創建的,此處的Activitythread是系統的ActivityThread,和應用的ActivityThread有區別,下面給出區別,創建了ActivitThread就獲得了ResourcesManager,就可以獲得各種資源,

// frameworks\base\core\java\android\app\ActivityThread.java
public static ActivityThread systemMain() {
        // The system process on low-memory devices do not get to use hardware
        // accelerated drawing, since this can add too much overhead to the
        // process.
        if (!ActivityManager.isHighEndGfx()) {
            ThreadedRenderer.disable(true);
        } else {
            ThreadedRenderer.enableForegroundTrimming();
        }
    	// 創建ActivityThread,在ActivityThread中其實就是去獲取ResourcesManager,不在贅述,
        ActivityThread thread = new ActivityThread();
    	// 此處就體現了SystemServer的ActivityThread和應用的ActivityThread不同之處,
    	// 系統的attch傳入的是true, 而應用的是傳入的false
        thread.attach(true);
        return thread;
    }
private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
    	// 如果是應用走if,系統走else
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            mgr.releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
    	// 列印應用或者系統崩潰日志
        DropBox.setReporter(new DropBoxReporter());

        ......
    }

從上面可以看出:

  • 如果是應用,系統會監控應用的記憶體是否在于堆記憶體的3/4,如果大于3/4了,ActivityThread就會通知AMS,銷毀一些當前行程的activity,
  • 如果是系統,僅僅創建Context并且呼叫Application.onCreate()方法,

下面繼續分析Context的創建程序,

// 單例創建ContextImpl
public ContextImpl getSystemContext() {
        synchronized (this) {
            if (mSystemContext == null) {
                mSystemContext = ContextImpl.createSystemContext(this);
            }
            return mSystemContext;
        }
    }
// frameworks\base\core\java\android\app\ContextImpl.java
static ContextImpl createSystemContext(ActivityThread mainThread) {
        // 獲取系統包資訊
        LoadedApk packageInfo = new LoadedApk(mainThread);
        // 封裝系統ContextImpl
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null);
        // 設定系統資源
        context.setResources(packageInfo.getResources());
        // 更新配置資訊
        context.mResources.updateConfiguration(context.mResourcesManager. getConfiguration(), context.mResourcesManager.getDisplayMetrics());
        return context;
    }

LoadedApk()一看名字就知道是封裝Apk資訊的,他有兩個構造方法,如下:

// 封裝應用apk資訊
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
            CompatibilityInfo compatInfo, ClassLoader baseLoader,
            boolean securityViolation, boolean includeCode, boolean registerPackage) {

        mActivityThread = activityThread;
        setApplicationInfo(aInfo);
        mPackageName = aInfo.packageName;
        mBaseClassLoader = baseLoader;
        mSecurityViolation = securityViolation;
        mIncludeCode = includeCode;
        mRegisterPackage = registerPackage;
        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
    }

// 封裝系統apk資訊
LoadedApk(ActivityThread activityThread) {
        mActivityThread = activityThread;
        mApplicationInfo = new ApplicationInfo();
        mApplicationInfo.packageName = "android";
        mPackageName = "android";
        mAppDir = null;
        mResDir = null;
        mSplitAppDirs = null;
        mSplitResDirs = null;
        mOverlayDirs = null;
        mSharedLibraries = null;
        mDataDir = null;
        mDataDirFile = null;
        mDeviceProtectedDataDirFile = null;
        mCredentialProtectedDataDirFile = null;
        mLibDir = null;
        mBaseClassLoader = null;
        mSecurityViolation = false;
        mIncludeCode = true;
        mRegisterPackage = false;
        mClassLoader = ClassLoader.getSystemClassLoader();
        mResources = Resources.getSystem();
    }

至此,系統資源的句柄已經創建完成了,那我們來看看該句柄提供了哪些常用的方法,供外部呼叫來獲取系統資源,

// frameworks\base\core\java\android\app\ContextImpl.java
// 獲取系統的context
static ContextImpl createSystemContext(ActivityThread mainThread) {
        LoadedApk packageInfo = new LoadedApk(mainThread);
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null);
        context.setResources(packageInfo.getResources());
        context.mResources.updateConfiguration(context.mResourcesManager. getConfiguration(),context.mResourcesManager.getDisplayMetrics());
        return context;
    }

// 該Context是包含了系統主題資源,主要用于UI,在使用的時候,需要確保創建的系統ui Context是在相同的LoadedApk的context中
 static ContextImpl createSystemUiContext(ContextImpl systemContext) {
        final LoadedApk packageInfo = systemContext.mPackageInfo;
        ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, null, null, 0, null);
        context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, packageInfo.getCompatibilityInfo()));
        return context;
    }

// app的Context
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null);
        context.setResources(packageInfo.getResources());
        return context;
    }

// Activity的context
static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) {
        ......
        return context;
    }

至此,系統資源的創建和提供的介面已經敘述完畢,下面可以開始啟動服務了,

5.2 啟動引導服務

從方法名字就可以看出來該階段啟動的是其他服務依賴的關鍵服務,包含:安裝器、AMS、PMS、LightService、DMS、PKMS、UMS、OMS等,具體某個服務的啟動,后面寫Blog分析,

private void startBootstrapServices() {
        ......

        // Wait for installd to finish starting up so that it has a chance to
        // create critical directories such as /data/user with the appropriate
        // permissions.  We need this to complete before we initialize other services.
        traceBeginAndSlog("StartInstaller");
     	// 安裝器
        Installer installer = mSystemServiceManager.startService(Installer.class);
        traceEnd();

        // In some cases after launching an app we need to access device identifiers,
        // therefore register the device identifier policy before the activity manager.
        traceBeginAndSlog("DeviceIdentifiersPolicyService");
        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
        traceEnd();

        // Activity manager runs the show.
        traceBeginAndSlog("StartActivityManager");
    	// 啟動AMS
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        traceEnd();

        // Power manager needs to be started early because other services need it.
        // Native daemons may be watching for it to be registered so it must be ready
        // to handle incoming binder calls immediately (including being able to verify
        // the permissions for those calls).
        traceBeginAndSlog("StartPowerManager");
    	// 啟動PMS
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        traceEnd();

        // Now that the power manager has been started, let the activity manager
        // initialize power management features.
        traceBeginAndSlog("InitPowerManagement");
        mActivityManagerService.initPowerManagement();
        traceEnd();

        // Bring up recovery system in case a rescue party needs a reboot
        if (!SystemProperties.getBoolean("config.disable_noncore", false)) {
            traceBeginAndSlog("StartRecoverySystemService");
            mSystemServiceManager.startService(RecoverySystemService.class);
            traceEnd();
        }

        // Now that we have the bare essentials of the OS up and running, take
        // note that we just booted, which might send out a rescue party if
        // we're stuck in a runtime restart loop.
        RescueParty.noteBoot(mSystemContext);

        // Manages LEDs and display backlight so we need it to bring up the display.
        traceBeginAndSlog("StartLightsService");
        mSystemServiceManager.startService(LightsService.class);
        traceEnd();

        // Display manager is needed to provide display metrics before package manager
        // starts up.
        traceBeginAndSlog("StartDisplayManager");
    	// 顯示服務
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
        traceEnd();

        // We need the default display before we can initialize the package manager.
        traceBeginAndSlog("WaitForDisplay");
    	// 等待顯示階段
        mSystemServiceManager.startBootPhase(SystemService. PHASE_WAIT_FOR_DEFAULT_DISPLAY);
        traceEnd();

        // Only run "core" apps if we're encrypting the device.
        String cryptState = SystemProperties.get("vold.decrypt");
        if (ENCRYPTING_STATE.equals(cryptState)) {
            Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
            mOnlyCore = true;
        } else if (ENCRYPTED_STATE.equals(cryptState)) {
            Slog.w(TAG, "Device encrypted - only parsing core apps");
            mOnlyCore = true;
        }

        // Start the package manager.
        if (!mRuntimeRestart) {
            MetricsLogger.histogram(null, "boot_package_manager_init_start",
                    (int) SystemClock.elapsedRealtime());
        }
        traceBeginAndSlog("StartPackageManagerService");
    	// 啟動PKMS
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        traceEnd();
        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
            MetricsLogger.histogram(null, "boot_package_manager_init_ready",
                    (int) SystemClock.elapsedRealtime());
        }
        // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
        // A/B artifacts after boot, before anything else might touch/need them.
        // Note: this isn't needed during decryption (we don't have /data anyways).
        if (!mOnlyCore) {
            boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                    false);
            if (!disableOtaDexopt) {
                traceBeginAndSlog("StartOtaDexOptService");
                try {
                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
                } catch (Throwable e) {
                    reportWtf("starting OtaDexOptService", e);
                } finally {
                    traceEnd();
                }
            }
        }

        traceBeginAndSlog("StartUserManagerService");
    	// 啟動UMS
        mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
        traceEnd();

        // Initialize attribute cache used to cache resources from packages.
        traceBeginAndSlog("InitAttributerCache");
        AttributeCache.init(mSystemContext);
        traceEnd();

        // Set up the Application instance for the system process and get started.
        traceBeginAndSlog("SetSystemProcess");
		//啟動AMS系統行程的應用實體
        mActivityManagerService.setSystemProcess();
        traceEnd();

        // DisplayManagerService needs to setup android.display scheduling related policies
        // since setSystemProcess() would have overridden policies due to setProcessGroup
        mDisplayManagerService.setupSchedulerPolicies();

        // Manages Overlay packages
        traceBeginAndSlog("StartOverlayManagerService");
    	// 啟動OMS
        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
        traceEnd();

        // The sensor service needs access to package manager service, app ops
        // service, and permissions service, therefore we start it after them.
        // Start sensor service in a separate thread. Completion should be checked
        // before using it.
        mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
            BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
                    SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
            traceLog.traceBegin(START_SENSOR_SERVICE);
            startSensorService();
            traceLog.traceEnd();
        }, START_SENSOR_SERVICE);
    }
5.3 startCoreServices()

啟動核心服務比較簡單,主要啟動DropBoxManagerService、BatteryService、UsageStatsService和WebViewUpdateService,

 private void startCoreServices() {
        // Records errors and logs, for example wtf()
        traceBeginAndSlog("StartDropBoxManager");
        mSystemServiceManager.startService(DropBoxManagerService.class);
        traceEnd();

        traceBeginAndSlog("StartBatteryService");
        // Tracks the battery level.  Requires LightService.
        mSystemServiceManager.startService(BatteryService.class);
        traceEnd();

        // Tracks application usage stats.
        traceBeginAndSlog("StartUsageService");
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
        traceEnd();

        // Tracks whether the updatable WebView is in a ready state and watches for update installs.
        traceBeginAndSlog("StartWebViewUpdateService");
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
        traceEnd();
    }
5.4 startOtherServices()

啟動其他服務就不細說了,太多了,套路都一樣,主要來分析一下其他服務啟動完成之后,又干了什么,Launcher是如何被拉起來的,

private void startOtherServices() {
    ......
    // 前面象征性的放一點啟動其他服務代碼
    traceBeginAndSlog("StartKeyChainSystemService");
    mSystemServiceManager.startService(KeyChainSystemService.class);
    traceEnd();

    traceBeginAndSlog("StartSchedulingPolicyService");
    ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
    traceEnd();

    traceBeginAndSlog("StartTelecomLoaderService");
    mSystemServiceManager.startService(TelecomLoaderService.class);
    traceEnd();

    ......
    // 接下來會回呼各個服務啟動完成的回呼,在各個服務中可以執行回應的操作
    traceBeginAndSlog("MakeWindowManagerServiceReady");
    try {
        // WMS啟動結束回呼
        wm.systemReady();
    } catch (Throwable e) {
        reportWtf("making Window Manager Service ready", e);
    }
    
    // 方法最后!!!!
    // 方法最后!!!!
    // 方法最后!!!!
    // 在方法最后回呼AMS.SystemReady(),然后第一個引數傳入的是一個Runnable,
     mActivityManagerService.systemReady(() -> {
     	 Slog.i(TAG, "Making services ready");
         traceBeginAndSlog("StartActivityManagerReadyPhase");
         mSystemServiceManager.startBootPhase(
             SystemService.PHASE_ACTIVITY_MANAGER_READY);
         traceEnd();
         traceBeginAndSlog("StartObservingNativeCrashes");
         try {
             mActivityManagerService.startObservingNativeCrashes();
         } catch (Throwable e) {
             reportWtf("observing native crashes", e);
         }
         traceEnd();

         // No dependency on Webview preparation in system server. But this should
         // be completed before allowring 3rd party
         final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
         Future<?> webviewPrep = null;
         if (!mOnlyCore) {
             webviewPrep = SystemServerInitThreadPool.get().submit(() -> {
                 Slog.i(TAG, WEBVIEW_PREPARATION);
                 BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
                     SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                 traceLog.traceBegin(WEBVIEW_PREPARATION);
                 ConcurrentUtils.waitForFutureNoInterrupt(mZygotePreload, "Zygote preload");
                 mZygotePreload = null;
                 mWebViewUpdateService.prepareWebViewInSystemServer();
                 traceLog.traceEnd();
             }, WEBVIEW_PREPARATION);
         }

         traceBeginAndSlog("StartSystemUI");
         try {
             // 啟動systemui
             startSystemUi(context, windowManagerF);
         } catch (Throwable e) {
             reportWtf("starting System UI", e);
         }
         traceEnd();
         traceBeginAndSlog("MakeNetworkScoreReady");
         try {
             // 啟動網路評分機制
             if (networkScoreF != null) networkScoreF.systemReady();
         } catch (Throwable e) {
             reportWtf("making Network Score Service ready", e);
         }
         traceEnd();
         traceBeginAndSlog("MakeNetworkManagementServiceReady");
         try {
             if (networkManagementF != null) networkManagementF.systemReady();
         } catch (Throwable e) {
             reportWtf("making Network Managment Service ready", e);
         }
         ......
         // 設定啟動階段
         mSystemServiceManager.startBootPhase(
             SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
         traceEnd();

         ......
     }, BOOT_TIMINGS_TRACE_LOG);
}

ok, 繼續分析AMS ready之后干了什么,

// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
public void systemReady(final Runnable goingCallback, BootTimingsTraceLog traceLog) {
        traceLog.traceBegin("PhaseActivityManagerReady");
        synchronized(this) {
            // 由于goingCallback中還有服務沒有回呼systemReady,所以此處為false,繼續往下走,
            if (mSystemReady) {
                // If we're done calling all the receivers, run the next "boot phase" passed in by the SystemServer
                if (goingCallback != null) {
                    goingCallback.run();
                }
                return;
            }

        ......

        retrieveSettings();
        final int currentUserId;
        synchronized (this) {
            // 獲取當前用戶id,之后啟動launcher之前會判斷該用戶是否解鎖
            currentUserId = mUserController.getCurrentUserIdLocked();
            readGrantedUriPermissionsLocked();
        }

        // 回呼systemserver中的run(),通知其他服務SystemReady()
        if (goingCallback != null) goingCallback.run();
        ......

        synchronized (this) {
            // Only start up encryption-aware persistent apps; once user is
            // unlocked we'll come back around and start unaware apps
            // 啟動Manifest中配置了Persistent屬性的App
            startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

            // Start up initial activity.
            mBooting = true;
            // 啟動HomeActivity,此處其實是啟動的FallbcakHome Activity
            startHomeActivityLocked(currentUserId, "systemReady");

           ......
    }

6 啟動FallbcakHome和Launcher

可以看到FallbcakHome的category配置也是HOME,當系統開啟了FBE之后,SystemServer首先會啟動FallbackHome,在FallbackHome中檢查用戶是否解鎖,

<!-- packages\apps\Settings\AndroidManifest.xml -->
<!-- Triggered when user-selected home app isn't encryption aware -->
<activity android:name=".FallbackHome"
    android:excludeFromRecents="true"
    android:screenOrientation="nosensor"
    android:theme="@style/FallbackHome">
    <intent-filter android:priority="-1000">
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.HOME" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
public class FallbackHome extends Activity {
    private static final String TAG = "FallbackHome";
    private static final int PROGRESS_TIMEOUT = 2000;

    ......

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 注冊解鎖廣播
        registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
        maybeFinish();
    }

    ......

    private void maybeFinish() {
        // 如果用戶已經解鎖
        if (getSystemService(UserManager.class).isUserUnlocked()) {
            // 構建launcher的Intent
            final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_HOME);
            final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);
            if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
                if (UserManager.isSplitSystemUser()
                        && UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
                    return;
                }
                Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
                mHandler.sendEmptyMessageDelayed(0, 500);
            } else {
                Log.d(TAG, "User unlocked and real home found; let's go!");
                // 如果用戶已經解鎖,并且找到了Launcher的主界面,退出FallbackHome界面,
                getSystemService(PowerManager.class).userActivity(
                        SystemClock.uptimeMillis(), false);
                finish();
            }
        }
    }

    ......
}

FallbackHome請求finish自己,當然會請求執行onPasue方法: ActivityManagerService.activityPaused --》觸發呼叫到ActivityStack.activityPausedLocked --》 呼叫到 ActivityStack.completePauseLocked —》 呼叫到 ActivityStack.finishCurrentActivityLocked --》呼叫到 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked --》ActivityStack.resumeTopActivityUncheckedLocked -》 ActivityStack.resumeTopActivityInnerLocked -》 ActivityStack.resumeTopActivityInNextFocusableStack -》 ActivityStackSupervisor.resumeHomeStackTask -》最后呼叫到了ActivityManagerService.startHomeActivityLocked,

跟蹤呼叫堆疊會發現,如果當category是HOME被銷毀之后,最終又會呼叫到startHomeActivityLocked中,

此處呼叫startHomeActivityLocked的reason是noMoreActivities resumeHomeStackTask,沒有找到可回傳的Home主頁,然后mActivityStarter.startHomeActivityLocked再起啟動Home Activity就是啟動的Launcher的啟動頁了,

此次,Launcher界面終于啟動起來了,此篇分析系統啟動的程序的帖子終于寫完了,

后記

此帖子最初的學習資源來自羅升陽大神《Android系統源代碼情景分析(第三版)》,回顧寫此篇文章主要是作業需要用到了,再次翻讀此書,結合Android O的原始碼,更細,更深入的理解了原始碼的呼叫堆疊和方法含義,

**建議:**如果第一次看系統啟動流程,最好看低版本系統的原始碼,因為高版本的代碼google用了很多設計模式進行封裝和重構了,很多看著看著就不知道跳到哪里去了,低版本的代碼還是很容易看懂的,

參考文章:

羅升陽大神《Android系統源代碼情景分析(第三版)》(至于第幾版,最好買最新的吧,第三版分析的原始碼在當前專案Andorid P和Q原始碼中很多都被重構了)

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/308895.html

標籤:其他

上一篇:軟體著作權代碼提取60頁制作Word

下一篇:如何搭建一個簡單的QQ機器人(基于mirai)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more