| [点晴永久免费OA]Android 开机流程介绍
					当前位置:点晴教程→点晴OA办公管理信息系统
					
					→『 经验分享&问题答疑 』
					
				 
 
 一、目的        从2014年Android4.0开始接触机器人,开发过App应用软件,研究过Framework层框架结构、也梳理过Native层的系统流程,但是对于Hal层,以及底下的kernel方向,知之甚少。 二、环境
 三、相关概念3.1 Android平台架构如下是Google官网提供的平台架构图,很直观地攘括了Android的层级,关于各个层级的结构,有想了解可以参考:https://developer.android.google.cn/guide/platform?hl=zh-cn  ps: Android系统为什么要有Hal层? 3.2 Android启动架构如下是从某大佬的文章里摘取的图片,很详细地描述了Android系统启动过程:Boot Loader引导开机 -> Kernel -> Native -> Framework -> App  3.3 zImagezImage是一般情况下默认的压缩内核映像文件,压缩vmlinux,加上一段解压启动代码得到,只能从0X0地址运行。 3.4 RAMDISK        RAMDISK(initrd) 是一个小的分区像,在引导时内核以只读方式挂载它。它只保护/int和一些置文件,它用于初始化和挂载其它的文件系统镜像。 3.5 RC文件rc文件,是用Android Init Language编写的特殊文件。用这种语法编写的文件,统一用".rc"后缀。所有rc文件,不会被编译/链接。它是配置文件,不是程序,是一种用于android init的配置文件。真正加载rc文件,并进行解析,做事情的是 Init进程。 四、详细设计 4.1 Boot Rom当长按电源开机的时候,引导芯片开始从固化在ROM的预设代码开始执行,然后将加载引导程序到RAM中。 4.2 BootLoaderBootLoader又称为引导程序,它在运行操作系统之前运行的一段程序,是运行的第一个程序。主要的功能有检查RAM、初始化一些硬件外设等功能,它最终的目的是启动操作系统。 4.3 KernelKernel初始化可以分成三部分:zImage解压缩、kernel的汇编启动阶段、Kernel的C启动阶段 4.3.1 zImage解压缩阶段
 4.3.2 kernel的汇编启动阶段idle进程的启动是用汇编语言编写(感兴趣可以去研究下),对应的启动如下: s @bsp\kernel\kernel5.4\arch\arm\kernel\head-common.S
