Android 开机流程解析

目录

第一章 概述

 第二章 Init启动

第三章 Android关键进程启动


第一章 概述


开机作为使用手机的第一步操作,在长按电源键之后到我们可视化可操作的界面中间包含了很多任务,诸如文件系统挂载、native service启动、zygote启动、launcher启动等,而这些任务是怎么执行的,又是在哪个阶段执行的? 
我们先来看下当我们按下电源键之后,我们的手机执行这些任务的流程图:


从上图中我们可以看到,当按下开机键的时候,手机开始从固化在ROM的预设代码开始执行,加载Bootloader到RAM中运行,接着Bootloader把kernel加载到内存,最终把kernel跑起来。在kernel启动的最后执行了“init”这个Android祖先进程,又init进程去进行文件系统挂载、启动native service、启动zygote等,之后把Home intent应用(Launcher等)启动起来。这个启动流程线可简略归纳为:
BootRom -> bootloader -> kernel -> init -> mount fs-> native service -> launcher。
Kernel启动的这一部分为linux操作系统通用流程,相关介绍可参考Linux Boot,本文中对此不进行展开。后续章节中将会就init启动开始直到launcher启动结束这个过程进行讲述开机启动流程。

 第二章 Init启动


所有的Linux系统都有一个较为特殊的进程, 它是Kernel启动结束后, 于userspace启动的第一个进程, 它负责启动系统, 是系统中其他进程的祖先进程,在不同系统上,它有不同的名称,但在传统意义上, 这个进程被统称为init进程。
Init作为第一个user space的进程,它是所有Android系统native service的祖先,从最根本上讲,它是为了引导/启动用户空间的各项service而存在,而为了确保各个service能正常运行,又会创建文件系统,设置权限,初始化属性等工作。Init的功能繁杂,后续章节会挑选开机相关的重点项来讲述,大致可以分为下面几项:
•    创建文件系统目录并挂载相关的文件系统 
•    初始化/设置/启动属性相关的资源 
•    解析init.rc
•    action/service管理 
2.1    init进程的创建
内核在启动初期,会调用跟平台架构相关的汇编代码,在架构相关的汇编代码运行完之后,程序跳入了架构无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段。接着后续会调用rest_init和kernel_thread,init进程的创建也是从这里开始的 而通过调用kernel_thread,1号进程被创建出来,但此时,它运行的还不是init,只有经过如下步骤,init才会正式启动。中间调用的函数也比较多,还涉及到空间的切换,这里用一个图来表示:
 
2.1章节讲了init进程的创建过程,接下来看下init进程在做些什么。Init进程的入口是main函数,查看init的功能实现,就从这个函数开始,这里首先来关注下文件系统挂载。
2.2    文件系统挂载
Android有很多分区,如system/userdata/cache/vendor/odm等分区,它们是何时挂载的?如何挂载的?接下去会进行相应分析。
2.2.1    system/vendor/product分区
在描述这一部分之前得先提一下动态分区。动态分区是Android 10上新功能,是Android系统的用户空间分区系统,system,vendor,product等只读分区被打包到super.img;在super.img的元数据(metadata)中记录着每个动态分区的名称和在Super分区中的存储范围。
在Init First Stage执行期间会解析和校验Super 分区的元数据,并创建虚拟的块设备对应各个动态分区,从而对system/vendor/product等分区进行挂载。而这一切的发起者是DoFirstStageMount()。

1.    bool FirstStageMount::DoFirstStageMount() {  
2.        if (!IsDmLinearEnabled() && fstab_.empty()) { //判断fstab中是否有logical标志,若无,则返回
3.            // Nothing to mount.  
4.            LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";  
5.            return true;  
6.        }  
7.      
8.        if (!InitDevices()) return false;  // add super name、system/vendor/product/etc. to required_devices_partition_names_ and its info to lp_metadata_partition_
9.      
10.        if (!CreateLogicalPartitions()) return false;  //创建super内动态分区对应的逻辑分区
11.      
12.        if (!MountPartitions()) return false;  //挂载system并切换为root、vendor、product、overlayfs
13.      
14.        return true;  
15.    }  

