Android系統(tǒng)啟動(dòng)學(xué)習(xí)記錄

1. init進(jìn)程啟動(dòng)

initshiAndroid系統(tǒng)用戶空間的第1個(gè)進(jìn)程锌畸,被賦予了很多重要職責(zé)毅整,比如創(chuàng)建孵化器Zygote嗦枢,屬性服務(wù)等阅悍。由多個(gè)源文件組成

1.1 引入init進(jìn)程

簡單說明init進(jìn)程的前幾步

啟動(dòng)電源以及系統(tǒng)啟動(dòng)

電源按下時(shí)引導(dǎo)芯片代碼從預(yù)定義處開始執(zhí)行朗伶。加載引導(dǎo)程序BootLoader到RAM中弦撩,然后執(zhí)行

引導(dǎo)程序BootLoader

是Android操作系統(tǒng)運(yùn)行前的一個(gè)小程序,主要用于拉起系統(tǒng)OS并運(yùn)行

Linux內(nèi)核啟動(dòng)

此時(shí)設(shè)置緩存论皆、被保護(hù)存儲(chǔ)器益楼、計(jì)劃列表、加載驅(qū)動(dòng)点晴。內(nèi)核完成系統(tǒng)設(shè)置后首先在系統(tǒng)文件中尋找init.rc文件感凤,并啟動(dòng)init進(jìn)程

init進(jìn)程啟動(dòng)

主要用于初始化啟動(dòng)屬性服務(wù),也用來啟動(dòng)Zygote進(jìn)程


1.2 init進(jìn)程的入口函數(shù)

init進(jìn)程的入口函數(shù)main粒督,抽取部分代碼陪竿,如下

main(第1部分)

int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (!strcmp(basename(argv[0]), "watchdogd")) {
        return watchdogd_main(argc, argv);
    }

    if (argc > 1 && !strcmp(argv[1], "subcontext")) {
        InitKernelLogging(argv);
        const BuiltinFunctionMap function_map;
        return SubcontextMain(argc, argv, &function_map);
    }

    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }

    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    if (is_first_stage) {
        boot_clock::time_point start_time = boot_clock::now();

        // Clear the umask.
        umask(0);

        clearenv();
        setenv("PATH", _PATH_DEFPATH, 1);
        // 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("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 };
        setgroups(arraysize(groups), groups);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);

        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));

        if constexpr (WORLD_WRITABLE_KMSG) {
            mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
        }

        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));

        // Mount staging areas for devices managed by vold
        // See storage config details at http://source.android.com/devices/storage/
        mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
              "mode=0755,uid=0,gid=1000");
        // /mnt/vendor is used to mount vendor-specific partitions that can not be
        // part of the vendor partition, e.g. because they are mounted read-write.
        mkdir("/mnt/vendor", 0755);

        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
        // talk to the outside world...
        InitKernelLogging(argv);
···

上面多段if處都是函數(shù)調(diào)用,在變量is_first_stage為真時(shí)屠橄,會(huì)創(chuàng)建和掛載tmpfs族跛、devpts捐康、proc、sysfs和selinuxfs共5種文件系統(tǒng)庸蔼,這些都是系統(tǒng)運(yùn)行時(shí)目錄解总,系統(tǒng)停止時(shí)會(huì)消失

main(第2部分)

···
property_init();
···
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(FATAL) << "epoll_create1 failed";
    }

    sigchld_handler_init();

    if (!IsRebootCapable()) {
        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
        // In that case, receiving SIGTERM will cause the system to shut down.
        InstallSigtermHandler();
    }

    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    set_usb_controller();

    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);

    subcontexts = InitializeSubcontexts();

    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();

    LoadBootScripts(am, sm);
···

開頭property_init函數(shù)對(duì)屬性進(jìn)行了初始化

末尾處start_property_service函數(shù)啟動(dòng)屬性服務(wù)

中間sigchld_handler_init函數(shù)用于設(shè)置子進(jìn)程信號(hào)處理函數(shù),主要用于防止init進(jìn)程的子進(jìn)程成為僵尸進(jìn)程姐仅。為了防止僵尸進(jìn)程的出現(xiàn)花枫,系統(tǒng)會(huì)在子進(jìn)程暫停和終止的時(shí)候發(fā)出SIGCHLD信號(hào),這個(gè)函數(shù)就是用來接收信號(hào)的

結(jié)尾處LoadBootScripts解析init.rc文件掏膏,講完main函數(shù)再分析

延申:僵尸進(jìn)程

進(jìn)程在OS中使用fork函數(shù)創(chuàng)建劳翰。父進(jìn)程fork子進(jìn)程,在子進(jìn)程終止后馒疹,如果父進(jìn)程不知道子進(jìn)程已經(jīng)終止佳簸,這時(shí)雖然子進(jìn)程已經(jīng)退出,到那時(shí)系統(tǒng)進(jìn)程仍然保留了它的信息颖变,這個(gè)子進(jìn)程就被稱作僵尸進(jìn)程生均。由于系統(tǒng)進(jìn)程表是有限的,如果被耗盡腥刹,則無法創(chuàng)建新進(jìn)程

main(第3部分)

···
while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;

        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }

        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            if (!shutting_down) {
                auto next_process_restart_time = RestartProcesses();

                // If there's a process that needs restarting, wake up in time for that.
                if (next_process_restart_time) {
                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
                                           *next_process_restart_time - boot_clock::now())
                                           .count();
                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
                }
            }

            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }

        epoll_event 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) {
            ((void (*)()) ev.data.ptr)();
        }
    }

    return 0;
}

中間處的RestartProcess函數(shù)就是用來重啟Zygote的马胧。因?yàn)榧偃鏸nit進(jìn)程的子進(jìn)程Zygote終止了,sigchld_handler_init函數(shù)內(nèi)部經(jīng)過層層調(diào)用最終會(huì)找到Zygote進(jìn)程并移除所有的Zygote進(jìn)程的信息衔峰,再重啟Zygote服務(wù)的腳本佩脊,其他init進(jìn)程子進(jìn)程的原理也是類似的


1.3 解析init.rc

這是一個(gè)非常重要的配置文件,是由Android初始化語言編寫的垫卤,主要包含5種類型的語句:Action威彰、Command、Service穴肘、Option和Import歇盼,配置代碼如下

init.rc

···
on init
    sysclktz 0

    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /default.prop /dev/urandom
···
on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain
···

這里截取一部分,on init和on bool是Action類型的語句梢褐,格式如下

on <trigger> [&&<trigger>]* //設(shè)置觸發(fā)器
   <command>
   <command> //動(dòng)作觸發(fā)之后的命令

為了分析如何創(chuàng)建Zygote旺遮,我們主要查看Service類型語句赵讯,格式如下

service <name> <pathname> [<argument>]*  //<service的名字> <執(zhí)行路徑> <傳遞參數(shù)>

<option>
<option> //是service的修飾詞盈咳,影響何時(shí),怎樣啟動(dòng)Service

我們分析Zygote啟動(dòng)腳本則在init.zygoteXX.rc中定義边翼,以64位處理器為例鱼响,分析zygote64.rc

zygote64.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

大概分析,Service用于通知组底,init進(jìn)程創(chuàng)建名為zygote的進(jìn)程丈积,這個(gè)進(jìn)程執(zhí)行程序的路徑為 /system/bin/app_process64筐骇,后面的代碼是要傳給app_process64的參數(shù)。class main指的是Zygote的classname為main


1.4 解析Service類型語句