ldmia	r4, {r0, r1, r2, r3}
str	r9, [r0]			@ Save processor ID
str	r7, [r1]			@ Save machine type
str	r8, [r2]			@ Save atags pointer
cmp	r3, #0
strne	r10, [r3]			@ Save control register values
mov	lr, #0
b	start_kernel //启动start_kernel函数其中,语句b start_kernel,b 是跳转的意思,即跳转到start_kernel函数,对应的实现在bsp/kernel/kernel5.4/init/main.c,至此idle进程被启动。 4.3.3 Kernel的C启动阶段start_kernel()函数是内核初始化C语言部分的主体。这个函数完成系统底层基本机制,包括处理器、存储管理系统、进程管理系统、中断机制、定时机制等的初始化工作。 c @bsp\kernel\kernel5.4\init\main.c
asmlinkage __visible void __init start_kernel(void){
    char *command_line;
    char *after_dashes;
    set_task_stack_end_magic(&init_task);
    smp_setup_processor_id();//打印了驱动加载的第一行log
    ... //初始化一系列系统底层机制
    pr_notice("%s", linux_banner);//打印内核版本信息
    ...
    pr_notice("Kernel command line: %s\n", saved_command_line);//打印从uboot传递过来的command_line字符串
    ...
    /* Do the rest non-__init'ed, we're now alive */
    arch_call_rest_init();//创建init进程、kthread进程、idle进程
    prevent_tail_call_optimization();}4.3.3.1 kernel启动log(1)kernel内核启动阶段,smp_setup_processor_id()函数会打印的第一条log(文中log可以在 [目录5.1开机log] 下载查看),如下: none [ 0.000000] c0 Booting Linux on physical CPU 0x0 (2)接着会打印内核的一些信息,版本,作者,编译器版本,日期等,如下: none [ 0.000000]c0 Linux version 5.4.147+ (lzq@cz-PowerEdge-R730) (Android (7284624, based on r416183b) clang version 12.0.5 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee), LLD 12.0.5 (/buildbot/src/android/llvm-toolchain/out/llvm-project/lld c935d99d7cf2016289302412d708641d52d2f7ee)) #5 SMP PREEMPT Thu Sep 28 15:17:40 CST 2023 (3)打印出从uboot传递过来的command_line字符串,在setup_arch函数中获得的(proc/cmdline) none [ 0.000000]c0 Kernel command line: earlycon=sprd_serial_ex,0x508d0000,115200n8 console=ttySE0,921600n8 loglevel=7 init=/init root=/dev/ram0 rw vmalloc=360M printk.devkmsg=on androidboot.boot_devices=soc/soc:ap-ahb/20600000.sdio initcall_debug=1 swiotlb=1 androidboot.selinux=permissive androidboot.hardware=sl8541e_1h10_32b androidboot.dtbo_idx=0 lcd_id=ID40396 lcd_name=lcd_st7123_truly_mipi_hd lcd_base=9e000000 lcd_size=1440x720 logo_bpix=24 androidboot.ddrsize=1024M androidboot.ddrsize.range=[1024,2048) sysdump_magic=80001000 sysdump_re_flag=1 androidboot.wdten=0 androidboot.dswdten=disable modem=shutdown ltemode=lcsfb rfboard.id=-1 rfhw.id=0 crystal=2 32k.less=1 androidboot.pmic.chipid=2721 modemboot.method=emmcboot cpcmdline=end androidboot.verifiedbootstate=orange androidboot.flash.locked=0 androidboot.serialno=LE210210001326000028 buildvariant=userdebug androidboot.vbmeta.device=PARTUUID=1.0 androidboot.vbmeta.avb_version=1.1 androidboot.vbmeta.device_state=unlocked androidboot. 4.3.3.2 init进程&kthreadd进程创建了Linux系统中两个重要的进程init和kthreadd,并且将当前进程设置为idle进程: c @bsp\kernel\kernel5.4\init\main.cvoid __init __weak arch_call_rest_init(void){
    rest_init();}noinline void __ref rest_init(void){
    ...
    pid = kernel_thread(kernel_init, NULL, CLONE_FS);//创建init进程
    ...
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);//创建kthreadd进程
    ...
    /* Call into cpu_idle with preempt disabled */
    cpu_startup_entry(CPUHP_ONLINE);//设置当前进程为idle进程}        Linux下有三个特殊的进程,idle(swapper)进程(PID = 0),init进程(PID = 1)和看threadd(PID = 2): (1)idle(swapper)进程由系统自动创建,运行在内核态。idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换,常常被称为交换进程。 4.3.3.3 idle进程启动这个函数是Linux内核为非引导CPU初始化和进入空闲循环的入口函数,负责在系统没有任务需要执行时,让CPU进入空闲状态。 c @bsp\kernel\kernel5.4\kernel\sched\idle.cvoid cpu_startup_entry(enum cpuhp_state state){
    arch_cpu_idle_prepare();
    cpuhp_online_idle(state);
    while (1)
        do_idle();}4.4 Init进程由上一节可知,Init进程由0号idle进程启动,kernel_init()为其入口函数,该函数主要通过三种方式启动init程序。 c static int __ref kernel_init(void *unused){
    ...
    if (ramdisk_execute_command) {
        ret = run_init_process(ramdisk_execute_command);//Step 1. 根据ramdisk_execute_command的值来启动init程序
        if (!ret)
            return 0;
        pr_err("Failed to execute %s (error %d)\n",
                ramdisk_execute_command, ret);
    }
    if (execute_command) {
        ret = run_init_process(execute_command);//Step 2. 根据execute_command的值来启动init程序
        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")) //Step 3.根据系统默认位置来启动init程序
        return 0;
    panic("No working init found.  Try passing init= option to kernel. "
            "See Linux Documentation/admin-guide/init.rst for guidance.");//Step 4.异常重启}(1)ramdisk_execute_command是一个全局的char指针变量,值为“/init”,也就是根目录下的init程序。该值通过uboot传递过来,具体可参考上一节的command_line。(如未配置该值,即会将该值默认设置为"/init",该项目是从该处启动init进程) log [ 1.000614]c1 Run /init as init process 4.4.1 init程序编译        我们知道init程序是引用的根目录下的init,即/init,但是其对应的软链接指向:system/bin/init,相关信息如下: 编译makefile文件如下: none @system\core\init\Android.bp
phony {
    name: "init",
    required: [
        "init_second_stage",
    ],
}
cc_binary {
    name: "init_second_stage",
    recovery_available: true,
    stem: "init",//最终生成的二进制文件名
    defaults: ["init_defaults"],
    static_libs: ["libinit"],
    ...
    srcs: ["main.cpp"],
    ...
}4.4.2 init程序入口函数init程序的入口函数,根据不同的入参,响应init不同阶段、处理不同业务逻辑。 c @system\core\init\main.cppint main(int argc, char** argv) {
    ...
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);//初始化uevent事件
    }
    if (argc > 1) {
        ...
        if (!strcmp(argv[1], "selinux_setup")) {
            android::mboot::mdb("SELinux Setup ...");
            return SetupSelinux(argv);//selinux权限
        }
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);//第二阶段
        }
    }
    return FirstStageMain(argc, argv);//第一阶段}由于在kernel阶段启动init程序时,未配置参数,故首先会引用FirstStageMain函数。另外,根据log可以看到,其引用顺序如下: none [ 1.004958]c1 init: init first stage started! [ 2.547025]c0 init: Opening SELinux policy [ 3.226672]c0 init: init second stage started! [ 3.715657]c1 ueventd: ueventd started! 
 4.4.3 FirstStageMain第一阶段,该阶段所挂载的文件系统都属于ramdisk,运行在虚拟内存上。 c @system\core\init\first_stage_mount.cppint FirstStageMain(int argc, char** argv) {
    ...
    //Step 1. 创建&挂载最基本的文件系统
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));//将/dev设置为tmpfs并挂载,设置0755权限,tmpfs是在内存上建立的文件系统(Filesystem)
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    ...
    //Step 2. 初始化log系统并打印
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    ...
    LOG(INFO) << "init first stage started!";
    ...
    //Step 3. 加载内核驱动模块
    if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console,
                           module_count)) {
        ...
    }
    ...
    //Step 4.挂载分区(system、vendor、product等分区)
    if (!DoFirstStageMount(!created_devices)) {
        LOG(FATAL) << "Failed to mount required partitions early ...";
    }
    ...
    //Step 5.初始化Android的安全框架Android Verified Boot
    SetInitAvbVersionInRecovery();
    ...
    //Step 6.执行下一个阶段
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    ...
    execv(path, const_cast<char**>(args));//exec系列函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID,即重新回到main.cpp
    ...}Step 1. 创建&挂载最基本的文件系统,创建了如下五类文件系统: 
 相关挂载情况如下: Step 2. 结合dev/kmsg节点,初始化log系统,并在第一阶段开始时,打印第一条log none [ 1.004958]c1 init: init first stage started! Step 3. 加载内核驱动模块,第一阶段加载的内核模块如下: none [ 1.012653]c1 init: Loaded kernel module /lib/modules/sprd_wdt.ko [ 1.020197]c0 init: Loaded kernel module /lib/modules/sc2721-regulator.ko [ 1.022427]c0 init: Loaded kernel module /lib/modules/nvmem-sc27xx-efuse.ko [ 1.026126]c0 init: Loaded kernel module /lib/modules/spool.ko [ 1.033668]c0 init: Loaded kernel module /lib/modules/sipx.ko [ 1.047553]c0 init: Loaded kernel module /lib/modules/seth.ko [ 1.048526]c0 init: Loaded kernel module /lib/modules/usb_f_vser.ko ... Step 4. 挂载分区。创建/first_stage_ramdisk并挂载,然后将根目录切换到/first_stage_ramdisk,并挂载system、vendor 、product等系统分区,挂载信息如上。 4.4.4 SetupSelinux该阶段主要是初始化Selinux权限相关业务,同时在业务流程最后一步时,重新执行system/bin/init程序,再次启动下一个阶段SecondStageMain。 c @system\core\init\selinux.cppint SetupSelinux(char** argv) {
    ...
    LOG(INFO) << "Opening SELinux policy";
    ...
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
    ...
    return 1;}该阶段log打印如下: none [ 2.547025]c0 init: Opening SELinux policy 4.4.5 SecondStageMain第二阶段,涉及到文件系统挂载、属性服务等系统相关业务,其中最主要的一点去解析rc文件(创建目录,修改权限,挂载分区,启动服务进程等),以期让开机流程进入下一阶段。 c @system\core\init\init.cppint SecondStageMain(int argc, char** argv) {
    //Step 1.初始化log
    SetStdioToDevNull(argv);
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";
    ...
    //Step 2.属性服务初始化,读取默认属性配置
    PropertyInit();
    ...
    //Step 3.挂载其他文件系统,如/apex
    MountExtraFilesystems();
    ...
    //Step 4.启动属性服务
    StartPropertyService(&property_fd);
    ...
    //Step 5.加载开机rc文件
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    LoadBootScripts(am, sm);
    ...
    //Step 6.设置进程优先级,主进程不能退出
    setpriority(PRIO_PROCESS, 0, 0);
    while (true) {
        ...
    }
    return 0;}Step 1. 初始化log,该阶段log打印如下: none [ 3.226672]c0 init: init second stage started! Step 2. 属性服务初始化,读取默认属性配置。获取system/build.prop、vendor/build.prop、/odm/build.prop、/product/build.prop等其他build.prop属性,并加载到properties map结构中,然后通过MMAP映射到全局内存中,供所有进程调用; none [ 3.481952]c0 init: Parsing file /system/etc/init/hw/init.rc... [ 3.489693]c0 init: Parsing file /init.environ.rc... [ 3.490110]c0 init: Parsing file /system/etc/init/hw/init.usb.rc... [ 3.491867]c0 init: Parsing file /init.sl8541e_1h10_32b.rc... [ 3.493283]c0 init: Parsing file /vendor/etc/init/hw/init.sl8541e_1h10_32b.rc... [ 3.494372]c0 init: Parsing file /vendor/etc/init/hw/init.sl8541e_1h10_32b.usb.rc... [ 3.509664]c0 init: Parsing file /vendor/etc/init/hw/init.ram.rc... ... 解析init.rc会把一条条命令映射到内存中,然后依次启动,启动顺序如下: none on on early-init:在初始化早期阶段触发 on init:在初始化阶段触发 on late-init:在初始化晚期阶段触发 on boot/charger:当系统启动/充电时触发 on property:当属性值满足条件时触发 Step 6. 设置进程优先级,主进程不能销毁和退出。 4.5 Zygote进程4.5.1 Zygote进程启动脚本(1)rc文件编译 c @system\core\rootdir\Android.bp