DFSM对应的执行流向如下: 

文件系统挂载是需要挂载信息的,而这个信息通常保存在fstab文件中:fstab.$(TARGET_BOARD),对应在device board里配置的是fstab.ramdisk文件。
1.    #Dynamic partitions fstab file  
2.    #<dev> <mnt_point> <type> <mnt_flags options>  <fs_mgr_flags>  
3.      
4.    system /system ext4 ro,barrier=1 wait,avb=vbmeta_system,logical,first_stage_mount,avb_keys=/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey  
5.    vendor /vendor ext4 ro,barrier=1 wait,avb=vbmeta_vendor,logical,first_stage_mount  
6.    product /product ext4 ro,barrier=1 wait,avb=vbmeta,logical,first_stage_mount  
7.    /dev/block/platform/soc/soc:ap-ahb/20600000.sdio/by-name/metadata /metadata    ext4 nodev,noatime,nosuid,errors=panic wait,formattable,first_stage_mount  
需注意的是,必须包含“avb=xxx, logical,first_stage_mount”这样配置才可以在first_stage 进行mount。
2.2.2    metadata分区
参考system/endor/product mount流程。
2.2.3    Other分区
至此system/vendo/odm分区已经成功挂载,而其它分区的挂载则通过do_mount_all来实现。看下这个流程:
init进程会根据init.rc的规则启动进程或者服务。init.rc通过"import /init.xxx.rc"语句导入平台的规则, 例如XXX/root/init.common.rc中就有如下规则:
1.    on fs  
2.        ubiattach 0 ubipac  
3.        # exec /sbin/resize2fs -ef /fstab.${ro.hardware}  
4.        mount_all /vendor/etc/fstab.${ro.hardware}  
5.        mount pstore pstore /sys/fs/pstore  
 mount_all是一条命令,fstab.${ro.hardware}是传入的参数,在XXXboard上就是fstab.XXX。接着通过ActionManager来解析“mount_all“指令,找到指令所对应的解析函数。这个指令解析函数的对应关系,定义在system/core/init/builtins.cpp:
1.    static const Map builtin_functions = {  
2.    .....  
3.    {  
4.        "mount_all",               {1,     kMax, do_mount_all}},  
5.        .....  
6.    }  
从上面可以看出,mount_all命令对应的是do_mount_all函数,/vendor/etc /fstab.XXX是do_mount_all函数的传入参数。
do_mount_all的解析流程如下:
 
2.3    Start Property Service
Android property系统其实可以理解为键值的对应关系,即属性名字和属性值。大部分property是记录在某些文件中的, init进程启动的时候,会加载这些文件,完成property系统初始化。
2.3.1    property service的启动过程
来看property service的启动过程,代码如下:
1.    void StartPropertyService(Epoll* epoll) {  
2.        selinux_callback cb;  
3.        cb.func_audit = SelinuxAuditCallback;  
4.        selinux_set_callback(SELINUX_CB_AUDIT, cb);  
5.      
6.        property_set("ro.property_service.version", "2");  
7.      
8.        property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,  
9.                                       false, 0666, 0, 0, nullptr);  
10.        if (property_set_fd == -1) {  
11.            PLOG(FATAL) << "start_property_service socket creation failed";  
12.        }  
13.      
14.        listen(property_set_fd, 8);  
15.      
16.        if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {  
17.            PLOG(FATAL) << result.error();  
18.        }  
19.    }  
创建property_service socket用于监听进程修改property请求,通过handle_property_set_fd来处理请求,set property msg分为两类处理,msg name以“ctl.”为起始的msg 通过handle_control_message处理,主要是启动、停止、重启服务。修改其它prop时会调用property_get,然后通过bionic的__system_property_set函数来实现,而这个函数会通过socket与init的property service取得联系。整个property访问的过程可以用下图来表述:

