Android 开机流程

Android 开机流程

Android 系统启动流程

1.启动电源即系统启动:

当电源键按下时引导芯片代码从预定义的地方(固化在ROM)开始执行。加载引导程序BootLoader到RAM中,然后执行。

2. 引导程序BootLoader

引导程序BootLoader是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。

3. Linux Kernel 启动:

Kernel启动时,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置时,它首先在文件系统中寻找init.rc文件并启动init进程。

4. init进程启动

  • init进程是Android系统中用户控件的第一个进程,进程号为1。

主要作用:初始化和启动属性服务,并且启动Zygote进程。

可分为三个部分

  • 创建和挂载启动所需的文件目录
  • 初始化和启动属性服务
  • 解析init.rc配置文件并启动Zygote进程

对于init进程的功能分为4部分:

  • 解析并运行所有的init.rc相关文件
  • 根据rc文件,生成相应的设备驱动节点
  • 处理子进程的终止(signal方式)
  • 提供属性服务的功能

下面是init.cpp中部分代码,可以看到parser.ParseConfig("/system/etc/init/hw/init.rc")此处对init.rc进行了解析。

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

init.rc是Android初始化语言(Android Init Language,这里简称为AIL)的脚本写成的文件

下面是init.rc文件中的部分代码:

on late-init
 ..........
 # Now we can start zygote for devices with file based encryption
    trigger zygote-start
    .........

可以看到,在这里启动了zygote进程。Android8.0以后对init.rc进行了拆分:其中Zygote进程拆分到了init.zygote32.rc(32位)、init.zygote64.rc(64位)文件中了。就以64位的文件为例:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    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

很明显有一些我们认识的,比如wifi、媒体、网络、相机等等。

5.Zygote进程启动:

**主要作用:**创建Java虚拟机并为Java虚拟机注册JNI方法,创建服务器端Socket,启动SystemServer进程。它是java的第一个进程,由它直接或间接孵化出了系统中的整个Java进程。

在Android系统中,DVMART、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程fork而来的。

zygote进程主要做了如下几个工作:

  1. 创建AppRuntime并调用其start方法,启动Zygote进程(此过程是在init进程结束的时候执行的)
  2. 创建java虚拟机并为java虚拟机注册JNI方法
  3. 通过JNI调用ZygoteInit的main函数进入Zygote的java框架层
  4. 通过registerZygoteSocket方法创建服务器Socket
  5. 启动SystemServer进程
  6. 通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程

6.System Server进程启动:

**主要作用:**启动Binder线程池和SystemServiceManager,并启动各种系统服务。我们所熟知的AMS、WMS、PMS等等都是由它来创建的。

主要工作如下:

  1. 启动Binder线程池,这样就可以与其他进程进行通信。
  2. 创建SystemServiceManager,其用于对系统服务进程创建、启动和生命周期管理。
  3. 启动各种系统服务(引导服务、核心服务、其他服务)。

7.Launcher启动:

SystemServer进程启动的AMS会启动Launcher,系统启动的最后一步是启动一个应用程序来显示系统中已经安装的应用程序,这个应用程序就叫做LauncherLanucher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上。

主要作用有:

  1. 作为Android系统的启动器,用于启动应用程序
  2. 作为Android系统的桌面,用于显示和管理应用程序的快捷图标或者其他桌面组件。

Launcher的启动过程:

  1. 首先SystemServer进程会在启动的过程中启动PackageManagerService,PackageManagerService启动后会将系统中的应用程序安装完成,再此前已经启动的AMS会将Launcer启动起来,启动Launcher的入口为AMS的systemReady方法,它在Systemserver的startOtherServices(启动其他服务)方法中被调用。(注:AMS是在startBootstrapServices()方法中启动的)。
  2. systemReady方法中最终是通过Intent进行启动的,其中action为:Intent.ACTION_MAIN、Category为Intent.CATEGORY_HOME。启动方法与普通的activity方式类似。

Launcher中应用图标显示过程:

  1. 首先加载所有应用信息是在内部创建了一个HandlerThread,然后通过handler循环调用来加载所以应用的。然后把allApps信息传递给一个AllAppsRecyclerView控件的adapter来进行展示的。
  2. Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标的,每一个工作区都是用来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分为n个单元格,每个单元格用来显示一个应用程序的快捷图标。

大致流程就是下图:

在这里插入图片描述

8.DirectBoot模式

是不是这样就把Launcher启动了呢?没有那么简单,这中间还有一点弯弯绕绕!搜索系统源码可以发现Settings中有一个Activity同样声明了CATEGORY_HOME,即FallbackHome。如果把锁屏方式设置为无,重启之后可能是先看到一个“android正在启动”的页面,然后才真正出现了Launcher

​ 那么问题来了,既然有两个声明了CATEGORY——HOME的页面,为什么开机后没有出现一个选择框让用户选择启动哪个呢?查阅官方资料知道Android 7.0之后增加了一个DirectBoot模式,大致内容如下:

​ 当设备已开机但用户尚未解锁设备时,Android 7.0 将在安全的“直接启动”模式下运行。为支持此模式,系统为数据提供了两个存储位置

  • 凭据加密存储,这是默认存储位置,仅在用户解锁设备后可用。
  • 设备加密存储,该存储位置在“直接启动”模式下和用户解锁设备后均可使用。

默认情况下,应用不会在“直接启动”模式下运行。如果您的应用需要在“直接启动”模式下执行操作,您可以注册应在此模式下运行的应用组件。

…详细信息:https://developer.android.google.cn/training/articles/direct-boot.html?hl=zh-cn#java

ok!继续对比两个应用,FallbackHomeManifestzhong 声明了android:directBootAware="true",并且声明了自己的优先级为-1000,而Launcher中并没有,因此刚开机时其实只有FallbackHome这个页面会被检索到,也就不会出现应用选择的对话框了。然后**FallbackHome这个界面会一直检测当前是否已经具备唤醒正常Launcher的条件,如果OK,就finish掉自己。**代码片段如下:

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);
        if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
            if (UserManager.isSplitSystemUser()
                && UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
                // This avoids the situation where the system user has no home activity after
                // SUW and this activity continues to throw out warnings. See b/28870689.
                return;
            }
            Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
            mHandler.sendEmptyMessageDelayed(0, 500);
        } else {
            Log.d(TAG, "User unlocked and real home found; let's go!");
            getSystemService(PowerManager.class).userActivity(
                SystemClock.uptimeMillis(), false);
            finish();
        }
    }
}

再然后经过一系列的逻辑处理,最后Launcher就登场了。

DirectBoot阻塞开机详细介绍在这里:
https://blog.csdn.net/qq_43369592/article/details/123113991