prebuilt_etc {
    name: "init.rc",
    src: "init.rc",
    sub_dir: "init/hw",
    required: [
        "fsverity_init",
        "platform-bootclasspath",
    ],}(2)init.rc c @system\core\rootdir\init.rc...import /system/etc/init/hw/init.${ro.zygote}.rc//导入zygote的rc文件,ro.zygote属性可根据系统读取...# Mount filesystems and start core system services.on late-init    ...
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start //在开机初始化晚期阶段,触发zygote启动
    ...# It is recommended to put unnecessary data/ initialization from post-fs-data# to start-zygote in device's init.rc to unblock zygote start.on zygote-start && property:ro.crypto.state=unencrypted
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary(3)init.zygote32.rc r @system\core\rootdir\init.zygote32.rc
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
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    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
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal(4)zygote启动log none [ 7.916749]c3 init: starting service 'zygote'... 4.5.2 Zygote进程(1)zygote编译文件 none @frameworks\base\cmds\app_process\Android.bp
cc_binary {
    name: "app_process",
    srcs: ["app_main.cpp"], 
    ...
}(2)app_process启动 c int main(int argc, char* const argv[]){
    ...
    while (i < argc) {//读取rc文件传进来的参数
        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;
        } 
        ...
    }
    ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//启动ZygoteInit
    } 
    ...}(3)AndroidRuntime c void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote){
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());
    ...
    //通过反射启动函数
    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
        }
    }
    ...}当前流程会打印如下log: none 01-01 08:00:08.538 387 387 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<< 4.5.3 Zygote进程(java)(1)ZygoteInit java @frameworks\base\core\java\com\android\internal\os\ZygoteInit.javapublic static void main(String[] argv) {
    ...
    try {
        //Step 1. 预加载资源文件
        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
        }
        ...
        //Step 2.注册Zygote的socket监听接口
        zygoteServer = new ZygoteServer(isPrimaryZygote);
        //Step 3.创建system_server进程
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
            if (r != null) {
                r.run();
                return;
            }
        }
        //Step 4.主线程loop消息循环
        caller = zygoteServer.runSelectLoop(abiList);
    } 
    ...}Step 1. 提前加载类,加载系统资源(如一些公共的库、SDK等),这样当程序被fork处理后,应用的进程内已经包含了这些系统资源,大大节省了应用的启动时间。 (2)forkSystemServer java @frameworks\base\core\java\com\android\internal\os\ZygoteInit.javaprivate 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",
    };//启动SystemServer相关参数
    ...
    try {
        ...
        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid, parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);//fork出SystemServer进程
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
    /* For child process */
    if (pid == 0) {
        ...
        return handleSystemServerProcess(parsedArgs);//通过反射调用SystemServer进程的main函数
    }
    return null;}(3)handleSystemServerProcess java @frameworks\base\core\java\com\android\internal\os\RuntimeInit.javaprotected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;
    try {
        cl = Class.forName(className, true, classLoader);//反射调用类:com.android.server.SystemServer
    }
    ...
    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });//反射调用方法:main
    } 
    ...
    return new MethodAndArgsCaller(m, argv);}4.6 SystemServer进程Android系统在启动的时候,在启动两个重要的进程,一个是Zygote进程,另一个是由zygote进程fork出来的system_server进程。SystemSever负责启动系统的各项服务,Android系统中Java世界的核心Service都在这里启动。 4.6.1 main函数由上一章节我们知道,SystemServer的入口函数是main方法,如下: java @frameworks\base\services\java\com\android\server\SystemServer.javapublic static void main(String[] args) {
    new SystemServer().run();}private void run() {
    ...    
    Slog.i(TAG, "Entered the Android system server!");
    ...
    // Start services.
    try {
        t.traceBegin("StartServices");
        startBootstrapServices(t);//引导服务
        startCoreServices(t);//核心服务
        startOtherServices(t);//其他服务
    } 
    ...
    // Loop forever.
    Looper.loop();//主线程循环队列
    throw new RuntimeException("Main thread loop unexpectedly exited");}SystemServer进程成功启动,会打印如下log: none 01-01 08:00:21.430 1001 1001 I SystemServer: Entered the Android system server! 4.6.2 SystemServer中启动服务在一系列的java服务中,可以分为三类:系统boot级别服务、核心服务、其他服务,其对应如下: 
 4.7 Home进程一般情况下,Android原生的软体会包含两个home进程,一个是Settings进程的Fallbackhome,一个是Launcher进程。 4.7.1 Home进程的编译(1)FallbackHome编译 none @packages\apps\Settings\Android.bp