init.rc中Action類型語句和Service類型語句都有相應(yīng)的類來解析江滨,Action類型采用ActionParser解析铛纬,Service類型采用ServiceParser解析,這里主要分析Zygote唬滑,所以只介紹ServiceParser告唆。其實(shí)現(xiàn)代碼在service.cpp中,解析Service用到兩個(gè)函數(shù):一個(gè)是ParseSection晶密,會(huì)解析Service的rc文件擒悬,搭建Service的架子。另一個(gè)是ParselineSection稻艰,解析子項(xiàng)懂牧,代碼如下

service

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);
    return Success();
}

Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
    return service_ ? service_->ParseLine(std::move(args)) : Success();
}

Result<Success> ServiceParser::EndSection() {
    if (service_) {
        Service* old_service = service_list_->FindService(service_->name());
        if (old_service) {
            if (!service_->is_override()) {
                return Error() << "ignored duplicate definition of service '" << service_->name()
                               << "'";
            }

            service_list_->RemoveService(*old_service);
            old_service = nullptr;
        }

        service_list_->AddService(std::move(service_));
    }

    return Success();
}

第1個(gè)if處,判斷Service是否有name與可執(zhí)行程序

第2個(gè)if處尊勿,檢查Service的name是否有效

中間處std::make_unique<Service>函數(shù)構(gòu)建一個(gè)Service對(duì)象

解析完數(shù)據(jù)后僧凤,最后調(diào)用EndSection函數(shù),函數(shù)里又有AddService函數(shù)

service的AddService

void ServiceList::AddService(std::unique_ptr<Service> service) {
    services_.emplace_back(std::move(service));
}

此函數(shù)將Service對(duì)象添加進(jìn)鏈表


1.5 init啟動(dòng)Zygote

接下來說說init如何啟動(dòng)Service元扔,主要講解啟動(dòng)Zygote這個(gè)Service拼弃,在init.rc中有如下配置代碼

init.rc

···
on nonencrypted
    class_start main
    class_start late_start
···

其中class_start是一個(gè)是一個(gè)Command,對(duì)應(yīng)的函數(shù)為do_class_start摇展,啟動(dòng)了那些classname為main的Service吻氧,我們?cè)谏衔闹繸ygote的classname就是main,所以這里就是用來啟動(dòng)Zygote的咏连。do_class_start函數(shù)在builtins.cpp中定義,如下

builtins的do_class_start

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])) {
            if (auto result = service->StartIfNotDisabled(); !result) {
                LOG(ERROR) << "Could not start service '" << service->name()
                           << "' as part of class '" << args[1] << "': " << result.error();
            }
        }
    }
    return Success();
}

for循環(huán)會(huì)遍歷ServiceList鏈表祟滴,找到classname為main的Zygote振惰,并執(zhí)行service.cpp里的StartIfNotDisabled函數(shù),如下

service的StartIfNotDisabled

Result<Success> Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return Success();
}

第一個(gè)if處垄懂,如果Service沒有在其對(duì)應(yīng)的rc文件中設(shè)置disabled選項(xiàng)骑晶,則會(huì)調(diào)用Start函數(shù)啟動(dòng)Service,Zygote對(duì)應(yīng)的init.zygote64.rc中并沒有設(shè)置disabled選項(xiàng)草慧,因此我們來查看Start函數(shù)

service的Start

Result<Success> Service::Start() {
    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
    // 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));

    // Running processes require no additional work --- if they're in the
    // process of exiting, we've ensured that they will immediately restart
    // on exit, unless they are ONESHOT. For ONESHOT service, if it's in
    // stopping status, we just set SVC_RESTART flag so it will get restarted
    // in Reap().
    if (flags_ & SVC_RUNNING) {
        if ((flags_ & SVC_ONESHOT) && disabled) {
            flags_ |= SVC_RESTART;
        }
        // It is not an error to try to start a service that is already running.
        return Success();
    }

    bool needs_console = (flags_ & SVC_CONSOLE);
    if (needs_console) {
        if (console_.empty()) {
            console_ = default_console;
        }

        // Make sure that open call succeeds to ensure a console driver is
        // properly registered for the device node
        int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
        if (console_fd < 0) {
            flags_ |= SVC_DISABLED;
            return ErrnoError() << "Couldn't open console '" << console_ << "'";
        }
        close(console_fd);
    }

    struct stat sb;
    if (stat(args_[0].c_str(), &sb) == -1) {
        flags_ |= SVC_DISABLED;
        return ErrnoError() << "Cannot find '" << args_[0] << "'";
    }
···
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        pid = fork();
    }

    if (pid == 0) {
        umask(077);
···
        if (!ExpandArgsAndExecv(args_)) {
            PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
        }

        _exit(127);
    }
···
   return Success();
}

第一個(gè)if處判斷Service是否已經(jīng)運(yùn)行桶蛔,如果運(yùn)行則不再啟動(dòng)

如果上面程序一直都沒有啟動(dòng)子進(jìn)程,末尾處pid = fork()時(shí)就會(huì)創(chuàng)建子進(jìn)程并返回pid值漫谷,如果pid值為0仔雷,說明當(dāng)前代碼邏輯在子進(jìn)程運(yùn)行

最后一個(gè)if處,調(diào)用ExpandArgsExecv函數(shù),為真時(shí)則啟動(dòng)子進(jìn)程碟婆,并進(jìn)入該Service的main函數(shù)电抚,如果該Service是Zygote,上文我們知道Zygote的執(zhí)行路徑為 /system/bin/app_process64竖共,對(duì)應(yīng)的文件為app_main.cpp蝙叛,這樣就會(huì)進(jìn)入app_main.cpp的main函數(shù),也就是Zygote的main函數(shù)公给,如下

app_main

int main(int argc, char* const argv[])
{
···
if (zygote){ 
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote); 
    } else { 
        fprintf(stderr, "Error: no class name or --zygote supplied.\n"); 
        app_usage(); 
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); 
    } 
}

可以看到runtime的start函數(shù)啟動(dòng)Zygote甥温,由此,Zygote正式啟動(dòng)


1.6 屬性服務(wù)

Windows的注冊(cè)表管理器中采用鍵值對(duì)形式記錄用戶軟件的一些信息妓布,即使系統(tǒng)重啟姻蚓,也可以根據(jù)記錄進(jìn)行初始化。Android的屬性服務(wù)即是類似的機(jī)制

init進(jìn)程啟動(dòng)時(shí)會(huì)啟動(dòng)屬性服務(wù)匣沼,并為其分配內(nèi)存狰挡,用來存儲(chǔ)屬性,需要時(shí)則直接讀取释涛。在上文中我們提到init.cpp的main函數(shù)中與屬性服務(wù)相關(guān)的代碼如下

init的main

property_init();
start_property_service();

用于初始化屬性服務(wù)和啟動(dòng)屬性服務(wù)加叁,首先我們來看屬性服務(wù)配置的初始化和啟動(dòng)

屬性服務(wù)配置的初始化和啟動(dòng)

property_init函數(shù)的具體實(shí)現(xiàn)如下,在property_service.cpp文件中

property_service的property_init

void property_init() {
    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
    CreateSerializedPropertyInfo();
    if (__system_property_area_init()) {
        LOG(FATAL) << "Failed to initialize property area";
    }
    if (!property_info_area.LoadDefaultPath()) {
        LOG(FATAL) << "Failed to load serialized property info file";
    }
}

__system_property_area_init用來初始化屬性內(nèi)存區(qū)域唇撬,接下來查看start_property_service函數(shù)的具體代碼

property_service的start_property_service

void start_property_service() {
    selinux_callback cb;
    cb.func_audit = SelinuxAuditCallback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    property_set("ro.property_service.version", "2");

    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, nullptr);
    if (property_set_fd == -1) {
        PLOG(FATAL) << "start_property_service socket creation failed";
    }

    listen(property_set_fd, 8);

    register_epoll_handler(property_set_fd, handle_property_set_fd);
}