2.3.2    property 的加载顺序
property文件的加载是在property_load_boot_defaults()中实现的,而在整个启动流程中,property的加载是在Rc文件加载之前的,其代码如下:
1.    void property_load_boot_defaults(bool load_debug_prop) {  
2.        ......  
3.        std::map<std::string, std::string> properties;  
4.        if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {  
5.            // Try recovery path  
6.            if (!load_properties_from_file("/prop.default", nullptr, &properties)) {  
7.                // Try legacy path  
8.                load_properties_from_file("/default.prop", nullptr, &properties);  
9.            }  
10.        }  
11.        load_properties_from_file("/system/build.prop", nullptr, &properties);  
12.        load_properties_from_file("/vendor/default.prop", nullptr, &properties);  
13.        load_properties_from_file("/vendor/build.prop", nullptr, &properties);  
14.        if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {  
15.            load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);  
16.        } else {  
17.            load_properties_from_file("/odm/default.prop", nullptr, &properties);  
18.            load_properties_from_file("/odm/build.prop", nullptr, &properties);  
19.        }  
20.        load_properties_from_file("/product/build.prop", nullptr, &properties);  
21.        load_properties_from_file("/product_services/build.prop", nullptr, &properties);  
22.        load_properties_from_file("/factory/factory.prop", "ro.*", &properties);  
23.      
24.        ......  
25.    }  
从代码的实现中可以看到,在正常启动流程中,property文件的加载顺序为:
 
2.4    Rc文件解析
从init main函数的代码可以看出来,根路径中只解析了init.rc,其它根路径的init.*.rc就是通过import导入进来的。
2.4.1    Rc文件的加载顺序
Rc文件的加载是在LoadBootScripts ()中实现的,而在整个启动流程中,
Rc文件按加载是在property文件加载之后的,其代码如下:
1.    static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {  
2.        Parser parser = CreateParser(action_manager, service_list);  
3.      
4.        std::string bootscript = GetProperty("ro.boot.init_rc", "");  
5.        if (bootscript.empty()) {  
6.        std::string bootmode = GetProperty("ro.bootmode", "");  
7.        if (bootmode == "charger") {  
8.            parser.ParseConfig("/vendor/etc/init/charge.rc");  
9.        } else {  
10.                parser.ParseConfig("/init.rc");  
11.                if (!parser.ParseConfig("/system/etc/init")) {  
12.                        late_import_paths.emplace_back("/system/etc/init");  
13.                }  
14.                if (!parser.ParseConfig("/product/etc/init")) {  
15.                        late_import_paths.emplace_back("/product/etc/init");  
16.                }  
17.                if (!parser.ParseConfig("/product_services/etc/init")) {  
18.                        late_import_paths.emplace_back("/product_services/etc/init");  
19.                }  
20.                if (!parser.ParseConfig("/odm/etc/init")) {  
21.                        late_import_paths.emplace_back("/odm/etc/init");  
22.                }  
23.                if (!parser.ParseConfig("/vendor/etc/init")) {  
24.                        late_import_paths.emplace_back("/vendor/etc/init");  
25.                }  
26.        }  
27.        } else {  
28.            parser.ParseConfig(bootscript);  
29.        }  
30.    }  
从代码的实现中可以看到,init会去先加载init.rc,接着加载各路径下的rc文件,在正常启动流程中,rc文件的加载顺序为:
 
2.5    Action的执行顺序与Class阶段设置的建议
在自定义service时,可以通过声明class xxx来指定service的启动阶段,那么这个启动阶段该如何选取呢?
目前系统常用的class阶段按顺序执行的有,附带class设置建议:
    early_hal (HALs required before storage encryption can get unlocked (FBE/FDE))
    hal (normal hal)
    core (system core base service)
    main (normal service)
    late_start (the last boot class, wait for all system resource ready)
