android 开机流程详细分析
来源:互联网 发布:可视化编程软件 编辑:程序博客网 时间:2024/05/19 18:13
arm平台开机的时候,会先跑ic内部的rom code,rom code把flash上的uboot加载到dram中,然后执行uboot。不同的ic厂商uboot实现可能不一样,有些厂商会把uboot拆分为两个部分,第一部分会先加载到ic内部的sram运行起来,然后初始化dram,再把第二部分加载到dram中运行起来。这里我们不再深入探讨,我们只分析common的部分,uboot在跳转到kernel之前,会传递一些参数过来,并且对于arm构架的平台而言,跳转到kernel前,r0寄存器设置为0,r1的值为match type,r2的值为指向参数结构体的指针,所以kernel是通过r2寄存器拿到uboot传递过来的参数。
linux-4.10/arch/arm/kernel/head.S
/*60 * Kernel startup entry point.61 * ---------------------------62 *63 * This is normally called from the decompressor code. The requirements64 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,65 * r1 = machine nr, r2 = atags or dtb pointer.66 *67 * This code is mostly position independent, so if you link the kernel at68 * 0xc0008000, you call this at __pa(0xc0008000).69 *70 * See linux/arch/arm/tools/mach-types for the complete list of machine71 * numbers for r1.72 *73 * We're trying to keep crap to a minimum; DO NOT add any machine specific74 * crap here - that's what the boot loader (or in extreme, well justified75 * circumstances, zImage) is for.76 */77 .arm78 79 __HEAD80 ENTRY(stext) // ...117 /*118 * r1 = machine no, r2 = atags or dtb,119 * r8 = phys_offset, r9 = cpuid, r10 = procinfo120 */121 bl__vet_atags //...130 /*131 * The following calls CPU specific code in a position independent132 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of133 * xxx_proc_info structure selected by __lookup_processor_type134 * above.135 *136 * The processor init function will be called with:137 * r1 - machine type138 * r2 - boot data (atags/dt) pointer139 * r4 - translation table base (low word)140 * r5 - translation table base (high word, if LPAE)141 * r8 - translation table base 1 (pfn if LPAE)142 * r9 - cpuid143 * r13 - virtual address for __enable_mmu -> __turn_mmu_on144 *145 * On return, the CPU will be ready for the MMU to be turned on,146 * r0 will hold the CPU control register value, r1, r2, r4, and147 * r9 will be preserved. r5 will also be preserved if LPAE.148 */149 ldrr13, =__mmap_switched@ address to jump to after150 @ mmu has been enabled151 badrlr, 1f@ return (PIC) address152 #ifdef CONFIG_ARM_LPAE153 movr5, #0@ high TTBR0154 movr8, r4, lsr #12@ TTBR1 is swapper_pg_dir pfn155 #else156 movr8, r4@ set TTBR1 to swapper_pg_dir157 #endif158 ldrr12, [r10, #PROCINFO_INITFUNC]159 addr12, r12, r10160 retr12161 1:b__enable_mmu162 ENDPROC(stext)
bl __vet_atags 就是把uboot传递给kernel的参数拷贝到一个位置,ldr r13, =__mmap_switched 保存后面要执行的指令
/*436 * Setup common bits before finally enabling the MMU. Essentially437 * this is just loading the page table pointer and domain access438 * registers. All these registers need to be preserved by the439 * processor setup function (or set in the case of r0)440 *441 * r0 = cp#15 control register442 * r1 = machine ID443 * r2 = atags or dtb pointer444 * r4 = TTBR pointer (low word)445 * r5 = TTBR pointer (high word if LPAE)446 * r9 = processor ID447 * r13 = *virtual* address to jump to upon completion448 */449 __enable_mmu://...471 b__turn_mmu_on472 ENDPROC(__enable_mmu)__enable_mmu执行完之后,又跳转到__turn_mmu_on,我们接下来看一下__turn_mmu_on。
490 ENTRY(__turn_mmu_on)491 movr0, r0492 instr_sync493 mcrp15, 0, r0, c1, c0, 0@ write control reg494 mrcp15, 0, r3, c0, c0, 0@ read id reg495 instr_sync496 movr3, r3497 movr3, r13498 retr3 //子程序返回时,执行这条指令,也就是跳到 __mmap_switched499 __turn_mmu_on_end:500 ENDPROC(__turn_mmu_on)__turn_mmu_on最后执行r3中的指令,r3从r13来,而r13在上面的赋值是__mmap_switched。
linux-4.10/arch/arm/kernel/head-common.S
15 #define ATAG_CORE 0x5441000116 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)17 #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)47 __vet_atags:48 tstr2, #0x3@ aligned?49 bne1f50 51 ldrr5, [r2, #0]52 #ifdef CONFIG_OF_FLATTREE53 ldrr6, =OF_DT_MAGIC@ is it a DTB?54 cmpr5, r655 beq2f56 #endif57 cmpr5, #ATAG_CORE_SIZE@ is first tag ATAG_CORE?58 cmpner5, #ATAG_CORE_SIZE_EMPTY59 bne1f60 ldrr5, [r2, #4]61 ldrr6, =ATAG_CORE62 cmpr5, r663 bne1f64 65 2:retlr@ atag/dtb pointer is ok66 67 1:movr2, #068 retlr69 ENDPROC(__vet_atags)
在分析__mmap_switched之前,我们先看一下__vet_atags把参数拷贝到了哪里,下面这两句汇编相当于把uboot传递过来的参数拷贝到了0x54410001这个地址开始的内存中。
ldr r5, [r2, #4]
ldr r6, =ATAG_CORE
下面我们接着看__mmap_switched 汇编代码做了什么事。
/*72 * The following fragment of code is executed with the MMU on in MMU mode,73 * and uses absolute addresses; this is not position independent.74 *75 * r0 = cp#15 control register76 * r1 = machine ID77 * r2 = atags/dtb pointer78 * r9 = processor ID79 */80 __INIT81 __mmap_switched:82 adrr3, __mmap_switched_data83 84 ldmiar3!, {r4, r5, r6, r7}85 cmpr4, r5@ Copy data segment if needed86 1:cmpner5, r687 ldrnefp, [r4], #488 strnefp, [r5], #489 bne1b90 91 movfp, #0@ Clear BSS (and zero fp)92 1:cmpr6, r793 strccfp, [r6],#494 bcc1b95 96 ARM(ldmiar3, {r4, r5, r6, r7, sp})97 THUMB(ldmiar3, {r4, r5, r6, r7})98 THUMB(ldrsp, [r3, #16])99 strr9, [r4]@ Save processor ID100 strr1, [r5]@ Save machine type101 strr2, [r6]@ Save atags pointer102 cmpr7, #0103 strner0, [r7]@ Save control register values104 bstart_kernel105 ENDPROC(__mmap_switched)
前面做了很多初始化的工作,准备好C函数的运行环境,然后跳转到start_kernel()函数中,这里就从汇编跑到了C代码。
linux-4.10/init/main.c
482 asmlinkage __visible void __init start_kernel(void)483 {484 char *command_line;485 char *after_dashes;//...672 /* Do the rest non-__init'ed, we're now alive */673 rest_init();674 }前面做了一大堆各种各样的初始化,接着跑到rest_init();
384 static noinline void __ref rest_init(void)385 {386 int pid;387 388 rcu_scheduler_starting();389 /*390 * We need to spawn init first so that it obtains pid 1, however391 * the init task will end up wanting to create kthreads, which, if392 * we schedule it before we create kthreadd, will OOPS.393 */394 kernel_thread(kernel_init, NULL, CLONE_FS);395 numa_default_policy();396 pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);397 rcu_read_lock();398 kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);399 rcu_read_unlock();400 complete(&kthreadd_done);401 402 /*403 * The boot idle thread must execute schedule()404 * at least once to get things moving:405 */406 init_idle_bootup_task(current);407 schedule_preempt_disabled();408 /* Call into cpu_idle with preempt disabled */409 cpu_startup_entry(CPUHP_ONLINE);410 }
est_init()里面创建了两个线程(进程),一个是init进程,这里还是内核空间的进程,后面会变成用户空间的init进程;另外一个是kthreadd进程,内核的守护进程。所以我们重点关注内核空间的init进程接下来做了什么事。
static int __ref kernel_init(void *unused)953 {954 int ret;955 956 kernel_init_freeable();//...968 if (ramdisk_execute_command) {969 ret = run_init_process(ramdisk_execute_command);970 if (!ret)971 return 0;972 pr_err("Failed to execute %s (error %d)\n",973 ramdisk_execute_command, ret);974 }975 976 /*977 * We try each of these until one succeeds.978 *979 * The Bourne shell can be used instead of init if we are980 * trying to recover a really broken machine.981 */982 if (execute_command) {983 ret = run_init_process(execute_command);984 if (!ret)985 return 0;986 panic("Requested init %s failed (error %d).",987 execute_command, ret);988 }989 if (!try_to_run_init_process("/sbin/init") ||990 !try_to_run_init_process("/etc/init") ||991 !try_to_run_init_process("/bin/init") ||992 !try_to_run_init_process("/bin/sh"))993 return 0;994 995 panic("No working init found. Try passing init= option to kernel. "996 "See Linux Documentation/admin-guide/init.rst for guidance.");997 }
我们继续追踪kernel_init_freeable();
static noinline void __init kernel_init_freeable(void)1000 {//...1032 do_basic_setup();//...1062 integrity_load_keys();1063 load_default_modules();1064 }
继续追踪do_basic_setup();
/*867 * Ok, the machine is now initialized. None of the devices868 * have been touched yet, but the CPU subsystem is up and869 * running, and memory and process management works.870 *871 * Now we can finally start doing some real work..872 */873 static void __init do_basic_setup(void)874 {875 cpuset_init_smp();876 shmem_init();877 driver_init();878 init_irq_proc();879 do_ctors();880 usermodehelper_enable();881 do_initcalls();882 random_int_secret_init();883 }
do_initcalls()会调用到每个driver的init(),也就是module_init()传入的函数指针。
858 static void __init do_initcalls(void)859 {860 int level;861 862 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)863 do_initcall_level(level);864 }
843 static void __init do_initcall_level(int level)844 {845 initcall_t *fn;846 847 strcpy(initcall_command_line, saved_command_line);848 parse_args(initcall_level_names[level],849 initcall_command_line, __start___param,850 __stop___param - __start___param,851 level, level,852 NULL, &repair_env_string);853 854 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)855 do_one_initcall(*fn);856 }
777 int __init_or_module do_one_initcall(initcall_t fn)778 {779 int count = preempt_count();780 int ret;781 char msgbuf[64];782 783 if (initcall_blacklisted(fn))784 return -EPERM;785 786 if (initcall_debug)787 ret = do_one_initcall_debug(fn);788 else789 ret = fn(); //这里调用了init函数//…804 return ret;805 }
到这里我们就了解了driver的初始化是在这里调用的,到后面调用run_init_process(execute_command); 把init进程加载到内存运行起来。
static int run_init_process(const char *init_filename)905 {906 argv_init[0] = init_filename;907 return do_execve(getname_kernel(init_filename),908 (const char __user *const __user *)argv_init,909 (const char __user *const __user *)envp_init);910 }
为什么这里运行了init进程后,就会变成用户空间的init进程?可以了解一下do_execve()这个系统调用。
system/core/init/init.cpp
int main(int argc, char** argv) {//...603 // Get the basic filesystem setup we need put together in the initramdisk604 // on / and then we'll let the rc file figure out the rest.605 if (is_first_stage) {606 mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");607 mkdir("/dev/pts", 0755);608 mkdir("/dev/socket", 0755);609 mount("devpts", "/dev/pts", "devpts", 0, NULL);610 #define MAKE_STR(x) __STRING(x)611 mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));612 mount("sysfs", "/sys", "sysfs", 0, NULL);613 }//...684 Parser& parser = Parser::GetInstance();685 parser.AddSectionParser("service",std::make_unique<ServiceParser>());686 parser.AddSectionParser("on", std::make_unique<ActionParser>());687 parser.AddSectionParser("import", std::make_unique<ImportParser>());688 parser.ParseConfig("/init.rc");689 690 ActionManager& am = ActionManager::GetInstance();691 692 am.QueueEventTrigger("early-init");//...702 // Trigger all the boot actions to get us started.703 am.QueueEventTrigger("init");//...717 // Run all property triggers based on current state of the properties.718 am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");719 720 while (true) {721 if (!waiting_for_exec) {722 am.ExecuteOneCommand();723 restart_processes();724 }725 726 int timeout = -1;727 if (process_needs_restart) {728 timeout = (process_needs_restart - gettime()) * 1000;729 if (timeout < 0)730 timeout = 0;731 }732 733 if (am.HasMoreCommands()) {734 timeout = 0;735 }736 737 bootchart_sample(&timeout);738 739 epoll_event ev;740 int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));741 if (nr == -1) {742 ERROR("epoll_wait failed: %s\n", strerror(errno));743 } else if (nr == 1) {744 ((void (*)()) ev.data.ptr)();745 }746 }747 748 return 0;749 }
跑到init的main()函数中,里面做了很多事,包括mount各种文件系统,解析init.rc,执行init.rc里面的各种command,最后进入while循环,等待各种请求。
system/core/rootdir/init.zygote32.rc
1 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server2 class main3 socket zygote stream 660 root system4 onrestart write /sys/android_power/request_state wake5 onrestart write /sys/power/state on6 onrestart restart audioserver7 onrestart restart cameraserver8 onrestart restart media9 onrestart restart netd10 writepid /dev/cpuset/foreground/tasks
init进程在解析init.rc文件后,会把很多service进程运行起来,其中包括zygote进程。
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])187 { //...245 ++i; // Skip unused "parent dir" argument.246 while (i < argc) {247 const char* arg = argv[i++];248 if (strcmp(arg, "--zygote") == 0) {249 zygote = true;250 niceName = ZYGOTE_NICE_NAME;251 } else if (strcmp(arg, "--start-system-server") == 0) {252 startSystemServer = true;253 } else if (strcmp(arg, "--application") == 0) {254 application = true;255 } else if (strncmp(arg, "--nice-name=", 12) == 0) {256 niceName.setTo(arg + 12);257 } else if (strncmp(arg, "--", 2) != 0) {258 className.setTo(arg);259 break;260 } else {261 --i;262 break;263 }264 }//...279 if (startSystemServer) {280 args.add(String8("start-system-server"));281 }282 //...306 if (zygote) {307 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);308 } else if (className) {309 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);310 } else {311 fprintf(stderr, "Error: no class name or --zygote supplied.\n");312 app_usage();313 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");314 return 10;315 }316 }
里面做了很多事,包括解析传进来的参数,传进来的参数有--zygote--start-system-server,所以走的是runtime.start("com.android.internal.os.ZygoteInit",args, zygote); args中带有start-system-server字符串。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {//...714 try {//...722 String abiList = null;723 for (int i = 1; i < argv.length; i++) {724 if ("start-system-server".equals(argv[i])) {725 startSystemServer = true;726 } else if (argv[i].startsWith(ABI_LIST_ARG)) {727 abiList = argv[i].substring(ABI_LIST_ARG.length());728 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {729 socketName = argv[i].substring(SOCKET_NAME_ARG.length());730 } else {731 throw new RuntimeException("Unknown command line argument: " + argv[i]);732 }733 }//...767 if (startSystemServer) {768 startSystemServer(abiList, socketName);769 }770 771 Log.i(TAG, "Accepting command socket connections");772 runSelectLoop(abiList);773 774 closeServerSocket();775 } catch (MethodAndArgsCaller caller) {776 caller.run();777 } catch (Throwable ex) {778 Log.e(TAG, "Zygote died with exception", ex);779 closeServerSocket();780 throw ex;781 }782 }
为什么跑runtime.start("com.android.internal.os.ZygoteInit",args, zygote) 会跑到ZygoteInit中的main()函数,这里先不讲。在跑这个之前,runtime,也就是虚拟机已经初始化好了,所以可以跑java的代码了。
private static boolean startSystemServer(String abiList, String socketName)634 throws MethodAndArgsCaller, RuntimeException {//...652 /* Hardcoded command line to start the system server */653 String args[] = {654 "--setuid=1000",655 "--setgid=1000",656 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",657 "--capabilities=" + capabilities + "," + capabilities,658 "--nice-name=system_server",659 "--runtime-args",660 "com.android.server.SystemServer",661 };662 ZygoteConnection.Arguments parsedArgs = null;663 664 int pid;665 666 try {667 parsedArgs = new ZygoteConnection.Arguments(args);668 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);669 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);670 671 /* Request to fork the system server process */672 pid = Zygote.forkSystemServer(673 parsedArgs.uid, parsedArgs.gid,674 parsedArgs.gids,675 parsedArgs.debugFlags,676 null,677 parsedArgs.permittedCapabilities,678 parsedArgs.effectiveCapabilities);679 } catch (IllegalArgumentException ex) {680 throw new RuntimeException(ex);681 }682 683 /* For child process */684 if (pid == 0) {685 if (hasSecondZygote(abiList)) {686 waitForSecondaryZygote(socketName);687 }688 689 handleSystemServerProcess(parsedArgs);690 }691 692 return true;693 }
这里fork出了一个新进程,就是system_server,注意参数里面的com.android.server.SystemServer。如果是子进程才跑handleSystemServerProcess(),如果是父进程就直接返回true了。父进程(zygote)往下跑就会进入runSelectLoop(abiList);循环,等待socket请求,fork出新的子进程。
private static void handleSystemServerProcess(506 ZygoteConnection.Arguments parsedArgs)507 throws ZygoteInit.MethodAndArgsCaller {508 509 closeServerSocket();//...518 final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");519 if (systemServerClasspath != null) {520 performSystemServerDexOpt(systemServerClasspath);521 }//...547 /*548 * Pass the remaining arguments to SystemServer.549 */550 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);551 }552 553 /* should never reach here */554 }
handleSystemServerProcess() 关闭fork“继承”过来socket,加载systemserver类。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)281 throws ZygoteInit.MethodAndArgsCaller {282 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");283 284 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");285 redirectLogStreams();286 287 commonInit();288 nativeZygoteInit();289 applicationInit(targetSdkVersion, argv, classLoader);290 }
继续往下,跑到applicationInit()。
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)//...336 // Remaining arguments are passed to the start class's static main337 invokeStaticMain(args.startClass, args.startArgs, classLoader);338 }private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)210 throws ZygoteInit.MethodAndArgsCaller {211 Class<?> cl;212 213 try {214 cl = Class.forName(className, true, classLoader);215 } catch (ClassNotFoundException ex) {216 throw new RuntimeException(217 "Missing class when invoking static main " + className,218 ex);219 }220 221 Method m;222 try {223 m = cl.getMethod("main", new Class[] { String[].class });224 } catch (NoSuchMethodException ex) {225 throw new RuntimeException(226 "Missing static main on " + className, ex);227 } catch (SecurityException ex) {228 throw new RuntimeException(229 "Problem getting static main on " + className, ex);230 }//...244 throw new ZygoteInit.MethodAndArgsCaller(m, argv);245 }
前面有提到过注意传入的参数,所以加载的cl类就是SystemServer类。最后抛出了一个异常,这里应该会有很多人疑惑,这是一个“别有用心”的设计,可以清掉栈中ZygoteInit.main()之后调用的函数。
catch (MethodAndArgsCaller caller) {776 caller.run();777 }
抛出异常后,回到ZygoteInit.main()中捕获异常的模块,执行caller.run();
frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {219 new SystemServer().run();220 }
所以就跑到了SystemServer的main()函数中。
private void run() {//...310 Looper.prepareMainLooper();311 312 // Initialize native services.313 System.loadLibrary("android_servers");//...329 // Start services.330 try {331 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");332 startBootstrapServices();333 startCoreServices();334 startOtherServices();335 } catch (Throwable ex) {336 Slog.e("System", "******************************************");337 Slog.e("System", "************ Failure starting system services", ex);338 throw ex;339 } finally {340 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);341 }//...348 // Loop forever.349 Looper.loop();350 throw new RuntimeException("Main thread loop unexpectedly exited");351 }
run()函数里面又做了一大堆的事件,在这里面创建了许多service,比如AMS,PMS等等。
/**514 * Starts a miscellaneous grab bag of stuff that has yet to be refactored515 * and organized.516 */517 private void startOtherServices() {//…1302 mActivityManagerService.systemReady(new Runnable() {1303 @Override1304 public void run() {1305 Slog.i(TAG, "Making services ready");1306 mSystemServiceManager.startBootPhase(1307 SystemService.PHASE_ACTIVITY_MANAGER_READY);//…1433 }1434 });1435 }
在startOtherServices()会call到ActivityManagerService的systemReady()函数。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
13217 public void systemReady(final Runnable goingCallback) {13218 synchronized(this) {13219 if (mSystemReady) {13220 // If we're done calling all the receivers, run the next "boot phase" passed in13221 // by the SystemServer13222 if (goingCallback != null) {13223 goingCallback.run();13224 }13225 return;13226 }//…13339 startHomeActivityLocked(currentUserId, "systemReady");//…13386 } boolean startHomeActivityLocked(int userId, String reason) {//...3927 Intent intent = getHomeIntent();3928 ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);3929 if (aInfo != null) {3930 intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));3931 // Don't do this if the home app is currently being3932 // instrumented.3933 aInfo = new ActivityInfo(aInfo);3934 aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);3935 ProcessRecord app = getProcessRecordLocked(aInfo.processName,3936 aInfo.applicationInfo.uid, true);3937 if (app == null || app.instrumentationClass == null) {3938 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);3939 mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);3940 }3941 } else {3942 Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());3943 }3944 3945 return true;3946 }
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {640 mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);641 startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,642 null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,643 null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,644 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,645 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,646 false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,647 null /*container*/, null /*inTask*/);648 if (mSupervisor.inResumeTopActivity) {649 // If we are in resume section already, home activity will be initialized, but not650 // resumed (to avoid recursive resume) and will stay that way until something pokes it651 // again. We need to schedule another resume.652 mSupervisor.scheduleResumeTopActivities();653 }654 }
startHomeActivityLocked()就会把launcher 运行起来,到这里我们就看到了android的home界面。
- android 开机流程详细分析
- Android 开机流程分析
- Android 开机启动流程分析
- Android开机流程分析 -- 概述
- Android开机流程分析 -- Zygote
- android 关机流程详细分析
- android开机锁屏流程分析
- Android开机流程分析 -- init进程
- Android源码分析---系统开机流程
- android开机启动流程简单分析
- android开机启动流程简单分析
- linux开机流程分析
- Linux 开机流程分析
- 开机动画流程分析
- 6223开机流程分析
- 开机启动流程分析
- linux开机启动详细流程
- linux开机启动详细流程
- IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constrai nt fails (`mxonline
- HAOI2010 计数
- 巴什博弈
- localStorage总结
- js判断数字是否为整数
- android 开机流程详细分析
- 神创造了致病的病毒吗?
- android aspectj 配置
- 字符串去除空格回车以及随机生成中英文字符串
- poj 3264 Balanced Lineup
- windows和linux环境下java调用C++代码-JNI技术
- 【LeetCode】Min Stack带最小值操作的栈
- 乐趣:初识React
- domElement.appendChild is not a function