CreateSocket函數(shù)創(chuàng)建了非阻塞的Socket它匕,下面調(diào)用listen方法對(duì)參數(shù)property_set_fd進(jìn)行監(jiān)聽,這樣Socket就成為server窖认,也就是屬性服務(wù)

listen方法的第二個(gè)參數(shù)8意味著屬性服務(wù)最多可以同時(shí)為8個(gè)試圖設(shè)置屬性服務(wù)的用戶提供服務(wù)

最后一行用epoll監(jiān)聽property_set_fd豫柬,當(dāng)有數(shù)據(jù)到來時(shí),init進(jìn)程將調(diào)用handle_property_set_fd來進(jìn)行處理

在Linux新內(nèi)核中扑浸,epoll用來替換select烧给,是為了處理大量文件描述符而做了改進(jìn)的poll,底層為紅黑樹喝噪,查找效率高础嫡,顯著增強(qiáng)CPU利用率,只有當(dāng)少量數(shù)據(jù)時(shí)酝惧,epoll效率才和select差不多

服務(wù)處理客戶端請(qǐng)求

上面我們了解了榴鼎,屬性服務(wù)接收到客戶端請(qǐng)求時(shí),會(huì)調(diào)用handle_property_set_fd函數(shù)進(jìn)行處理

property_service的handle_property_set_fd

static void handle_property_set_fd() {
···
    switch (cmd) {
    case PROP_MSG_SETPROP: {
        char prop_name[PROP_NAME_MAX];
        char prop_value[PROP_VALUE_MAX];

        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
          return;
        }

        prop_name[PROP_NAME_MAX-1] = 0;
        prop_value[PROP_VALUE_MAX-1] = 0;

        const auto& cr = socket.cred();
        std::string error;
        uint32_t result =
            HandlePropertySet(prop_name, prop_value, socket.source_context(), cr, &error);
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << prop_name << "' to '" << prop_value
                       << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": "
                       << error;
        }

        break;
      }
···

最后一個(gè)if處的上一句晚唇,HandlePropertySet函數(shù)做了封裝巫财,如下

property_service的HandlePropertySet

uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                           const std::string& source_context, const ucred& cr, std::string* error) {
···
    if (StartsWith(name, "ctl.")) {
        if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
            *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
                                  value.c_str());
            return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
        }

        HandleControlMessage(name.c_str() + 4, value, cr.pid);
        return PROP_SUCCESS;
    }

    const char* target_context = nullptr;
    const char* type = nullptr;
    property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);

    if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
        *error = "SELinux permission check failed";
        return PROP_ERROR_PERMISSION_DENIED;
    }

    if (type == nullptr || !CheckType(type, value)) {
        *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
                              (type ?: "(null)"));
        return PROP_ERROR_INVALID_VALUE;
    }
···
    if (name == "selinux.restorecon_recursive") {
        return PropertySetAsync(name, value, RestoreconRecursiveAsync, error);
    }

    return PropertySet(name, value, error);
}

系統(tǒng)屬性分為控制屬性和普通屬性∪绷粒控制屬性用來執(zhí)行一些命令翁涤,比如開機(jī)動(dòng)畫。上面代碼第1個(gè)if和第2個(gè)if處萌踱,檢查是否以ctl.開頭葵礼,說明是控制屬性,緊接著HandleControlMessage設(shè)置控制屬性

第3個(gè)if處檢查是否是普通屬性并鸵,是的話最后會(huì)調(diào)用PropertySet函數(shù)對(duì)普通屬性進(jìn)行修改鸳粉。這里分析如何修改普通屬性

property_service的PropertySet

static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
    size_t valuelen = value.size();

    if (!IsLegalPropertyName(name)) {
        *error = "Illegal property name";
        return PROP_ERROR_INVALID_NAME;
    }
···
    prop_info* pi = (prop_info*) __system_property_find(name.c_str());
    if (pi != nullptr) {
        // ro.* properties are actually "write-once".
        if (StartsWith(name, "ro.")) {
            *error = "Read-only property was already set";
            return PROP_ERROR_READ_ONLY_PROPERTY;
        }

        __system_property_update(pi, value.c_str(), valuelen);
    } else {
        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
        if (rc < 0) {
            *error = "__system_property_add failed";
            return PROP_ERROR_SET_FAILED;
        }
    }

    // Don't write properties to disk until after we have read all default
    // properties to prevent them from being overwritten by default values.
    if (persistent_properties_loaded && StartsWith(name, "persist.")) {
        WritePersistentProperty(name, value);
    }
    property_changed(name, value);
    return PROP_SUCCESS;
}

第1個(gè)if處,判斷屬性是否合法园担,下面的(prop_info*) __system_property_find函數(shù)用于從屬性存儲(chǔ)空間查找該屬性

第2個(gè)if處届谈,為真代表屬性存在,以ro.開頭表示只讀不能修改弯汰,直接返回

第3個(gè)if下面__system_property_update()表示如果屬性存在就更新屬性值艰山,緊接著else塊里的邏輯表示如果不存在則添加該屬性

最后一個(gè)if處,是對(duì)以persist.開頭的屬性進(jìn)行了處理


1.7 init進(jìn)程啟動(dòng)總結(jié)

總的來說做了下面三件事

  1. 創(chuàng)建和掛載啟動(dòng)所需的文件目錄

  2. 初始化和啟動(dòng)屬性服務(wù)

  3. 解析init.rc配置文件并啟動(dòng)Zygote進(jìn)程


2. Zygote進(jìn)程啟動(dòng)過程

了解其啟動(dòng)過程咏闪,先了解Zygote是什么

2.1 Zygote概述

Zygote曙搬,亦稱孵化器。DVM鸽嫂、ART纵装、應(yīng)用程序進(jìn)程以及運(yùn)行系統(tǒng)的關(guān)鍵服務(wù)的SystemServer都是他創(chuàng)建的。它通過fork形式創(chuàng)建這些進(jìn)程据某。由于Zygote啟動(dòng)時(shí)會(huì)創(chuàng)建DVM或ART橡娄,因此通過fork創(chuàng)建的應(yīng)用程序進(jìn)程和SystemServer進(jìn)程可以在內(nèi)部獲取一個(gè)DVM或ART的實(shí)例副本

從上文我們知道Zygote是在init進(jìn)程啟動(dòng)時(shí)創(chuàng)建的,原名就是app_process癣籽,在Android.mk中定義挽唉。Zygote進(jìn)程啟動(dòng)后,Linux系統(tǒng)下的pctrl系統(tǒng)會(huì)調(diào)用app_process筷狼,將其名稱替換為Zygote

2.2 Zygote啟動(dòng)腳本

在init.rc文件中采用Import語句來引入Zygote啟動(dòng)腳本橱夭,這些啟動(dòng)腳本都是由Android初始化語言來編寫的:

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

所以init.rc并不會(huì)直接引入一個(gè)固定文件,而是根據(jù)ro.zygote的內(nèi)容來引入不同文件的桑逝。由32位和64位程序的不同棘劣,ro.zygote的屬性取值有以下四種

  1. init.zygote32.rc

  2. init.zygote32_64.rc

  3. init.zygote64.rc

  4. init.zygote64_32.rc

為了更好理解這些啟動(dòng)腳本,我們回顧一下上文提到的Service類型語句的格式

service <name> <pathname> [<argument>]*  //<service的名字> <執(zhí)行路徑> <傳遞參數(shù)>

<option>
<option> //是service的修飾詞楞遏,影響何時(shí)茬暇,怎樣啟動(dòng)Service