其启动的时序与action的执行对应关系如下图
 
可以按照其时序结合自身需求添加到对应class。
2.6    Bootchart 
通过bootchart 工具可以直观的看出init启动 启动到homescreen这段时间啊系统负载和启动耗时。Bootchart init command是在init.rc的post-fs-data action中执行的。
1.    # Start bootcharting as soon as possible after the data partition is  
2.        # mounted to collect more data.  
3.        mkdir /data/bootchart 0755 shell shell  
4.        bootchart start  
init 进程默认已经创建了data/bootchart目录,启动bootchart功能只需要在data/bootchart/目录创建enabled文件即可,
重启手机,采样的数据存在data/bootchart目录中,运行system/core/init/grab-bootchart.sh即可生成bootchart.png。


第三章 Android关键进程启动


上章介绍了init进程执行Action的内容和顺序,并在boot和nonencrypted Action中启动了core、main、late-start class的service。本章节将重点介绍开机中比较关键的service,这些service异常将会导致开机失败。
3.1    Surfaceflinger and bootAnimation
首先介绍用户可以看到的开机动画,开机动画从surfaceflinger进程启动后开始执行到launcher启动完成后退出。
Surfaceflinger service属于class core类型服务,在init 执行boot action阶段会被启动。且如果surfaceflinger启动失败,在自身重启的同时也会导致zygote重启。所以在android启动阶段首先要关注surfaceflinger是否启动正常。
1.    service surfaceflinger /system/bin/surfaceflinger  
2.        class core animation  
3.        user system  
4.        group graphics drmrpc readproc  
5.        onrestart restart zygote  // surfaceflinger restart导致zygote重启
6.        writepid /dev/stune/foreground/tasks  
Surfaceflinger 服务的实现不是本篇文章介绍的重点,感兴趣的可以自己查看相关资料,这里主要介绍surfaceflinger 如何启动bootanim service的。
Bootanim service 虽然属于class core,但是disable,在init 执行boot action阶段不会被启动,其启动入口是在surfaceflinger::init方法中。
Bootanim.rc:
1.    service bootanim /system/bin/bootanimation  
2.        class core animation  
3.        user graphics  
4.        group graphics audio  
5.        disabled  
6.        oneshot  
7.        writepid /dev/stune/top-app/tasks
SurfaceFlinger.cpp:
1.    void SurfaceFlinger::init() {  
2.        ……  
3.        if (getHwComposer().hasCapability(//创建propertysetthread  
4.            HWC2::Capability::PresentFenceIsNotReliable)) {  
5.            mStartPropertySetThread = new StartPropertySetThread(false);  
6.        } else {  
7.            mStartPropertySetThread = new StartPropertySetThread(true);  
8.        }  
9.        //运行StartPropertySetThread  
10.        if (mStartPropertySetThread->Start() != NO_ERROR) {  
11.            ALOGE("Run StartPropertySetThread failed!");  
12.        }  
13.        ……  
14.    }  
继续看下StartPropertySetThread做了什么:
1.    status_t StartPropertySetThread::Start() {  
2.        return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);  
3.    }  
4.    bool StartPropertySetThread::threadLoop() {  
5.        // Set property service.sf.present_timestamp, consumer need check its readiness  
6.        property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");  
7.        // Clear BootAnimation exit flag  
8.        property_set("service.bootanim.exit", "0");  
9.        // Start BootAnimation if not started  
10.        property_set("ctl.start", "bootanim");//开始运行bootanim  
11.        // Exit immediately  
12.        return false;  
13.    }  
通过property service ctrl msg启动bootanim service,并设置service.bootanim.exit 为0,该属性值决定开机动画是否退出,其流程如下图所示:
 
