啟動(dòng)流程
1.按下電源,系統(tǒng)啟動(dòng)
當(dāng)電源鍵按下時(shí),引導(dǎo)芯片代碼(匯編指令)會(huì)從預(yù)定的地方(固化在ROM)開始執(zhí)行,將引導(dǎo)程序 BootLoader 加載到 RAM中,然后執(zhí)行
2.引導(dǎo)程序 BootLoader
BootLoader 是在 Android 操作系統(tǒng)開始前的一個(gè)小程序,主要作用是把系統(tǒng)OS拉起來并運(yùn)行
位置:\bootable\bootloader
3.Linux內(nèi)核啟動(dòng)
當(dāng) Linux系統(tǒng)被 BootLoader 程序拉起,內(nèi)核啟動(dòng)時(shí),會(huì)設(shè)置緩存,被保護(hù)存儲(chǔ)器,計(jì)劃列表,加載驅(qū)動(dòng)等工作,在內(nèi)核完成系統(tǒng)設(shè)置后,會(huì)啟動(dòng)進(jìn)程,主要涉及3個(gè)特殊的進(jìn)程,idle進(jìn)程(PID = 0), init進(jìn)程(PID = 1)和kthreadd進(jìn)程(PID = 2),這三個(gè)進(jìn)程是內(nèi)核的基礎(chǔ)
- idle進(jìn)程:是 init 進(jìn)程和 kthreadd 進(jìn)程的父進(jìn)程,是Linux系統(tǒng)第一個(gè)進(jìn)程。
- init進(jìn)程:是Android系統(tǒng)應(yīng)用程序的始祖,app都是直接或間接以它為父進(jìn)程,是Linux系統(tǒng)第一個(gè)用戶進(jìn)程
- kthreadd進(jìn)程:是Linux系統(tǒng)內(nèi)核管家,所有的內(nèi)核線程都是直接或間接以它為父進(jìn)程
idle進(jìn)程的啟動(dòng)是用匯編語言寫的,對(duì)應(yīng)文件是/kernel/fusion/4.9/arch/arm64/kernel/head.S
注意:不同版本的android文件夾名稱不同
具體的也看不懂,根據(jù)大佬說的會(huì)跳轉(zhuǎn)到 /kernel/fusion/4.9/include/linux/start_kernel.h
這個(gè)頭文件對(duì)應(yīng)的實(shí)現(xiàn)在 /kernel/fusion/4.9/init/main.c
asmlinkage __visible void __init start_kernel(void)
{
......
ftrace_init();
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
在 rest_init 函數(shù)中開啟了 init 進(jìn)程和 kthreadd 進(jìn)程
static noinline void __ref rest_init(void)
{
int pid;
#if (MP_CACHE_DROP==1)
int pid_kthre_drop_cache;
struct sched_param para;
struct task_struct *p;
int srch_retval;
#endif
#ifdef CONFIG_MP_PLATFORM_PHY_ADDRESS_MORE_THAN_2G_SET_MOVABLE_DEBUG
testAddrTranslation();
#endif
//啟動(dòng)RCU機(jī)制,這個(gè)與后面的rcu_read_lock和rcu_read_unlock是配套的,用于多核同步
rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
//用kernel_thread方式創(chuàng)建init進(jìn)程,將 kernel_init函數(shù)指針傳遞過去創(chuàng)建 init 進(jìn)程
kernel_thread(kernel_init, NULL, CLONE_FS);
// 設(shè)定NUMA系統(tǒng)的默認(rèn)內(nèi)存訪問策略
numa_default_policy();
//同上,用kernel_thread方式創(chuàng)建kthreadd進(jìn)程
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
#if (MP_CACHE_DROP==1)
pid_kthre_drop_cache=kernel_thread(kthre_drop_cache, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
srch_retval = -ESRCH;
p = pid_kthre_drop_cache ? find_task_by_vpid(pid_kthre_drop_cache) : current;
if (p != NULL)
{
srch_retval = (p->policy == SCHED_FIFO || p->policy == SCHED_RR)?1:0;
para.sched_priority=srch_retval;
//use default and set min
srch_retval = sched_setscheduler(p, p->policy, ¶);
}
rcu_read_unlock();
#endif
//打開RCU讀取鎖,在此期間無法進(jìn)行進(jìn)程切換
rcu_read_lock();
// 獲取kthreadd的進(jìn)程描述符,期間需要檢索進(jìn)程pid的使用鏈表,所以要加鎖
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
//關(guān)閉RCU讀取鎖
rcu_read_unlock();
// 之前kernel_init函數(shù)調(diào)用了wait_for_completion(&kthreadd_done),這里調(diào)用complete就是通知kernel_init進(jìn)程kthreadd進(jìn)程已創(chuàng)建完成,可以繼續(xù)執(zhí)行
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
//current表示當(dāng)前進(jìn)程,當(dāng)前0號(hào)進(jìn)程init_task設(shè)置為idle進(jìn)程
init_idle_bootup_task(current);
//0號(hào)進(jìn)程主動(dòng)請求調(diào)度,讓出cpu,1號(hào)進(jìn)程kernel_init將會(huì)運(yùn)行,并且禁止搶占
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
// 這個(gè)函數(shù)會(huì)調(diào)用cpu_idle_loop()使得idle進(jìn)程進(jìn)入自己的事件處理循環(huán)
cpu_startup_entry(CPUHP_ONLINE);
}
4.init 進(jìn)程啟動(dòng)
init 進(jìn)程是 Android 系統(tǒng)中用戶第一個(gè)進(jìn)程,進(jìn)程號(hào)為1,它被賦予了很多極其重要的工作職責(zé),比如創(chuàng)建 Zygote(孵化器)和屬性服務(wù)等,init是由多個(gè)源文件共同組成的,這些文件位置:system/core/init
中,可用ps命令查看到:
上面說到在rest_init 函數(shù)中通過 kernel_thread(kernel_init, NULL, CLONE_FS); 方法來啟動(dòng)init進(jìn)程
kernel_thread方法位置:/kernel/fusion/4.9/kernel/fork.c
kernel_thread 的第一個(gè)參數(shù)是一個(gè)函數(shù)指針,會(huì)在創(chuàng)建進(jìn)程后執(zhí)行,第三個(gè)參數(shù)是創(chuàng)建進(jìn)程的方式
參數(shù)名 | 表示 |
---|---|
CLONE_PARENT | 創(chuàng)建的子進(jìn)程的父進(jìn)程是調(diào)用者的父進(jìn)程,新進(jìn)程與創(chuàng)建它的進(jìn)程成了“兄弟”而不是“父子” |
CLONE_FS | 子進(jìn)程與父進(jìn)程共享相同的文件系統(tǒng),包括root、當(dāng)前目錄、umask |
CLONE_FILES | 子進(jìn)程與父進(jìn)程共享相同的文件描述符(file descriptor)表 |
CLONE_NEWNS | 在新的namespace啟動(dòng)子進(jìn)程,namespace描述了進(jìn)程的文件hierarchy |
CLONE_SIGHAND | 子進(jìn)程與父進(jìn)程共享相同的信號(hào)處理(signal handler)表 |
CLONE_PTRACE | 若父進(jìn)程被trace,子進(jìn)程也被trace |
CLONE_UNTRACED | 若父進(jìn)程被trace,子進(jìn)程不被trace |
CLONE_VFORK | 父進(jìn)程被掛起,直至子進(jìn)程釋放虛擬內(nèi)存資源 |
CLONE_VM | 子進(jìn)程與父進(jìn)程運(yùn)行于相同的內(nèi)存空間 |
CLONE_PID | 子進(jìn)程在創(chuàng)建時(shí)PID與父進(jìn)程一致 |
CLONE_THREAD | Linux 2.4中增加以支持POSIX線程標(biāo)準(zhǔn),子進(jìn)程與父進(jìn)程共享相同的線程群 |
_do_fork 函數(shù)用于創(chuàng)建進(jìn)程,它首先調(diào)用 copy_process() 創(chuàng)建新進(jìn)程,然后調(diào)用 wake_up_new_task() 將進(jìn)程放入運(yùn)行隊(duì)列中并啟動(dòng)新進(jìn)程,在創(chuàng)建完成后會(huì)回調(diào) /kernel/fusion/4.9/init/main.c
文件中的kernel_init 方法
static int __ref kernel_init(void *unused)
{
......
if (ramdisk_execute_command) { // ramdisk_execute_command 的值為"/init"
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
這個(gè)方法會(huì)去找根目錄下的 init(ramdisk_execute_command) 可執(zhí)行文件,并運(yùn)行它,如果在根目錄找不到就會(huì)去找 /sbin/init、/etc/init、/bin/init、/bin/sh 目錄下的可執(zhí)行文件,只要這些應(yīng)用程序有一個(gè)啟動(dòng)了,其他就不啟動(dòng)了
而這個(gè) init 可執(zhí)行文件是 system/core/init/init.cpp
編譯后生成的
int main(int argc, char** argv) {
//注釋一:進(jìn)行ueventd/watchdogd跳轉(zhuǎn)及環(huán)境變量設(shè)置
//basename是C庫中的一個(gè)函數(shù),得到特定的路徑中的最后一個(gè)'/'后面的內(nèi)容,比如/sdcard/miui_recovery/backup,得到的結(jié)果是backup
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
......
if (REBOOT_BOOTLOADER_ON_PANIC) {//將各種信號(hào)量,如SIGABRT,SIGBUS等的行為設(shè)置為SA_RESTART,一旦監(jiān)聽到這些信號(hào)即執(zhí)行重啟系統(tǒng)
InstallRebootSignalHandlers();
}
//之前準(zhǔn)備工作時(shí)將INIT_SECOND_STAGE設(shè)置為true,已經(jīng)不為nullptr,所以is_first_stage為false
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) { //如果是第一次執(zhí)行
boot_clock::time_point start_time = boot_clock::now();
// 清理 umask
// 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.
// 注釋二:創(chuàng)建和掛載啟動(dòng)所需要的文件目錄
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
......
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
// talk to the outside world...
// 注釋三:初始化Kernel 的 Log,外界可獲取 Kernel 的打印日志
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) { //掛載分區(qū)設(shè)備
LOG(FATAL) << "Failed to mount required partitions early ...";
}
....
// 注釋四:初始化selinux策略
SelinuxSetupKernelLogging();
SelinuxInitialize();
// We're in the kernel domain, so re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (selinux_android_restorecon("/init", 0) == -1) { //restorecon命令用來恢復(fù)SELinux文件屬性即恢復(fù)文件的安全上下文
PLOG(FATAL) << "restorecon failed of /init failed";
}
setenv("INIT_SECOND_STAGE", "true", 1); //設(shè)置環(huán)境變量
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args); //重新執(zhí)行main方法
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
}
/***************** 第二部分 ******************/
// At this point we're in the second stage of init.
InitKernelLogging(argv); //初始化 kernel 日志
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_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1); //初始化進(jìn)程會(huì)話密鑰 位置:/system/core/libkeyutils/Keyutils.cpp
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); //創(chuàng)建 /dev/.booting 文件,就是個(gè)標(biāo)記,表示booting進(jìn)行中
// 注釋五:
property_init(); //初始化屬性系統(tǒng),并從指定文件讀取屬性
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
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");
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
unsetenv("INIT_SECOND_STAGE"); //清空這些環(huán)境變量,因?yàn)橹岸家呀?jīng)存入到系統(tǒng)屬性中去了
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
// Now set up SELinux for second stage.
SelinuxSetupKernelLogging();
SelabelInitialize(); // SElinux第二階段
SelinuxRestoreContext(); // 恢復(fù)安全上下文
epoll_fd = epoll_create1(EPOLL_CLOEXEC); //注釋六:創(chuàng)建 epoll 句柄
if (epoll_fd == -1) {
PLOG(FATAL) << "epoll_create1 failed";
}
sigchld_handler_init(); //類似java中的Handelr,如果子進(jìn)程(比如 Zygote 進(jìn)程)異常退出,init進(jìn)程會(huì)調(diào)用到該函數(shù)中設(shè)定的信號(hào)處理函數(shù)來進(jìn)行處理
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(); //從文件中加載一些屬性,讀取usb配置
export_oem_lock_status(); //設(shè)置ro.boot.flash.locked 屬性
start_property_service(); //注釋七:啟動(dòng)屬性服務(wù)
set_usb_controller(); //設(shè)置sys.usb.controller 屬性
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map); //靜態(tài)方法,將function_map放到Action中作為成員變量
subcontexts = InitializeSubcontexts();
ActionManager& am = ActionManager::GetInstance(); //得到ActionManager對(duì)象
ServiceList& sm = ServiceList::GetInstance();
//注釋八:解析init.rc 文件
LoadBootScripts(am, sm); //解析 init.rc 配置文件
// 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) DumpState();
am.QueueEventTrigger("early-init"); //注釋九:額外配置一些事件和Action
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
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(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
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(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
// 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) {//注釋十:監(jiān)聽新的事件
// 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;
}
init 的 main 函數(shù)做了很多的事情,
注釋一:ueventd_main 創(chuàng)建設(shè)備節(jié)點(diǎn)文件,watchdogd_main
ueventd_main
Android 根文件系統(tǒng)的映像上不存在 /dev 目錄,該目錄是init進(jìn)程啟動(dòng)后動(dòng)態(tài)創(chuàng)建的,而init進(jìn)程將創(chuàng)建設(shè)備節(jié)點(diǎn)文件的任務(wù)交給了 ueventd 子進(jìn)程
位置:\system\core\init\ueventd.cpp
ueventd 通過兩種方式創(chuàng)建設(shè)備節(jié)點(diǎn)文件
1.冷插拔(Cold Plug)即以預(yù)先定義的設(shè)備信息統(tǒng)一創(chuàng)建設(shè)備節(jié)點(diǎn)文件,這一類設(shè)備節(jié)點(diǎn)文件也被稱為靜態(tài)節(jié)點(diǎn)文件
2.熱插拔(Hot Plug)即在系統(tǒng)運(yùn)行中,當(dāng)有設(shè)備插入U(xiǎn)SB端口時(shí),ueventd就會(huì)監(jiān)聽到這一時(shí)間,為插入的設(shè)備動(dòng)態(tài)創(chuàng)建設(shè)備節(jié)點(diǎn)文件,這一類設(shè)備節(jié)點(diǎn)文件也被稱為動(dòng)態(tài)節(jié)點(diǎn)文件
watchdogd_main
看門狗本身是一個(gè)定時(shí)電路,內(nèi)部會(huì)不斷進(jìn)行計(jì)時(shí)操作,有兩個(gè)引腳與系統(tǒng)相連,正常運(yùn)行時(shí)每隔一段時(shí)間計(jì)算機(jī)系統(tǒng)會(huì)通過一個(gè)引腳向看門狗發(fā)送信號(hào),看門狗接收到信號(hào)后會(huì)將計(jì)時(shí)器清零并重新開始計(jì)時(shí),若系統(tǒng)卡死,看門狗計(jì)時(shí)結(jié)束,就會(huì)通過另一個(gè)引腳向系統(tǒng)發(fā)動(dòng)復(fù)位信號(hào),讓系統(tǒng)重啟
位置:\system\core\init\watchdogd.cpp
注釋二:第一部分 掛載文件系統(tǒng)并創(chuàng)建目錄
因?yàn)槭堑谝淮螆?zhí)行main函數(shù) is_first_stage 獲得為null
mount是用來掛載文件系統(tǒng)的,非常熟悉了,用于掛載前面創(chuàng)建的節(jié)點(diǎn)文件,mknod用于創(chuàng)建Linux中的設(shè)備文件
init 初始化過程中,Android分別掛載了 tmpfs,devpts,proc,sysfs,selinuxfs 這5類文件系統(tǒng)
????????tmpfs:虛擬內(nèi)存文件系統(tǒng),會(huì)將所有的文件存儲(chǔ)在虛擬內(nèi)存中,既可以使用RAM,也可以使用交換分區(qū),會(huì)根據(jù)實(shí)際需要改變大小,因?yàn)槭邱v留在RAM中,所以讀取的速度非常快
????????devpts:devpts文件系統(tǒng)為偽終端提供了一個(gè)標(biāo)準(zhǔn)的接口,標(biāo)準(zhǔn)節(jié)點(diǎn)是/dev/pts。只要pty的主復(fù)合設(shè)備/dev/ptmx被打開,就會(huì)在/dev/pts下動(dòng)態(tài)的創(chuàng)建一個(gè)新的pty設(shè)備文件
????????proc:虛擬文件系統(tǒng),它可以看作是內(nèi)核內(nèi)部數(shù)據(jù)結(jié)構(gòu)的接口,通過它我們可以獲得系統(tǒng)的信息,同時(shí)也能夠在運(yùn)行時(shí)修改特定的內(nèi)核參數(shù)
????????sysfs:不占有任何磁盤空間的虛擬文件系統(tǒng)。它通常被掛接在/sys目錄下。sysfs文件系統(tǒng)是Linux2.6內(nèi)核引入的,它把連接在系統(tǒng)上的設(shè)備和總線組織成為一個(gè)分級(jí)的文件,使得它們可以在用戶空間存取
????????selinuxfs:通常掛載在/sys/fs/selinux目錄下,用來存放SELinux安全策略文件
注釋三:初始化日志輸出,掛載分區(qū)設(shè)備
InitKernelLogging
位置:/system/core/init/log.cpp
Linux 萬物皆文件,/sys/fs/selinux/null 相當(dāng)于一個(gè) null 對(duì)象
首先是將標(biāo)準(zhǔn)輸入輸出( 0、1、2)定向到 /sys/fs/selinux/null(null設(shè)備上)
文件描述符 (file descriptor) 是內(nèi)核為了高效管理已被打開的文件所創(chuàng)建的索引,其是一個(gè)非負(fù)整數(shù)(通常是小整數(shù)),用于指代被打開的文件,所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都通過文件描述符。
Linux 進(jìn)程默認(rèn)情況下會(huì)有3個(gè)缺省打開的文件描述符,分別是標(biāo)準(zhǔn)輸入 0, 標(biāo)準(zhǔn)輸出 1, 標(biāo)準(zhǔn)錯(cuò)誤 2
InitLogging
位置:/system/core/base/logging.cpp
DoFirstStageMount
位置:system/core/init/init_first_stage.cpp
主要作用是初始化特定設(shè)備并掛載
注釋四:啟用SELinux安全策略
位置:\system\core\init\selinux.cpp
注釋五:第二部分 屬性服務(wù) property_init() 函數(shù) 和 start_property_service() 函數(shù)
啟用SELinux安全策略后,會(huì)重新執(zhí)行main函數(shù),由于設(shè)置了INIT_SECOND_SRAGE 屬性,所以第一部分執(zhí)行的代碼不會(huì)再執(zhí)行
位置:/system/core/init/property_service.cpp
直接交給 __system_property_area_init 處理,位置 /bionic/libc/bionic/system_property_api.cpp
最終調(diào)用了system_properties中的AreaInit 方法 位置:/bionic/libc/system_properties/system_properties.cpp
主要完成的工作,清除緩存,主要清除幾個(gè)鏈表以及在內(nèi)存中的映射,新建property_fliename 目錄(/dev/_properties)然后調(diào)用Initialize加載心痛屬性的類別信息,最后將加載的鏈表寫入文件并映射到內(nèi)存
process_kernel_dt() 位置:/system/core/init/init.cpp
process_kernel_cmdline位置:/system/core/init/init.cpp
注釋六:新建epoll并初始化子進(jìn)程終止信號(hào)處理函數(shù)
epoll_create1 位置:
sigchld_handler_init() 位置:/system/core/init/signal_handler.cpp
這個(gè)函數(shù)的主要作用是注冊 SIGCHLD 信號(hào)的處理函數(shù),init是一個(gè)守護(hù)進(jìn)程,為了防止init的子進(jìn)程成為僵尸進(jìn)程,需要init在子進(jìn)程結(jié)束時(shí)獲取子進(jìn)程的結(jié)束碼,通過結(jié)束碼將程序表中的進(jìn)程移除,防止僵尸進(jìn)程占用程序表的空間(程序表空間達(dá)到上限時(shí),系統(tǒng)不能再啟動(dòng)新的進(jìn)程)
注釋七:start_property_service() 開啟屬性服務(wù)
start_property_service 位置:\system\core\init\property_service.cpp
之前都是通過property_set 可以輕松設(shè)置系統(tǒng)屬性,但不是所有的進(jìn)程都有權(quán)限可以隨意修改系統(tǒng)屬性,Android 將屬性的設(shè)置統(tǒng)一交給init進(jìn)程管理,其他進(jìn)程不能直接修改屬性,只能通過init進(jìn)程來修改
start_property_service() 位置:/system/core/init/property_service.cpp
注釋八:解析init.rc文件
位置:/system/core/init/parser.cpp
這里涉及到on service import 對(duì)應(yīng)的三個(gè)解析器:ActionParser、ServiceParser、ImportParser,它們是之前加入到section_parsers_這個(gè)map中
它們都是SectionParser的子類,SectionParser中有三個(gè)虛函數(shù)和一個(gè)純虛函數(shù),只要包含純虛函數(shù)的類就是抽象類,不能new,只能通過子類實(shí)現(xiàn)
ActionParser
位置:\system\core\init\action_parser.cpp
ParseSection 函數(shù)的作用就是構(gòu)造了一個(gè)Action對(duì)象,將trigger條件記錄到Action這個(gè)對(duì)象中,如果是event trigger 就賦值給event_trigger_,如果是property trigger就放到property_trigger_這個(gè)map中ParseLineSection是直接調(diào)用Action對(duì)象的AddCommand函數(shù),AddCommand看名字就大概知道是添加命令,其調(diào)用FindFunction查找命令對(duì)應(yīng)的執(zhí)行函數(shù),最后將這些信息包裝成Command對(duì)象存放到commands_數(shù)組中
FindFunction是通過命令查找對(duì)應(yīng)的執(zhí)行函數(shù),比如.rc文件中定義chmod,那得在一個(gè)map中找到 chmod 具體去執(zhí)行哪個(gè)函數(shù),find相當(dāng)于Java中的get,但是返回的是entry,可以通過entry ->first和entry ->second獲取key-value。找到的value是一個(gè)結(jié)構(gòu)體,里面有三個(gè)值,第一個(gè)是參數(shù)最小數(shù)目,第二個(gè)是參數(shù)最大數(shù)目,第三個(gè)就是執(zhí)行函數(shù),之后作了參數(shù)的數(shù)目檢查,也就是說命令后的參數(shù)要在最小值和最大值之間。
這個(gè)BuiltinFunctionMap也比較簡單,例如 {"chown", {2, 3, {true, do_chown}}},
表示
最小的參數(shù)為2,最大的參數(shù)為3,調(diào)用的方法為 do_chown(),ture表示 是否需要在vendor_init域的子進(jìn)程中運(yùn)行,SELinux相關(guān)
EndSection 直接是調(diào)用ActionManager::GetInstance().AddAction,將數(shù)據(jù)存放到 actions_ 數(shù)組中,EndFile是一個(gè)空實(shí)現(xiàn)
ServiceParser
位置:\system\core\init\service.cpp
一樣是看ParseSection 、ParseLineSection方法
OptionParserMap也比較簡單,例如 {"oneshot", {0, 0, &Service::ParseOneshot}},
表示
最小的參數(shù)為0,最大的參數(shù)為0,調(diào)用的方法為 Service 類中的 ParseOneshot() 方法
EndSection,直接調(diào)用ServiceManager的AddService函數(shù),將數(shù)據(jù)存放到 services_ 數(shù)組中,EndFile依然是一個(gè)空實(shí)現(xiàn)
ImportParser
位置:\system\core\init\import_parser.cpp
主要導(dǎo)入一些其他的rc文件進(jìn)來,只實(shí)現(xiàn)了 ParseSection 和 EndFile ,因?yàn)樗恼Z法比較單一
至此,解析init.rc語法的過程走完了,主要就是三個(gè)核心解析器:ActionParser、ServiceParser、ImportParser。而這幾個(gè)解析器主要是實(shí)現(xiàn)ParseSection、ParseLineSection、EndSection、EndFile四個(gè)函數(shù)
注釋九:其他事件和一些Action
注釋十:監(jiān)聽新的事件
到這里 init 進(jìn)程已經(jīng)啟動(dòng)完成
5.Zygote(孵化器)進(jìn)程啟動(dòng)
上面講到在init進(jìn)程中有解析.rc文件,在這個(gè)rc文件中配置了一個(gè)重要的服務(wù)service–zygote,這是app程序的鼻祖
zygote進(jìn)程主要負(fù)責(zé)創(chuàng)建Java虛擬機(jī),加載系統(tǒng)資源,啟動(dòng)SystemServer進(jìn)程,以及在后續(xù)運(yùn)行過程中啟動(dòng)普通的應(yīng)用程序。
不同機(jī)器 zygote.rc 的文件個(gè)數(shù)可能有不同,這里有四種
- init.zygote32.rc :進(jìn)程對(duì)應(yīng)的執(zhí)行程序是 app_process (純 32bit 模式)
- init.zygote32_64.rc :啟動(dòng)兩個(gè) zygote 進(jìn)程 (名為 zygote 和 zygote_secondary),對(duì)應(yīng)的執(zhí)行程序分別是 app_process32 (主模式)、app_process64
- init.zygote64.rc:進(jìn)程對(duì)應(yīng)的執(zhí)行程序是 app_process64 (純 64bit 模式)
- init.zygote64_32.rc:啟動(dòng)兩個(gè) zygote 進(jìn)程 (名為 zygote 和 zygote_secondary),對(duì)應(yīng)的執(zhí)行程序分別是 app_process64 (主模式)、app_process32
上節(jié)注釋九的位置,再 init 最后會(huì)加入 late-init 的 trigger,當(dāng)late-init 觸發(fā)時(shí),會(huì)觸發(fā)zygote-start的操作,staty zygote就會(huì)創(chuàng)建zygote進(jìn)程并運(yùn)行
上一節(jié)在解析init.rc文件時(shí)會(huì)創(chuàng)建解析器解析init.rc里面的命令,而start命令是由ActionParser 解析器解析
可知 start 命令對(duì)應(yīng)的執(zhí)行函數(shù)為 do_start,do_start函數(shù)首先通過 FindService 去service 數(shù)組中遍歷,根據(jù)信息匹配出對(duì)應(yīng)的service,然后調(diào)用這個(gè) service 的 Start 方法
zygote 服務(wù)對(duì)應(yīng)的二進(jìn)制文件是 /system/bin/app_processXXX,對(duì)應(yīng)的源文件在:/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
// 將參數(shù)argv放到argv_String 字符串中
// 上圖可知,傳入的參數(shù)是 -Xzygote /system/bin --zygote --start-system-server
if (!LOG_NDEBUG) {
String8 argv_String;
for (int i = 0; i < argc; ++i) {
argv_String.append("\"");
argv_String.append(argv[i]);
argv_String.append("\" ");
}
ALOGV("app_process main with argv: %s", argv_String.string());
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //構(gòu)建 AppRuntime 對(duì)象,并將參數(shù)傳入
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to '--' or first non '-' arg goes to the vm.
//
// The first argument after the VM args is the "parent dir", which
// is currently unused.
//
// After the parent dir, we expect one or more the following internal
// arguments :
//
// --zygote : Start in zygote mode
// --start-system-server : Start the system server.
// --application : Start in application (stand alone, non zygote) mode.
// --nice-name : The nice name for this process.
//
// For non zygote starts, these arguments will be followed by
// the main class name. All remaining arguments are passed to
// the main method of this class.
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
//
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.
//
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.
const char* spaced_commands[] = { "-cp", "-classpath" }; //這兩個(gè)參數(shù)是Java程序需要依賴的Jar包,相當(dāng)于import
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
int i;
for (i = 0; i < argc; i++) {
if (known_command == true) { //將spaced_commands中的參數(shù)額外加入VM
runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add known option '%s'", argv[i]);
known_command = false;
continue;
}
for (int j = 0;
j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
++j) {
if (strcmp(argv[i], spaced_commands[j]) == 0) {//參數(shù)是否是spaced_commands中的參數(shù)
known_command = true;
ALOGV("app_process main found known command '%s'", argv[i]);
}
}
if (argv[i][0] != '-') { //如果參數(shù)第一個(gè)字符是”-“,直接跳出循環(huán),之前傳入的第一個(gè)參數(shù)是 -Xzygote,所以執(zhí)行到這里就跳出了,i=0
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add option '%s'", argv[i]);
}
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
//跳過一個(gè)參數(shù),之前跳過了 -Xzygote,這里跳過 /system/bin
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { // 表示zygote啟動(dòng)模式
zygote = true;
niceName = ZYGOTE_NICE_NAME; //這個(gè)值根據(jù)平臺(tái)可能是zygote或者zygote64
} else if (strcmp(arg, "--start-system-server") == 0) {//需要啟動(dòng)SystemServer
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {//表示application啟動(dòng)模式,普通的應(yīng)用程序
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {//進(jìn)程別名
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {//application啟動(dòng)的class
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) { //className不為空,說明是application啟動(dòng)模式
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);//將className和參數(shù)設(shè)置給runtime
if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append("\"");
restOfArgs.append(argv_new[k]);
restOfArgs.append("\" ");
}
ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
}
} else { //zygote啟動(dòng)模式
// We're in zygote mode.
maybeCreateDalvikCache();//創(chuàng)建Dalvik的緩存目錄
if (startSystemServer) {//加入 start-system-server參數(shù)
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag); // 加入--abi-list=參數(shù)
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));//將剩下的參數(shù)加入args
}
}
if (!niceName.isEmpty()) {//設(shè)置進(jìn)程的別名
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) { //zygote啟動(dòng)模式,加載 ZygoteInit 類
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) { //application 啟動(dòng)模式,加載 RuntimeInit 類
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.");
}
}
app_main.cpp 的 main 函數(shù)主要做的事就是參數(shù)解析,這個(gè)函數(shù)有兩種啟動(dòng)模式
- 一種是zygote模式:初始化zygote進(jìn)程,傳遞的參數(shù):–start-system-server 和 --socket-name=zygote,前者表示啟動(dòng)SystemServer,后者指定socket的名稱
- 一種是application模式:啟動(dòng)普通應(yīng)用程序,傳遞的參數(shù)有class名字以及class帶的參數(shù)
兩種模式最終都是調(diào)用AppRuntime對(duì)象的start函數(shù),加載 ZygoteInit 或 RuntimeInit 兩個(gè)Java類,并將之前整理的參數(shù)傳入進(jìn)去
上面main函數(shù)最后得知,如果 zygote 為 true,說明當(dāng)前在運(yùn)行Zygote進(jìn)程中,就會(huì)調(diào)用 AppRuntime 的 start 函數(shù)
位置:\frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
。。。。。。。
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL); //注釋一:初始化jni
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { //注釋二:啟動(dòng)JAVA虛擬機(jī)
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
//注釋三:為Java虛擬機(jī)注冊JNI方法
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; //注釋四:調(diào)用ZygoteInit.java 的 main 函數(shù)
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
// 獲得傳遞的 className 參數(shù),如果為 zygote 則傳遞的參數(shù)為:com.android.internal.os.ZygoteInit
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.
*/
// slashClassName 函數(shù)將className中的 “.” 替換成 “/”
char* slashClassName = toSlashClassName(className != NULL ? className : "");
// 找到 com.android.internal.os.ZygoteInit.java 這個(gè)類
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 找到 ZygoteInit.java 類中的main方法
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 {
//通過jni反射調(diào)用 zygoteInit.java 的 main 方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)//退出當(dāng)前線程
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)//創(chuàng)建一個(gè)線程,該線程會(huì)等待所有子線程結(jié)束后關(guān)閉虛擬機(jī)
ALOGW("Warning: VM did not shut down cleanly\n");
}
總體流程是:1.初始化jni,2.startVm函數(shù)創(chuàng)建java虛擬機(jī),3.startReg 函數(shù)為虛擬機(jī)注冊JNI方法,4. 根據(jù)傳遞進(jìn)來的參數(shù)找到對(duì)應(yīng)的java類,5. 通過JNI調(diào)用對(duì)應(yīng)類的main方法。通過JNI的方法zygote就從Native層進(jìn)入了Java框架層了,此前沒有任何代碼進(jìn)入Java框架層
注釋一:初始化JNI
位置:\libnativehelper\JniInvocation.cpp
bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
char buffer[PROP_VALUE_MAX];
#else
char* buffer = NULL;
#endif
library = GetLibrary(library, buffer);
// Load with RTLD_NODELETE in order to ensure that libart.so is not unmapped when it is closed.
// This is due to the fact that it is possible that some threads might have yet to finish
// exiting even after JNI_DeleteJavaVM returns, which can lead to segfaults if the library is
// unloaded.
const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
handle_ = dlopen(library, kDlopenFlags);
if (handle_ == NULL) {
if (strcmp(library, kLibraryFallback) == 0) {
// Nothing else to try.
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
// Note that this is enough to get something like the zygote
// running, we can't property_set here to fix this for the future
// because we are root and not the system user. See
// RuntimeInit.commonInit for where we fix up the property to
// avoid future fallbacks. http://b/11463182
ALOGW("Falling back from %s to %s after dlopen error: %s",
library, kLibraryFallback, dlerror());
library = kLibraryFallback;
//dlopen的功能是以指定的模式打開指定的動(dòng)態(tài)鏈接庫文件,并返回一個(gè)句柄
//RTLD_NOW 表示需要在dlopen返回前,解析出所有未定義的符號(hào),如果解析不出返回NULL
//RTLD_NODELETE 表示在dlclose()期間不卸載庫,并在之后使用dlopen重新加載庫的時(shí)不初始化庫中的靜態(tài)變量
handle_ = dlopen(library, kDlopenFlags);
if (handle_ == NULL) {
ALOGE("Failed to dlopen %s: %s", library, dlerror());
return false;
}
}
// FindSymbol 函數(shù)內(nèi)部實(shí)際調(diào)用的是dlsym
// dlsym作用是根據(jù)動(dòng)態(tài)鏈接庫 操作句柄(handle)與符號(hào)(symbol),返回對(duì)應(yīng)的地址
// 這里實(shí)際就是從lobart.so庫中將 JNI_GetDefaultJavaVMInitArgs 等對(duì)應(yīng)的地址存放到 &JNI_GetDefaultJavaVMInitArgs_
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
注釋二:創(chuàng)建虛擬機(jī) startVm
調(diào)用的函數(shù)是\libnativehelper\JniInvocation.cpp
下的 AndroidRuntime::startVm 函數(shù),這個(gè)函數(shù)比較長,但做的事情單一,就是從系統(tǒng)屬性中讀取參數(shù),然后通過 addOption 設(shè)置到 AndroidRuntime 的 mOptions 數(shù)組中存儲(chǔ)起來,然后調(diào)用從 libart.so 中找到的 JNI_CreateJavaVM 函數(shù),并將之前讀到的參數(shù)傳入
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
JavaVMInitArgs initArgs;
。。。。。。
/* route exit() to our handler */
addOption("exit", (void*) runtime_exit); //將各個(gè)參數(shù)放到mOption數(shù)組中
。。。。。。
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray(); //將mOptions賦值給initArgs
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { //調(diào)用libart.so 的JNI_CreateJavaVM 函數(shù)去創(chuàng)建虛擬機(jī)
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
libart.so是ART虛擬機(jī)的核心庫,它包含了ART虛擬機(jī)所有的核心組件,如ClassLinker、DexFile、JNI、gc等
注釋三:為虛擬機(jī)注冊JNI方法 startReg
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
//設(shè)置Android創(chuàng)建線程的函數(shù)javaCreateThreadEtc,這個(gè)函數(shù)內(nèi)部是通過Linux的clone來創(chuàng)建線程的
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
//創(chuàng)建一個(gè)200容量的局部引用作用域,這個(gè)局部引用其實(shí)就是局部變量
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {//注冊JNI函數(shù)
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);//釋放局部引用作用域
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
/*********************************************************/
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
startReg 處理就是交給 RegJNIRec 的 mProc,RegJNIRec是個(gè)很簡單的結(jié)構(gòu)體,mProc是個(gè)函數(shù)指針
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
REG_JNI(register_android_util_PathParser),
REG_JNI(register_android_util_StatsLog),
REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
REG_JNI(register_android_text_MeasuredParagraph),
REG_JNI(register_android_text_StaticLayout),
REG_JNI(register_android_view_InputDevice),
REG_JNI(register_android_view_KeyCharacterMap),
REG_JNI(register_android_os_Process),
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
REG_JNI(register_android_os_HidlSupport),
。。。。。。
};
注釋四:反射調(diào)用ZygoteInit類的main函數(shù)
虛擬機(jī)創(chuàng)建完成后,就可以運(yùn)行java代碼了,主要是通過jni的函數(shù) CallStaticVoidMethod 反射調(diào)用 com.android.internal.os.ZygoteInit.java 的main函數(shù),至此 Zygote 進(jìn)程已經(jīng)啟動(dòng)
6.SystemServer進(jìn)程啟動(dòng)
上面已經(jīng)啟動(dòng)了Zygote進(jìn)程,并最終調(diào)用到了ZygoteInit.java 的main函數(shù),而SystemServer就是在這個(gè)main函數(shù)中啟動(dòng)的
位置:\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
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);
}
final Runnable caller;
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";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
// 注釋一:處理傳遞過來的參數(shù)
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) { //是否啟動(dòng)systemServer
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) { //ABI_LIST_ARG = "--abi-list=";
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) { //SOCKET_NAME_ARG = "--socket-name=";
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.");
}
// 注釋二:創(chuàng)建一個(gè)Server端的Socket,socketName的值為“zygote”
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());
// 注釋三:預(yù)加載類和資源
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0);
Zygote.nativeSecurityInit();
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
// 注釋四:啟動(dòng)systemSercer進(jìn)程
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.
//注釋五:等待 AMS 請求 進(jìn)入looper,等待AMS請求Zygote進(jìn)程來創(chuàng)建新的應(yīng)用程序進(jìn)程
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();
}
}
注釋一:處理傳遞過來的參數(shù)
在\frameworks\base\cmds\app_process\app_main.cpp
中有傳遞對(duì)應(yīng)的參數(shù)
注釋二:創(chuàng)建一個(gè)Server端的Socket
位置:\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
之后創(chuàng)建 SystemServer 進(jìn)程的時(shí)候,會(huì)將這個(gè)Socket傳遞進(jìn)去,SystemServer 就會(huì)在這個(gè)務(wù)器端 Socket 上等待 AMS 請求 Zygote 進(jìn)程來創(chuàng)建新的應(yīng)用程序進(jìn)程。
注釋三:預(yù)處理
注釋四:啟動(dòng)SystemSercer進(jìn)程
SystemSercer進(jìn)程創(chuàng)建
private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_IPC_LOCK,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_PTRACE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG,
OsConstants.CAP_WAKE_ALARM,
OsConstants.CAP_BLOCK_SUSPEND
);
/* Containers run without some capabilities, so drop any caps that are not available. */
StructCapUserHeader header = new StructCapUserHeader(
OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
StructCapUserData[] data;
try {
data = Os.capget(header);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to capget()", ex);
}
capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
// Mediatek Android Patch Begin
/* Mediatek add 1014 to setgroups for dhcp*/
/* Hardcoded command line to start the system server */
String args[] = { // 創(chuàng)建args 數(shù)組,這個(gè)數(shù)組用來保存啟動(dòng) SystemServer 的啟動(dòng)參數(shù)
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1014,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
// Mediatek Android Patch End
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
/* Request to fork the system server process */
pid = Zygote.forkSystemServer( //創(chuàng)建一個(gè)子進(jìn)程,也就是 SystemServer 進(jìn)程
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) { //當(dāng)代碼邏輯運(yùn)行在子進(jìn)程中,既是 SystemServer 進(jìn)程
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket(); //子進(jìn)程關(guān)閉 Socket
return handleSystemServerProcess(parsedArgs);//處理 SystemServer 進(jìn)程
}
return null;
}
第一步:創(chuàng)建 SystemServer 的啟動(dòng)參數(shù)
從 args 數(shù)組,SystemServer 的啟動(dòng)參數(shù)可以看出 SystemServer 進(jìn)程用戶 id 和 用戶組 id 被設(shè)置成了1000,并擁有
setgroups=1001,1002,1003,1004,1005,1006,1007,1014,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010"
的權(quán)限,進(jìn)程的名稱為:–nice-name=system_server,啟動(dòng)的類名為com.android.server.SystemServer
第二步:forkSystemServer 創(chuàng)建出 SystemServer進(jìn)程
注意: 這里有個(gè)pid == 0 的判斷,android
的fork機(jī)制可以理解為分裂,分裂后有兩個(gè)代碼一模一樣的進(jìn)程,分裂后會(huì)同時(shí)執(zhí)行兩個(gè)進(jìn)程的代碼,如果是在父進(jìn)程中執(zhí)行
fork,則會(huì)返回分裂子進(jìn)程的的進(jìn)程號(hào)(pid),如果是在子進(jìn)程中 執(zhí)行 fork,返回值為0,所以 if (pid == 0)
里面的代碼只會(huì)在子進(jìn)程既 SystemServer 進(jìn)程中執(zhí)行
至此,就創(chuàng)建出了 SystemServer 進(jìn)程
由于SystemServer進(jìn)程 是 fork Zygote進(jìn)程的,所以也會(huì)得到 Zygote 進(jìn)程創(chuàng)建的 Socket ,但這個(gè) Socket 對(duì)于 SystemServer 沒有用處,所以關(guān)閉了這個(gè) Socket,之后調(diào)用 handleSystemServerProcess 來初始化 SystemServer 進(jìn)程
最終是得到了 SystemServer 的main方法反射
SystemSercer進(jìn)程啟動(dòng)流程
位置:\frameworks\base\services\java\com\android\server\SystemServer.java
/**
* The main entry point from zygote.
*/
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 = "1".equals(SystemProperties.get("sys.boot_completed"));
mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
mRuntimeStartUptime = SystemClock.uptimeMillis();
}
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) { //獲得時(shí)間
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"); //獲得時(shí)區(qū)
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);
// The system server should always load safe labels
PackageItemInfo.setForceSafeLabels(true);
// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
SQLiteCompatibilityWalFlags.init(null);
// 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());
// 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);
// Within the system server, when parceling exceptions, include the stack trace
Parcel.setStackTraceParceling(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();
Looper.getMainLooper().setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
// Initialize native services.
System.loadLibrary("android_servers"); //加載動(dòng)態(tài)庫 libandroid_servers.so
// 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); //創(chuàng)建SystemServiceManaager對(duì)象,會(huì)對(duì)系統(tǒng)服務(wù)進(jìn)行創(chuàng)建,啟動(dòng)和生命周期管理
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
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(); //啟動(dòng)引導(dǎo)服務(wù)
startCoreServices(); //啟動(dòng)核心服務(wù)
startOtherServices(); //啟動(dòng)其他服務(wù)
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
StrictMode.initVmDefaults(null);
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");
}
startBootStrapServices():對(duì)應(yīng)系統(tǒng)引導(dǎo)服務(wù)。我們熟悉的ATM、AMS、PMS、PKMS服務(wù)就是在這啟動(dòng)的
startCoreServices():對(duì)應(yīng)核心服務(wù)。如電池服務(wù)就是在這啟動(dòng)
startOtherServices():對(duì)應(yīng)其他服務(wù)。在這個(gè)方法中,啟動(dòng)的服務(wù)大概有70+個(gè),WMS服務(wù)就是在這里啟動(dòng)的
引導(dǎo)服務(wù) | 作用 |
---|---|
Installer | 系統(tǒng)安裝APK時(shí)的一個(gè)服務(wù),啟動(dòng)完成 Installer 服務(wù)之后才能啟動(dòng)其他的服務(wù) |
ActivityManagerService | 負(fù)責(zé)四大組件的啟動(dòng),切換,調(diào)度 |
PowerManagerService | 系統(tǒng)中和 Power 相關(guān)的計(jì)算,然后決策系統(tǒng)應(yīng)該如何相應(yīng) |
LightsService | 管理背光顯示LED |
DisplayManagerService | 管理所有顯示設(shè)備 |
UserManagerService | 多用戶模式管理 |
SensorService | 為系統(tǒng)提供各種感應(yīng)器服務(wù) |
PackageManagerService | 用來對(duì)APK進(jìn)行安裝,解析,刪除,卸載等操作 |
… | … |
核心服務(wù) | 作用 |
---|---|
DropBoxManagerService | 用于生成和管理系運(yùn)行時(shí)的一些日志文件 |
BatteryService | 管理電池相關(guān)服務(wù) |
UsageStatsService | 手機(jī)用戶使用每個(gè)app的頻率,時(shí)長 |
WebViewUpdateService | WebView 更新服務(wù) |
… | … |
其他服務(wù) | 作用 |
---|---|
CameraService | 攝像頭相關(guān)服務(wù) |
AlarmManagerService | 全局定時(shí)器管理服務(wù) |
InputManagerService | 管理輸入事件 |
WindowManagerService | 窗口管理服務(wù) |
VrManagerService | VR模式夫管理服務(wù) |
BluetoothService | 藍(lán)牙管理服務(wù) |
NotificationManagerService | 通知管理服務(wù) |
DeviceStorageMonitorService | 存儲(chǔ)相關(guān)管理服務(wù) |
LocationManagerService | 定位相關(guān)管理服務(wù) |
AudioService | 音頻相關(guān)服務(wù) |
… | … |
startBootStrapServices() startCoreServices() startOtherServices()方法里都是調(diào)用類似的方法去開啟服務(wù)
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);以 PowerManagerService 為例,調(diào)用了SystemServiceManager 的 startService 方法開啟服務(wù)
位置: \frameworks\base\services\core\java\com\android\server\SystemServiceManager.java
7.Launcher 啟動(dòng)
系統(tǒng)啟動(dòng)的最后一步是啟動(dòng)一個(gè)應(yīng)用程序用來顯示系統(tǒng)中已經(jīng)安裝的應(yīng)用程序,并作為這些安裝程序的啟動(dòng)入口,這個(gè)應(yīng)用程序就是Launcher
上面得知SystemServer 進(jìn)程啟動(dòng)中會(huì)啟動(dòng)很多其他的服務(wù),其中一個(gè)就是 ActivityManagerService,在 startOtherServices 中會(huì)調(diào)用 AMS 的 systemReady() 方法將 Lanuncher 啟動(dòng)起來
位置:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
文章來源:http://www.zghlxwxcb.cn/news/detail-623665.html
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
traceLog.traceBegin("PhaseActivityManagerReady");
。。。。。。
synchronized (this) {
。。。。。。
startHomeActivityLocked(currentUserId, "systemReady");
。。。。。。
}
}
在 AMS 中的 systemReady() 方法中執(zhí)行 startHomeActivityLocked()方法,傳入當(dāng)前用戶ID
Launcher本身就是一個(gè)系統(tǒng)APP,用于顯示桌面等,LauncherApp啟動(dòng)之后會(huì)執(zhí)行其生命周期方法初始化桌面布局,至此,Launcher就啟動(dòng)完成了,用戶進(jìn)入到界面,整個(gè)Android系統(tǒng)也啟動(dòng)起來文章來源地址http://www.zghlxwxcb.cn/news/detail-623665.html
到了這里,關(guān)于筆記:Android 9系統(tǒng)啟動(dòng)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!