接下來分別了解這些啟動(dòng)腳本

init.zygote32.rc

只支持32位,內(nèi)容如下

service zygote /system/bin/app_process -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

進(jìn)程名稱為zygote寡喝,執(zhí)行程序?yàn)閍pp_process糙俗,classname為main,如果audioserver预鬓、cameraserver巧骚、media等進(jìn)程終止了,就需要進(jìn)行重啟

init.zygote32_64.rc
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    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

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

兩個(gè)Service語句,說明啟動(dòng)兩個(gè)Zygote進(jìn)程劈彪,一個(gè)名為zygote竣蹦,啟動(dòng)程序?yàn)閍pp_process32,作為主模式沧奴。另一個(gè)名稱為zygote_secondary痘括,執(zhí)行程序?yàn)閍pp_process64,作為輔模式

另外64位處理與上面兩種類似滔吠,這里不贅述了


2.3 Zygote進(jìn)程啟動(dòng)過程介紹

由上面可知init啟動(dòng)Zygote時(shí)主要調(diào)用app_main.cpp的main函數(shù)中的runtime的start方法來啟動(dòng)Zygote進(jìn)程的纲菌。時(shí)序圖如下,我們就從app_main.cpp的main函數(shù)開始分析


image.png

app_main的main

int main(int argc, char* const argv[])
{
···
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
···
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

Zygote進(jìn)程都是通過fork自身來創(chuàng)建子進(jìn)程的疮绷,這樣Zygote進(jìn)程和其子進(jìn)程都可以進(jìn)入app_main.cpp的main函數(shù)翰舌,因此main函數(shù)中為了區(qū)分當(dāng)前運(yùn)行在哪個(gè)進(jìn)程,在第1個(gè)if處判斷參數(shù)是否包含--zygote冬骚,若包含則說明main函數(shù)運(yùn)行在Zygote進(jìn)程中灶芝,將其設(shè)置為true。同理下面都是參數(shù)的判斷唉韭,為真則同樣為它們?cè)O(shè)置參數(shù)

最后一個(gè)if處上文已經(jīng)分析過夜涕,如果為true,就調(diào)用runtime的start函數(shù)属愤,在AndroidRuntime.cpp文件中

AndroidRuntime的start

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
···
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    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.
     */
    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 != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        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
        }
    }
···
}

可以看到開頭調(diào)用startVm函數(shù)來創(chuàng)建Java虛擬機(jī)女器,第2個(gè)if處的startReg函數(shù)為Java虛擬機(jī)注冊(cè)JNI方法

第1個(gè)for循環(huán)上面的classNameStr的值是com.android.internal.os.ZygoteInit,并緊接著在for循環(huán)下面賦值給slashClassName

之后又以slashClassName為參數(shù)調(diào)用FindClass方法找到ZygoteInit住诸,又在第1個(gè)else塊中找到main方法驾胆。最終會(huì)在第2個(gè)else塊中通過JNI調(diào)用main方法

使用JNI是因?yàn)閆ygoteInit的main方法是用Java寫的,當(dāng)前邏輯在Native中贱呐,需要通過JNI調(diào)用Java丧诺,這樣就從Native進(jìn)入了Java框架層,即Zygote開創(chuàng)了Java框架層奄薇,該main方法如下

ZygoteInit的main

public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();
···
            zygoteServer.registerServerSocketFromEnv(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            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();
            }
···
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

開頭處驳阎,zygoteServer調(diào)用registerServerSocketFromEnv創(chuàng)建一個(gè)Server端的Socket

第1個(gè)if處,preload方法預(yù)加載類和資源

第2個(gè)if處馁蒂,forkSystemServer創(chuàng)建SystemServer進(jìn)程镜廉,這樣系統(tǒng)的服務(wù)也會(huì)由SystemServer啟動(dòng)

第1個(gè)catch語句上調(diào)用runSelectLoop方法等待AMS請(qǐng)求創(chuàng)建新的應(yīng)用程序進(jìn)程

由此吧凉,我們可知ZygoteInit的main方法主要做了4件事

  1. 創(chuàng)建一個(gè)Server端的Socket

  2. 預(yù)加載類資源

  3. 啟動(dòng)SystemServer進(jìn)程

  4. 等待AMS請(qǐng)求創(chuàng)建新的應(yīng)用程序進(jìn)程

這里我們主要分析第1赞咙,3俱饿,4步

第1步 創(chuàng)建一個(gè)Server端的Socket

看看registerServerSocketFromEnv做了什么

ZygoteServer的registerServerSocketFromEnv

void registerServerSocketFromEnv(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                mServerSocket = new LocalServerSocket(fd);
                mCloseSocketFd = true;
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

開頭處拼接SOCKET名稱,其中ANDROID_SOCKET_PREFIX的值為ANDROID_SOCKET_沮脖,socketName為zygote金矛,因此fullSocketName的值為ANDROID_SOCKET_zygote

第1個(gè)if處芯急,將fullSocketName轉(zhuǎn)為環(huán)境變量值,并緊接著parseInt轉(zhuǎn)換為文件描述符參數(shù)

第2個(gè)try處驶俊,創(chuàng)建文件操作符娶耍,傳入上述文件描述符參數(shù)。緊接著創(chuàng)建LocalServerSocket废睦,也就是服務(wù)端Socket伺绽,將文件操作符作為參數(shù)傳入

在Zygote進(jìn)程將SystemServer進(jìn)程啟動(dòng)后养泡,就會(huì)在這個(gè)服務(wù)器端的Socket上等待AMS請(qǐng)求Zygote進(jìn)程來創(chuàng)建新的應(yīng)用程序進(jìn)程

第3步 啟動(dòng)SystemServer進(jìn)程

看看forkSystemServer做了什么

ZygoteInit的forkSystemServer

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
···        
        /* Hardcoded command line to start the system server */
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs;

        int pid;

        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
···
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

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

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

最開始有個(gè)args數(shù)組嗜湃,保存啟動(dòng)SystemServer的參數(shù)

第2個(gè)try處,用parsedArgs將args數(shù)組封裝并供給下面的Zygote調(diào)用forkSystemServer方法澜掩,其內(nèi)部最終會(huì)通過fork函數(shù)在當(dāng)前進(jìn)程里創(chuàng)建一個(gè)子進(jìn)程购披,也就是SystemServer進(jìn)程

如果其返回的pid為0,則代表當(dāng)前代碼運(yùn)行在新創(chuàng)建的子進(jìn)程中肩榕,通過return的handleSystemServerProcess來處理SystemServer進(jìn)程

第4步 等待AMS請(qǐng)求創(chuàng)建新的應(yīng)用程序進(jìn)程

ZygoteServer的runSelectLoop

啟動(dòng)SystemServer進(jìn)程后刚陡,會(huì)執(zhí)行runSelectLoop方法,如下

Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        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;
                }

                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    try {
                        ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);

                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this
                            // stage if processOneCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This shows up as
                            // a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                        if (!mIsForkChild) {
                            // We're in the server so any exception here is one that has taken place
                            // pre-fork while processing commands or reading / writing from the
                            // control socket. Make a loud noise about any such exceptions so that
                            // we know exactly what failed and why.

                            Slog.e(TAG, "Exception executing zygote command: ", e);

                            // Make sure the socket is closed so that the other end knows immediately
                            // that something has gone wrong and doesn't time out waiting for a
                            // response.
                            ZygoteConnection conn = peers.remove(i);
                            conn.closeSocket();

                            fds.remove(i);
                        } else {
                            // We're in the child so any exception caught here has happened post
                            // fork and before we execute ActivityThread.main (or any other main()
                            // method). Log the details of the exception and bring down the process.
                            Log.e(TAG, "Caught post-fork exception in child process.", e);
                            throw e;
                        }
                    } finally {
                        // Reset the child flag, in the event that the child process is a child-
                        // zygote. The flag will not be consulted this loop pass after the Runnable
                        // is returned.
                        mIsForkChild = false;
                    }
                }
            }
        }
    }