在图中1.8的android func中会重复播放android默认动画,并在每次播放后都执行checkExit来读取service.bootanim.exit 属性值,当service.bootanim.exit属性值为1时会执行requestExit将mExitPending 值设置为ture,退出循环播放,Bootanim执行结束退出,如下代码:
1.    bool BootAnimation::android()  
2.    {  
3.        ......  
4.        do {  
5.            ......  
6.            EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);  
7.            if (res == EGL_FALSE)  
8.                break;  
9.      
10.            // 12fps: don't animate too fast to preserve CPU  
11.            const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);  
12.            if (sleepTime > 0)  
13.                usleep(sleepTime);  
14.      
15.            checkExit();  
16.        } while (!exitPending());  
17.      
18.        glDeleteTextures(1, &mAndroid[0].name);  
19.        glDeleteTextures(1, &mAndroid[1].name);  
20.        return false;  
21.    }  
CheckExit实现如下:
1.    void BootAnimation::checkExit() {  
2.        // Allow surface flinger to gracefully request shutdown  
3.        char value[PROPERTY_VALUE_MAX];  
4.        property_get(EXIT_PROP_NAME, value, "0");  
5.        int exitnow = atoi(value);  
6.        if (exitnow) {  
7.            requestExit();  
8.            mCallbacks->shutdown();  
9.        }  
10.    }  
下面看下service.bootanim.exit是如何被修改的,当android系统桌面应用被启动后并且进入Idle状态时会通知surfaceflinger将service.bootanim.exit设置为1,具体的流程如下:
 