android_app {
    name: "Settings",
    defaults: ["platform_app_defaults"],
    platform_apis: true,
    certificate: "platform",
    system_ext_specific: true,
    privileged: true,
    ...
}(2)Launcher进程编译 none @packages\apps\Launcher3\Android.mk include $(CLEAR_VARS) ... LOCAL_PACKAGE_NAME := Launcher3QuickStepGo LOCAL_PRIVILEGED_MODULE := true LOCAL_SYSTEM_EXT_MODULE := true LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3QuickStep ... 4.7.2 Launcher进程启动FallbackHome是系统由未解密到解密过程的一个过度界面,只要用户把系统解锁过一次后,FallbackHome收到解锁广播就会退出,而WMS检测到当前Acitivity栈是空的,进而启动真正的Launcher。由于FallbackHome没有界面,所以可能会出现一个问题,home进程切换时会出现空白界面,接下来才是显示Launcher的一个图标界面。 java @packages\apps\Settings\src\com\android\settings\FallbackHome.javaprotected void onCreate(Bundle savedInstanceState) {
    ...
    registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));//注册ACTION_USER_UNLOCKED广播
    maybeFinish();}private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        maybeFinish();//接收ACTION_USER_UNLOCKED广播
    }};private void maybeFinish() {
    if (getSystemService(UserManager.class).isUserUnlocked()) {
        final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME);
        final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);//查询home包名信息,此处一般是返回Launcher的信息
        if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
            Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
            mHandler.sendEmptyMessageDelayed(0, 500);//间隔500ms轮询
        } else {
            Log.d(TAG, "User unlocked and real home found; let's go!");
            getSystemService(PowerManager.class).userActivity(
                    SystemClock.uptimeMillis(), false);
            finish();//结束当前Activity,启动Launcher应用
        }
    }}4.7.3 FallbackHome进程启动(1) 启动home进程 java @frameworks\base\services\core\java\com\android\server\wm\RootWindowContainer.javavoid startHomeOnEmptyDisplays(String reason) {
    forAllTaskDisplayAreas(taskDisplayArea -> {
        if (taskDisplayArea.topRunningActivity() == null) {
            startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea,
                    false /* allowInstrumenting */, false /* fromHomeKey */);
        }
    });}(2) ACTION_USER_UNLOCKED广播发送 java @frameworks\base\services\core\java\com\android\server\am\UserController.javavoid finishUserUnlocked(final UserState uss) {
    ...
    if (!mInjector.getUserManager().isPreCreated(userId)) {
        // Dispatch unlocked to external apps
        final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
        unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        unlockedIntent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
        mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
                null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                Binder.getCallingUid(), Binder.getCallingPid(), userId);
    }
    ...}五、相关资源5.1 开机log串口+logcat:https://download.csdn.net/download/u013320490/88800008 六、小结        本文章涉猎Android多个层级,旨在梳理整体流程,对Android设备的启动有一个感性的认识,能够达到一定逻辑自洽。 七、参考资料
 作者:林奋斗同学,转自博客园 https://www.cnblogs.com/zhiqinlin/p/18001113 该文章在 2024/2/1 16:39:13 编辑过 | 关键字查询 相关文章 正在查询... |