開頭創(chuàng)建了兩個(gè)集合株汉,緊接著添加進(jìn)一個(gè)mServerSocket筐乳,就是我們上面第一步創(chuàng)建的服務(wù)端Socket,進(jìn)入while循環(huán)無限等待AMS的請(qǐng)求

第1個(gè)for循環(huán)處乔妈,通過遍歷fds存儲(chǔ)的信息轉(zhuǎn)移到pollFds數(shù)組中

第2個(gè)for循環(huán)處蝙云,又遍歷pollFds數(shù)組,如果i為0路召,說明服務(wù)器和Socket鏈接上了勃刨,即AMS與Zygote進(jìn)程建立了鏈接

第2個(gè)for循環(huán)的第2個(gè)if處,通過acceptCommandPeer方法得到ZygoteConnection類并添加到Socket鏈接列表peers中股淡,接著將ZygoteConnection的fd添加到fds列表中身隐,以便接收AMS發(fā)送的請(qǐng)求

如果i不為0,下面則分別進(jìn)行了在子線程或服務(wù)端的異常處理


2.4 Zygote進(jìn)程啟動(dòng)總結(jié)

Zygote進(jìn)程啟動(dòng)共做了如下幾件事

  1. 創(chuàng)建AppRuntime并調(diào)用其start方法唯灵,啟動(dòng)Zygote進(jìn)程

  2. 創(chuàng)建Java虛擬機(jī)并為Java虛擬機(jī)注冊(cè)JNI方法

  3. 通過JNI調(diào)用ZygoteInit的main函數(shù)進(jìn)入Zygote的Java框架層

  4. 通過registerZygoteSocket方法創(chuàng)建服務(wù)器端Socket贾铝,并通過runSelectLoop方法等待AMS的請(qǐng)求來創(chuàng)建新的應(yīng)用程序進(jìn)程

  5. 啟動(dòng)SystemServer進(jìn)程


3. SystemServer處理過程

SystemServer進(jìn)程主要用于創(chuàng)建系統(tǒng)服務(wù),我們熟知的AMS埠帕、WMS和PMS都是由它創(chuàng)建的

3.1 Zygote處理SystemServer進(jìn)程

上文講解了Zygote啟動(dòng)SystemServer的進(jìn)程忌傻,接下來學(xué)習(xí)Zygote是如何處理SystemServer進(jìn)程的,先看看時(shí)序圖


image.png

上文提到過搞监,在ZygoteInit的forkSystemServer方法中水孩,啟動(dòng)了SystemServer進(jìn)程

ZygoteInit的forkSystemServer

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
···
    if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

SystemServer進(jìn)程復(fù)制了Zygote進(jìn)程的地址空間,因此也會(huì)用到Zygote進(jìn)程創(chuàng)建的Socket琐驴,但是由于Socket對(duì)SystemServer沒有用處俘种,所以需要調(diào)用closeServerSocket關(guān)閉該Socket秤标,緊接著調(diào)用handleSystemServerProcess方法

ZygoteInit的handleSystemServerProcess

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
···
        if (parsedArgs.invokeWith != null) {
···
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }

        /* should never reach here */
    }

在else塊中調(diào)用createPathClassLoader方法創(chuàng)建PathClassLoader,最后返回了zygoteInit方法宙刘,代碼如下

ZygoteInit的zygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        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();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

return的上一句調(diào)用nativeZygoteInit方法苍姜,用于啟動(dòng)Binder線程池,這樣悬包,SystemServer進(jìn)程就可以使用Binder與其他進(jìn)程進(jìn)行通信

return語句調(diào)用的方法用于進(jìn)入SystemServer的main方法

下面展開介紹這兩部分

啟動(dòng)Binder線程池

nativeZygoteInit是一個(gè)Native方法衙猪,因此我們先了解其對(duì)應(yīng)的JNI文件,即AndroidRuntime.cpp布近,如下

AndroidRuntime的ZygoteInit

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

通過JNI的gMethods數(shù)組垫释,可以看出nativeZygoteInit方法對(duì)應(yīng)的是JNI文件AndroidRuntime.cpp的com_android_internal_os_ZygoteInit_nativeZygoteInit函數(shù),如下

AndroidRuntime的nativeZygoteInit

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

這里gCurRuntime是AndroidRuntime類型的指針撑瞧,具體指向AndroidRuntime的子類AppRuntime棵譬,它在app_main.cpp中定義,我們來看AppRuntime的onZygoteInit方法预伺,如下

app_main的onZygoteInit

virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

startThreadPool用于啟動(dòng)一個(gè)Binder線程池订咸,這樣SystemServer進(jìn)程就可以使用Binder與其他進(jìn)程進(jìn)行通信

所以我們知道ZygoteInit的nativeZygoteInit函數(shù)主要用于啟動(dòng)Binder線程池

進(jìn)入SystemServer的main方法

回到ZygoteInit的zygoteInit函數(shù)的代碼,最后return的是RuntimeInit的
applicationInit函數(shù)酬诀,代碼如下

RuntimeInit的applicationInit

protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // 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);

        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);

        final Arguments args = new Arguments(argv);

        // 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
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

注釋的大意就是在應(yīng)用程序調(diào)用System.exit()時(shí)應(yīng)立即終止程序脏嚷,不然會(huì)出現(xiàn)問題,最后返回的是findStaticMain函數(shù)瞒御,我們查看一下

RuntimeInit的findStaticMain

protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        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.
         */
        return new MethodAndArgsCaller(m, argv);
    }

第1個(gè)try語句中父叙,反射forName得到的className是com.android.server.SystemServer,返回的cl為SystemServer中的main方法

第2個(gè)try語句中葵腹,cl.getMethod找到的是SystemServer里的main方法高每,賦值給m

最后return處又根據(jù)m調(diào)用MethodAndArgsCaller方法

RuntimeInit的MethodAndArgsCaller

static class MethodAndArgsCaller 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 {
                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);
            }
        }
    }

這里是一個(gè)靜態(tài)內(nèi)部類,構(gòu)造器中的mMethd就是SystemServer的main方法践宴,在run方法中調(diào)用invoke后鲸匿,SystemServer的main方法就會(huì)被動(dòng)態(tài)調(diào)用,SystemServer進(jìn)程就進(jìn)入了SystemServer的main方法


3.2 解析SystemServer進(jìn)程

下面查看SystemServer的main方法

SystemServer的main

public static void main(String[] args) {
        new SystemServer().run();
    }

跟進(jìn)run方法

SystemServer的run

private void run() {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
        try {
···
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            SystemServiceRegistry.sEnableServiceNotFoundWtf = true;

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

            // Allow heap / perf profiling.
            initZygoteChildHeapProfiling();
···
            // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.start();
            // Attach JVMTI agent if this is a debuggable build and the system property is set.
···
        } finally {
            t.traceEnd();  // InitBeforeStartServices
        }

        // Setup the default WTF handler
        RuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);

        // Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);
            startCoreServices(t);
            startOtherServices(t);
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }
···
        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

開頭調(diào)用prepareMainLooper創(chuàng)建Looper阻肩,緊接著loadLibary加載動(dòng)態(tài)庫libandroid_service.so