在上图15:bootFinished()中将service.bootanim.exit设置为1。bootanim 进程在checkExit时检测到service.bootanim.exit=1时退出循环播放。如果bringup中出现动画不结束的情况,可以根据上面的流程check。
bootFinished()实现如下:
1.    void SurfaceFlinger::bootFinished()  
2.    {  
3.        ……  
4.        if (mVrFlinger) {  
5.        mVrFlinger->OnBootFinished();  
6.        }  
7.      
8.        // stop boot animation  
9.        // formerly we would just kill the process, but we now ask it to exit so it  
10.        // can choose where to stop the animation.  
11.        property_set("service.bootanim.exit", "1"); //关闭bootanim  
12.      
13.        const int LOGTAG_SF_STOP_BOOTANIM = 60110;  
14.        LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,  
15.                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));  
16.      
17.        sp<LambdaMessage> readProperties = new LambdaMessage([&]() {  
18.            readPersistentProperties();  
19.        });  
20.        postMessageAsync(readProperties);  
21.    }  
3.2    ServiceManager
ServiceManager service属于class core类别的服务,在init 执行core action阶段会被启动。ServiceManager启动异常会导致zygote、surfaceflinger、media 主要系统服务重启。而且被标识为critical 服务,当在4分钟内重启超过4次系统会进入recovery模式。ServiceManager是系统服务的守护进程,用来管理android各种服务,并向client提供注册/查询/获取server远程接口的方法。
1.    service servicemanager /system/bin/servicemanager  
2.        class core animation  
3.        user system  
4.        group system readproc  
5.        critical  
6.        onrestart restart healthd  
7.        onrestart restart zygote  
8.        onrestart restart audioserver  
9.        onrestart restart media  
10.        onrestart restart surfaceflinger  
11.        onrestart restart inputflinger  
12.        onrestart restart drm  
13.        onrestart restart cameraserver  
14.        onrestart restart keystore
15.        onrestart restart gatekeeperd
16.        writepid /dev/cpuset/system-background/tasks  
17.        shutdown critical  
ServiceManager 在启动中主要完成下面三件事情:
•    打开dev/binder设备
1.    int main(int argc, char** argv)  
2.    {  
3.        struct binder_state *bs;  
4.        union selinux_callback cb;  
5.        char *driver;  
6.      
7.        if (argc > 1) {  
8.            driver = argv[1];  
9.        } else {  
10.            driver = "/dev/binder";  
11.        }  
12.      
13.        bs = binder_open(driver, 128*1024);  
•    通知binder设备,将ServiceManager设置为context_manager
1.    if (binder_become_context_manager(bs)) {  
2.        ALOGE("cannot become context manager (%s)\n", strerror(errno));  
3.        return -1;  
4.    }  
•    循环读取binder设备,检测是否有service binder请求,当检测到请求后调用svcmgr_handler处理
1.    binder_loop(bs, svcmgr_handler);  
svcmgr_handler 提供了search、add、get service 请求对应的处理方法。当客户端要与服务端进行通信时,首先通过Service Manager来查询和取得所要交互的服务。而每个服务也要向servicemanager注册自己能提供的服务。而注册服务实际上是通过在本地创建sm代理BpServiceManager并调用其addService()函数实现的。
3.2.1    HwServiceManager
HwServiceManage用于HIDL的管理。Hwservicemanager的主程序实现在system/hwservicemanager/service.cpp;它同样是一个很关键的service,通过看它的rc文件定义可以知道,如果此service启动失败,系统也会出现问题:
1.    service hwservicemanager /system/bin/hwservicemanager  
2.        user system  
3.        disabled  
4.        group system readproc  
5.        critical  
6.        onrestart setprop hwservicemanager.ready false  
7.        onrestart class_restart hal  
8.        onrestart class_restart early_hal  
9.        writepid /dev/cpuset/system-background/tasks  
10.        class animation  
11.        shutdown critical  
ServiceManager要先于所有其他HIDL service执行,否则所有其他HIDL service都获取不到servicemanager,需要等待,并打印:
"Waited for hwservicemanager.ready for a second, waiting another..."
也就是其它的HIDL service都要等到hwservicemanager执行并设置prop:” hwservicemanager.ready”为true之后才可以执行。来看下这个prop何时会修改:
1.    int main() {  
2.        ServiceManager *manager = new ServiceManager();  // IServiceManager的子类  
3.      
4.        if (!manager->add(serviceName, manager)) {  
5.            ALOGE("Failed to register hwservicemanager with itself.");  
6.        }  
7.        //...  
8.        rc = property_set("hwservicemanager.ready", "true");  
9.        //...  
3.3    Zygote
Zygote是native应用程序属于class main,在init 执行class main阶段会被启动。
1.    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server  
2.        class main  
3.        priority -20  
4.        user root  
5.        group root readproc reserved_disk  
6.        socket zygote stream 660 root system  
7.        onrestart write /sys/android_power/request_state wake  
8.        onrestart write /sys/power/state on  
9.        onrestart restart audioserver  
10.        onrestart restart cameraserver  
11.        onrestart restart media  
12.        onrestart restart netd  
13.        onrestart restart wificond  
14.        writepid /dev/cpuset/foreground/tasks  
 Zygote是所有android java进程的父进程,是java世界的入口。它实现以下几个功能如下:
 
接下来针对流程图中的关键步骤,做些说明:
startVM——该函数中主要是初始化VM的参数。需要重点关注其中dalvik heapsize的初始化,如果没有配置正确的参数或者使用默认的参数很有可能导致手机无法进入Launcher。因为目前APP占用的heapsize都比较大,使用默认参数很容易出现OOM导致应用不断重启。
startReg——注册JNI函数,遍历gRegJNI数组中JNI register 方法注册JNI method。注册JNI方法后,会通过JNI调用java class(zygoteInit)的main函数进入java世界。
registerServerSocket——通过获取环境变量值得到zygote文件描述符,根据该文件描述符创建socket,用来和ActivityManagerService通信。AMS通过Process.start来创建新的进程,而Process.start会先通过socket连接到zygote进程,并最终由zygote完成进程创建。
Preload——预加载类和资源, zygote通过预加载类和资源可以加快子进程的执行速度和优化内存。因为预加载的类和资源较多,在开机优化过程中也需要重点关注preload的耗时。
Class 预加载文件路径:/system/etc/preloaded-classes;
resource预加载文件路径:frameworks/base/core/res/res/values/arrays.xml
forkSystemServer——启动system_server进程,android java 系统服务都将驻留在该进程中。是android framework核心。设置systemserver 进程uid和gid,process name,class name。 
3.4    SystemServer
上面介绍了SystemServer的实际进程名是system_server。System_server作为zygote fork的第一个进程,不言而喻具很重要。如果system_server退出也会导致zygote进程退出,具体的处理是在Zygote Sigchldhandler中。具体看下com.android.server.systemserver的入口函数
1.    public static void main(String[] args) {  
2.        new SystemServer().run();  
3.    }  
Run方法中主要是启动android 系统服务
1.    // Start services.  
2.            try {  
3.                traceBeginAndSlog("StartServices");  
4.                startBootstrapServices();  
5.                startCoreServices();  
6.                startOtherServices();  
7.                SystemServerInitThreadPool.shutdown();  
8.            } catch (Throwable ex) {  
9.                Slog.e("System", "******************************************");  
10.                Slog.e("System", "************ Failure starting system services", ex);  
11.                throw ex;  
12.            } finally {  
13.                traceEnd();  
14.            }  
将service分为三个等级,开机相关服务、核心服务和其他服务
•    BootStrap Services:
ActivityManagerService、Installer、PowerManagerservice、LightService、DisplayManagerService、PackageManagerservice、SensorService(native)等
•    CoreService
BatteryService、UsageStatsService、webViewUpdateService
•    OtherService
TelecomLoaderService、CameraService(java)、AccountManagerService、ContentService、AlarmManagerService、InputManagerService、VRManagerService(VR 系统服务)、WindowManagerService、BluetoothService、StartOtherService()等
最后调用ActivityManagerService.SystemReady() 启动Home 进程(Launcher),发送ACTION_BOOT_COMPLETED Intent。
3.5    Launcher
3.4章节讲到,Laucher是由ActivityManagerService.SystemReady()启动的,下面通过一张流程图简单介绍一下Launcher的启动流程:
 
我们来看七步的getHomeIntent()方法,看一下getHomeIntent是如何实现构造Intent对象的:
1.    Intent getHomeIntent() {  
2.        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);  
3.        intent.setComponent(mTopComponent);  
4.        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);  
5.        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {  
6.            intent.addCategory(Intent.CATEGORY_HOME);  
7.        }  
8.        return intent;  
9.    }  
可以发现, Intent对象中添加了Intent.CATEGORY_HOME常量,这是Home应用的标志,一般系统的启动页面Activity都会在manifest.xml中配置这个标志:
在Launcher应用程序中可以找到这个标志:
1.    <category name="intent.category.HOME" />  
在startHomeActivity去启动这个Intent。而在startHomeActivity中会先通过ActivityStarter启用scheduleResumeTopActivities()方法,这个方法中就是Activity的启动流程的逻辑了,此处不展开。
1.    void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {  
2.        mSupervisor.moveHomeStackTaskToTop(reason);  
3.      
4.        mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)  
5.                .setOutActivity(tmpOutRecord)  
6.                .setCallingUid(0)  
7.                .setActivityInfo(aInfo)  
8.                .execute();  
9.        mLastHomeActivityStartRecord = tmpOutRecord[0];  
10.        …… 
11.    }  
至此声明有Intent.CATEGORY_HOME的应用便会启动,这其中包含Launcher,当Launcher启动时开机动画仍在不断的播放,所以Launcher会进入idle状态,此后开机动画便会停止播放(这个流程见3.1 Surfaceflinger and bootAnimation),当开机动画结束后,AMS会唤醒栈顶的activity,此时栈顶只有一个activity,那便是Launcher,这些都是AMS的一些处理流程,这里边不进行展开,至此开机启动流程完成。

  • 4
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值