下面創(chuàng)建的SystemServiceManager會(huì)對(duì)系統(tǒng)服務(wù)進(jìn)行創(chuàng)建带欢、啟動(dòng)和生命周期管理

第2個(gè)try語句中,startBootstrapServices方法用SystemServiceManager啟動(dòng)了ActivityManagerService烤惊,PackageManagerService乔煞、PowerManagerService等服務(wù)

startCoreServices方法中則啟動(dòng)了DropBoxManagerService、BatteryServices柒室、UsageStatsServices和WebViewUpdateServices

startOtherServices方法中則啟動(dòng)了CameraServices渡贾、AlarmManagerServices、VrManagerServices等服務(wù)

上述服務(wù)的父類均為SystemService雄右。由方法名可以看出官方把系統(tǒng)服務(wù)分為了三種類型:引導(dǎo)服務(wù)空骚、核心服務(wù)和其他服務(wù)

這些啟動(dòng)服務(wù)的邏輯是類似的纺讲,這里舉例PowerManagerService,代碼如下

PowerManagerService

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

可以看出SystemServiceManager的startService方法啟動(dòng)了PowerManagerService囤屹,startService方法如下

public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    }

開頭處調(diào)用add方法將PowerManagerService添加到mServices中熬甚,完成注冊(cè)工作

try語句中調(diào)用onStart函數(shù)完成啟動(dòng)PowerManagerService


3.3 SystemServer進(jìn)程總結(jié)

SystemServer進(jìn)程創(chuàng)建后,主要做了3件事

  1. 啟動(dòng)Binder線程池肋坚,與其他進(jìn)程通信

  2. 創(chuàng)建SystemServiceManager乡括,用于對(duì)系統(tǒng)的服務(wù)進(jìn)行創(chuàng)建、啟動(dòng)和生命周期管理

  3. 啟動(dòng)各種系統(tǒng)服務(wù)


4. Launcher啟動(dòng)過程

到了最后一步智厌,來學(xué)習(xí)Launcher的啟動(dòng)流程

4.1 Launcher概述

系統(tǒng)啟動(dòng)的最后一步是啟動(dòng)一個(gè)應(yīng)用程序用來顯示系統(tǒng)中已經(jīng)安裝的應(yīng)用诲泌,這個(gè)應(yīng)用程序就叫做Launcher。啟動(dòng)過程中會(huì)請(qǐng)求PackageManagerService返回系統(tǒng)中已經(jīng)安裝應(yīng)用的信息峦剔,并將這些信息封裝成一個(gè)快捷圖標(biāo)列表顯示在系統(tǒng)屏幕上档礁,這樣用戶就可以通過點(diǎn)擊快捷圖標(biāo)來啟動(dòng)相應(yīng)的應(yīng)用程序

所以通俗來說角钩,Launcher就是Android系統(tǒng)的桌面吝沫,它的作用主要有以下兩點(diǎn)

  1. 作為Android系統(tǒng)啟動(dòng)器,啟動(dòng)應(yīng)用程序

  2. 作為Android系統(tǒng)桌面递礼,用于顯示和管理應(yīng)用程序的快捷圖標(biāo)或者其他桌面組件


4.2 Launcher啟動(dòng)過程介紹

SystemServer啟動(dòng)過程中會(huì)啟動(dòng)PackageManagerService惨险,PackageManagerService啟動(dòng)后會(huì)將系統(tǒng)中的應(yīng)用程序安裝完成。在此之前已經(jīng)啟動(dòng)的AMS會(huì)將Launcher啟動(dòng)起來脊髓,時(shí)序圖如下


image.png

啟動(dòng)Launcher的入口為AMS的systemReady方法辫愉,在SystemServer的startOtherServices方法中被調(diào)用

SystemServer的startOtherServices

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
···
            mActivityManagerService.systemReady(() -> {
            Slog.i(TAG, "Making services ready");
            t.traceBegin("StartActivityManagerReadyPhase");
            mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);
···

下面查看AMS的systemReady方法做了什么

ActivityManagerService的systemReady

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
···
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
···
}

調(diào)用了ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法

ActivityStackSupervisor的resumeFocusedStackTopActivityLocked

boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
···
        if (r == null || !r.isState(RESUMED)) {
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        }
···
        return false;
    }

調(diào)用ActivityStack的resumeTopActivityUncheckedLocked方法,ActivityStack是用來描述堆棧的将硝,方法如下

ActivityStack的resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }

        return result;
    }

try語句中把resumeTopActivityInnerLocked方法的值給了result

ActivityStack的resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
···
         return isOnHomeDisplay() &&
                mStackSupervisor.resumeHomeStackTask(prev, reason);
    }
···

調(diào)用ActivityStackSupervisor的resumeHomeStackTask方法

ActivityStackSupervisor的resumeHomeStackTask

boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
···
        if (r != null && !r.finishing) {
            moveFocusableActivityStackToFrontLocked(r, myReason);
            return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
        }
        return mService.startHomeActivityLocked(mCurrentUser, myReason);
    }

調(diào)用了AMS的startHomeActivityLocked方法恭朗,如下

ActivityManagerService的startHomeActivityLocked

boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instr == null) {
                intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                // For ANR debugging to verify if the user activity is the one that actually
                // launched.
                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                mActivityStartController.startHomeActivity(intent, aInfo, myReason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

第一個(gè)if處的mFactoryTest代表系統(tǒng)的運(yùn)行模式,系統(tǒng)運(yùn)行模式分為三種:工廠模式依疼、低級(jí)工廠模式痰腮、高級(jí)工廠模式。mTopAction用來描述第一個(gè)被啟動(dòng)Activiy組件的Action律罢,默認(rèn)值為Intent.ACTION_MAIN膀值。因此if的條件含義為當(dāng)mFactoryTest的模式為低級(jí)工廠模式,且mTopAction為空時(shí)误辑,返回false

下面的Intent調(diào)用了getHomeIntent方法沧踏,代碼如下

ActivityManagerService的getHomeIntent

Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
    }

這里創(chuàng)建intent,并將mTopAction和mTopData傳入巾钉。mTopAction的值為Intent.ACTION_MAIN翘狱,并且如果系統(tǒng)運(yùn)行模式不是低級(jí)工廠模式,則將intent的Category設(shè)置為Intent.CATEGORY_HOME砰苍,最后返回該Intent

回到ActivityManagerService的startHomeActivityLocked方法潦匈,我們假設(shè)系統(tǒng)運(yùn)行模式不是低級(jí)工廠模式踏烙,在第3個(gè)if處判斷符合Action為Intent.ACTION_MAIN、Category為Intent.CATEGORY_HOME的應(yīng)用程序是否已經(jīng)啟動(dòng)历等,如果沒啟動(dòng)則調(diào)用下面的startHomeActivity啟動(dòng)該應(yīng)用程序讨惩。這個(gè)被啟動(dòng)的應(yīng)用程序就是Launcher,不信我們可以查看Launcher的AndroidMenifest文件

Launcher的AndroidManifest

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.launcher"
    android:sharedUserId="android.uid.shared"
    android:sharedUserLabel="@string/uid_name">
···
        <activity
            android:name="Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/Theme"
            android:screenOrientation="nosensor"
            android:windowSoftInputMode="stateUnspecified|adjustPan">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME"/>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY" />
            </intent-filter>
        </activity>
···
    </application>
</manifest>

我們看到<intent-filter>標(biāo)簽里設(shè)置了android.intent.category.HOME屬性寒屯,這樣他就成了主Activity

再次回到上面ActivityManagerService的startHomeActivityLocked荐捻,我們知道如果Launcher未啟動(dòng)則調(diào)用startHomeActivity啟動(dòng)Launcher,代碼如下

ActivityStartController的startHomeActivity

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
        mSupervisor.moveHomeStackTaskToTop(reason);
        mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
                .setOutActivity(tmpOutRecord)
                .setCallingUid(0)
                .setActivityInfo(aInfo)
                .execute();
···
        }
    }

這里將Launcher放入HomeStack中寡夹,HomeStack是在ActivityStackSupervisor中定義的用于存儲(chǔ)Launcher的變量处面,接著調(diào)用obtainStarter來啟動(dòng)Launcher,后面的過程與Activity的啟動(dòng)類似菩掏,最后進(jìn)入Launcher的onCreate方法魂角,到這里L(fēng)auncher完成了啟動(dòng)


4.3 Launcher中應(yīng)用圖標(biāo)顯示過程

Launcher啟動(dòng)后會(huì)做很多工作,作為桌面它會(huì)顯示應(yīng)用程序圖標(biāo)智绸,與應(yīng)用程序開發(fā)有所關(guān)聯(lián)野揪,圖標(biāo)作為應(yīng)用程序的入口,我們有必要接著來學(xué)習(xí)

先看Launcher的onCreate方法

Launcher的onCreate

protected void onCreate(Bundle savedInstanceState) {
···
        LauncherAppState app = LauncherAppState.getInstance(this);
        mOldConfig = new Configuration(getResources().getConfiguration());
        mModel = app.setLauncher(this);
        initDeviceProfile(app.getInvariantDeviceProfile());
···
        if (!mModel.startLoader(currentScreen)) {
            if (!internalStateHandled) {
                // If we are not binding synchronously, show a fade in animation when
                // the first page bind completes.
                mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
            }
        }
···
}

開頭處獲取LauncherAppState的實(shí)例瞧栗,并調(diào)用setLauncher傳給mModel斯稳,setLauncher方法如下

LauncherAppState的setLauncher

LauncherModel setLauncher(Launcher launcher) {
        getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
        mModel.initialize(launcher);
        return mModel;
    }

mModel會(huì)調(diào)用initialize方法,如下

LauncherModel的initialize

public void initialize(Callbacks callbacks) {
        synchronized (mLock) {
            Preconditions.assertUIThread();
            mCallbacks = new WeakReference<>(callbacks);
        }
    }

這里會(huì)將Callbacks迹恐,也就是傳入的Launcher封裝成弱引用

回到Launcher的onCreate方法挣惰,末尾的if語句中調(diào)用了startLoader方法,如下

LauncherModel的startLoader

public boolean startLoader(int synchronousBindPage) {
        // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
        synchronized (mLock) {
            // Don't bother to start the thread if we know it's not going to do anything
            if (mCallbacks != null && mCallbacks.get() != null) {
                final Callbacks oldCallbacks = mCallbacks.get();
                // Clear any pending bind-runnables from the synchronized load process.
                mUiExecutor.execute(oldCallbacks::clearPendingBinds);

                // If there is already one running, tell it to stop.
                stopLoader();
                LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
                        mBgAllAppsList, synchronousBindPage, mCallbacks);
                if (mModelLoaded && !mIsLoaderTaskRunning) {
                    // Divide the set of loaded items into those that we are binding synchronously,
                    // and everything else that is to be bound normally (asynchronously).
                    loaderResults.bindWorkspace();
                    // For now, continue posting the binding of AllApps as there are other
                    // issues that arise from that.
                    loaderResults.bindAllApps();
                    loaderResults.bindDeepShortcuts();
                    loaderResults.bindWidgets();
                    return true;
                } else {
                    startLoaderForResults(loaderResults);
                }
            }
        }
        return false;
    }

開頭創(chuàng)建了一個(gè)隊(duì)列殴边,接著在同步塊中進(jìn)行操作憎茂,調(diào)用execute方法從同步加載過程中清除所有掛起的綁定可運(yùn)行對(duì)象

第2個(gè)if處,會(huì)根據(jù)當(dāng)前是否已經(jīng)加載過數(shù)據(jù)锤岸,而決定是直接綁定UI竖幔,還是去加載數(shù)據(jù)。如果已經(jīng)加載過數(shù)據(jù)能耻,則調(diào)用bindWorkspace赏枚、bindAllApps、bindDeepShortcuts晓猛、bindWidgets四個(gè)重要方法饿幅,分別加載Workspace(即桌面啟動(dòng)后看到的主界面)、AllApps(即當(dāng)前安裝的所有app)戒职、DeepShortcuts(即長按圖標(biāo)后懸浮的界面)栗恩、Widgets(天氣溫度等小部件)。我們來看看沒有加載過數(shù)據(jù)時(shí)對(duì)應(yīng)的最后一個(gè)else語句里的startLoaderForResults方法做了什么

LauncherModel的startLoaderForResults

public void startLoaderForResults(LoaderResults results) {
        synchronized (mLock) {
            stopLoader();
            mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
            runOnWorkerThread(mLoaderTask);
        }
    }

這個(gè)LoaderTask是個(gè)Runnable方法洪燥,我們看看這個(gè)類

LoaderTask的run

public void run() {
···
        TraceHelper.beginSection(TAG);
        try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
            TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
            loadWorkspace();

            verifyNotStopped();
            TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
            mResults.bindWorkspace();

            // Notify the installer packages of packages with active installs on the first screen.
            TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast");
            sendFirstScreenActiveInstallsBroadcast();

            // Take a break
            TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
            waitForIdle();
            verifyNotStopped();

            // second step
            TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
            loadAllApps();

            TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
            verifyNotStopped();
            mResults.bindAllApps();

            verifyNotStopped();
            TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
            updateIconCache();

            // Take a break
            TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
            waitForIdle();
            verifyNotStopped();

            // third step
            TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts");
            loadDeepShortcuts();

            verifyNotStopped();
            TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts");
            mResults.bindDeepShortcuts();

            // Take a break
            TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle");
            waitForIdle();
            verifyNotStopped();

            // fourth step
            TraceHelper.partitionSection(TAG, "step 4.1: loading widgets");
            mBgDataModel.widgetsModel.update(mApp, null);

            verifyNotStopped();
            TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets");
            mResults.bindWidgets();

            transaction.commit();
        } catch (CancellationException e) {
            // Loader stopped, ignore
            TraceHelper.partitionSection(TAG, "Cancelled");
        }
        TraceHelper.endSection(TAG);
    }

我們可以看到每一個(gè)partitionSection方法里都標(biāo)明了步驟磕秤,這里不贅述乳乌,觀察一下還可以發(fā)現(xiàn)步驟和步驟之間基本都有waitForIdle方法和verifyNotStopped方法

waitForIdle方法用于等待上個(gè)步驟的UI線程加載完畢,即上個(gè)步驟UI沒展示前市咆,不進(jìn)行下一步的數(shù)據(jù)準(zhǔn)備

verifyNotStopped用于檢查該加載過程是否已經(jīng)被取消汉操,這意味著這個(gè)加載過程是可以中途取消的

最后調(diào)用commit方法提交,然后endSection結(jié)束

由于我們介紹的是App應(yīng)用圖標(biāo)的顯示蒙兰,所以我們?cè)俅芜M(jìn)入LoaderTask類的loadAllApps方法查看

LoaderTask的loadAllApps

private void loadAllApps() {
        final List<UserHandle> profiles = mUserManager.getUserProfiles();

        // Clear the list of apps
        mBgAllAppsList.clear();
        for (UserHandle user : profiles) {
            // Query for the set of apps
            final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
            // Fail if we don't have any apps
            // TODO: Fix this. Only fail for the current user.
            if (apps == null || apps.isEmpty()) {
                return;
            }
            boolean quietMode = mUserManager.isQuietModeEnabled(user);
            // Create the ApplicationInfos
            for (int i = 0; i < apps.size(); i++) {
                LauncherActivityInfo app = apps.get(i);
                // This builds the icon bitmaps.
                mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
            }
        }

        if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
            // get all active sessions and add them to the all apps list
            for (PackageInstaller.SessionInfo info :
                    mPackageInstaller.getAllVerifiedSessions()) {
                mBgAllAppsList.addPromiseApp(mApp.getContext(),
                        PackageInstallerCompat.PackageInstallInfo.fromInstallingState(info));
            }
        }

        mBgAllAppsList.added = new ArrayList<>();
    }

開頭for循環(huán)查找app集合磷瘤,對(duì)于無app的特殊情況進(jìn)行了處理,接著就是把圖標(biāo)bitmaps放入集合中

最后一個(gè)if就是獲取所有活動(dòng)的會(huì)話放入集合

我們回到上面看看LauncherModel的startLoader中的bindAllApps方法做了什么

LoaderResults的bindAllApps

public void bindAllApps() {
        // shallow copy
        @SuppressWarnings("unchecked")
        final ArrayList<AppInfo> list = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();

        Runnable r = new Runnable() {
            public void run() {
                Callbacks callbacks = mCallbacks.get();
                if (callbacks != null) {
                    callbacks.bindAllApplications(list);
                }
            }
        };
        mUiExecutor.execute(r);
    }

run方法里如果callbacks不為空則調(diào)用bindAllApplications方法綁定搜变,其中的參數(shù)list就是開始創(chuàng)建的ArrayList采缚,集合的泛型恰好就是AppInfo,和LoaderTask的loadAllApps中的集合泛型一致挠他,我們回顧上文可知callback指向的是Launcher扳抽,我們查看Launcher的bindAllApplications方法

Launcher的bindAllApplications

public void bindAllApplications(ArrayList<AppInfo> apps) {
        mAppsView.getAppsStore().setApps(apps);

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.bindAllApplications(apps);
        }
    }

mAppsView是AllAppsContainerView的對(duì)象,調(diào)用了getAppsStore方法殖侵,我們來看看這個(gè)方法做了什么

AllAppsContainerView的getAppsStore

public AllAppsStore getAppsStore() {
        return mAllAppsStore;
    }

返回了一個(gè)mAllAppsStore對(duì)象贸呢,是AllAppsStore類的實(shí)例,所以上面的setApps方法就在這個(gè)類中愉耙,跟進(jìn)

AllAppsStore的setApps

public void setApps(List<AppInfo> apps) {
        mComponentToAppMap.clear();
        addOrUpdateApps(apps);
    }

點(diǎn)進(jìn)addOrUpdateApps方法

AllAppsStore的addOrUpdateApps

public void addOrUpdateApps(List<AppInfo> apps) {
        for (AppInfo app : apps) {
            mComponentToAppMap.put(app.toComponentKey(), app);
        }
        notifyUpdate();
    }

最后調(diào)用addOrUpdateApps把包含應(yīng)用信息的列表放入一個(gè)Map中

回到AllAppsContainerView類中贮尉,還有一個(gè)適配器Adpater拌滋,里面還有一個(gè)setup方法朴沿,我們看看這個(gè)方法的內(nèi)容

AllAppsContainerView的setup

void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
            appsList.updateItemFilter(matcher);
            recyclerView = (AllAppsRecyclerView) rv;
            recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
            recyclerView.setApps(appsList, mUsingTabs);
            recyclerView.setLayoutManager(layoutManager);
            recyclerView.setAdapter(adapter);
            recyclerView.setHasFixedSize(true);
            // No animations will occur when changes occur to the items in this RecyclerView.
            recyclerView.setItemAnimator(null);
            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
            recyclerView.addItemDecoration(focusedItemDecorator);
            adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
            applyVerticalFadingEdgeEnabled(verticalFadingEdge);
            applyPadding();
        }

可以看出其實(shí)我們的界面也是recyclerView,顯示app列表败砂,調(diào)用setApps方法顯示應(yīng)用程序快捷圖標(biāo)的列表就會(huì)顯示在屏幕上

到這里赌渣,Launcher的啟動(dòng)流程就結(jié)束了


5. Android系統(tǒng)啟動(dòng)流程

結(jié)合前面四點(diǎn),簡單總結(jié)流程如下

啟動(dòng)電源以及系統(tǒng)啟動(dòng)

電源按下時(shí)引導(dǎo)芯片代碼從預(yù)定義處開始執(zhí)行昌犹。加載引導(dǎo)程序BootLoader到RAM中坚芜,然后執(zhí)行

引導(dǎo)程序BootLoader

是Android操作系統(tǒng)運(yùn)行前的一個(gè)小程序,主要用于拉起系統(tǒng)OS并運(yùn)行

Linux內(nèi)核啟動(dòng)

此時(shí)設(shè)置緩存斜姥、被保護(hù)存儲(chǔ)器鸿竖、計(jì)劃列表、加載驅(qū)動(dòng)铸敏。內(nèi)核完成系統(tǒng)設(shè)置后首先在系統(tǒng)文件中尋找init.rc文件缚忧,并啟動(dòng)init進(jìn)程

init進(jìn)程啟動(dòng)

主要用于初始化啟動(dòng)屬性服務(wù),也用來啟動(dòng)Zygote進(jìn)程

Zygote進(jìn)程啟動(dòng)

創(chuàng)建Java虛擬機(jī)并為Java虛擬機(jī)注冊(cè)JNI方法杈笔,創(chuàng)建服務(wù)器端Socket闪水,啟動(dòng)SystemServer進(jìn)程

SystemServer進(jìn)程啟動(dòng)

啟動(dòng)Binder線程池和SystemServiceManager,并且啟動(dòng)各種系統(tǒng)服務(wù)

Launcher啟動(dòng)

被SystemServer進(jìn)程啟動(dòng)的AMS會(huì)啟動(dòng)Launcher蒙具,Launcher啟動(dòng)后會(huì)將已經(jīng)安裝的應(yīng)用的快捷圖標(biāo)顯示到桌面

流程圖

image.png

歡迎指正球榆。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末朽肥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子持钉,更是在濱河造成了極大的恐慌衡招,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件每强,死亡現(xiàn)場離奇詭異蚁吝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舀射,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門窘茁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脆烟,你說我怎么就攤上這事山林。” “怎么了邢羔?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵驼抹,是天一觀的道長。 經(jīng)常有香客問我拜鹤,道長框冀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任敏簿,我火速辦了婚禮明也,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惯裕。我一直安慰自己温数,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布蜻势。 她就那樣靜靜地躺著撑刺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪握玛。 梳的紋絲不亂的頭發(fā)上够傍,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音挠铲,去河邊找鬼冕屯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛市殷,可吹牛的內(nèi)容都是我干的愕撰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼搞挣!你這毒婦竟也來了带迟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤囱桨,失蹤者是張志新(化名)和其女友劉穎仓犬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舍肠,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搀继,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翠语。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叽躯。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肌括,靈堂內(nèi)的尸體忽然破棺而出点骑,到底是詐尸還是另有隱情,我是刑警寧澤谍夭,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布黑滴,位于F島的核電站,受9級(jí)特大地震影響紧索,放射性物質(zhì)發(fā)生泄漏袁辈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一珠漂、第九天 我趴在偏房一處隱蔽的房頂上張望晚缩。 院中可真熱鬧,春花似錦甘磨、人聲如沸橡羞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莺债,卻和暖如春滋觉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背齐邦。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工椎侠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人措拇。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓我纪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浅悉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容