Android:启动流程

Posted 临木小屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android:启动流程相关的知识,希望对你有一定的参考价值。

android启动流程

第一步:启动电源以及系统启动

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

第二步:引导程序

引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针 对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运 营商加锁和限制的地方。
引导程序分两个阶段执行。
第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序; 第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程 序可以根据配置参数或者输入数据设置内核。 Android引导程序可以在\\bootable\\bootloader\\legacy\\usbloader找到。传统的加载器包含两个文件, 需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数; main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签

第三步:内核

Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表, 加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第 一个进程

第四步:init进程 (搭建环境+启动zygote)

init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进程,并调用init中的main()方法执行init进程的职责。

  1. 创建和挂载启动所需的文件目录
  2. 初始化和启动属性服务
  3. 解析init.rc配置文件并 启动zygote进程
    3.1 ----》SystemServers—》开启一系列服务(AMS、WMS、PKMS、PMS、、、、)
    3.2 ----》Launcher --> app —> 从 zygote fork 子进程 app

第五步:启动Lancher App

fork函数

pid_t fork(void)

返回值分两种情况:

  • 返回0表示成功创建子进程,并且接下来进入子进程执行流程
  • 返回PID(>0),成功创建子进程,并且继续执行父进程流程代码
  • 返回非正数(<0),创建子进程失败,失败原因主要有: 进程数超过系统所能创建的上限,errno会被设置为EAGAIN系统内存不足,errno会被设置为 ENOMEM

使用 fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空 间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控 制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信 息)。因此,使用 fork() 函数的代价是很大的

子进程与父进程的区别:

  1. 除了文件锁以外,其他的锁都会被继承
  2. 各自的进程ID和父进程ID不同
  3. 子进程的未决告警被清除;
  4. 子进程的未决信号集设置为空集。

相关面试题

你了解Android启动流程吗

当按电源键触发开机,首先会从ROM中预定义的地方加载引导程序BootLoader到RAM中,并执行BootLoader程序启动Linux kernel,然后启动用户级别的第一个进程:init进程。init进程会解析init.rc脚本并做一些初始化工作,包括挂载文件系统、创建工作目录以及启动系统服务进程等,其中系统服务进程包括Zygote、system manger、media等。在zygote中会进一步启动system_server进程,并启动AMS、WMS、PMS等服务,等这些服务启动后AMS就会打开Launcher应用的home activity,然后看到了手机的“桌面”

system_server为什么要在zygote中启动,而不是由init启动

zygote作为孵化器可以提前加载一些资源,这样fork()时基于Copy_On_Write 机制创建的其他进程就能直接使用这些资源而不用重新加载。比如system_server可以直接使用Zygote中的JNI函数、共享库、常用的类、以及主题资源

zygote为什么不用Binder机制进行IPC通信

Binder 机制中存在 Binder 线程池,是多线程的,如果 Zygote 采用 Binder 的话就存在上面说的fork() 与 多线程的问题了。其实严格来说,Binder 机制不一定要多线程,所谓的 Binder 线程只不过是在循环读取 Binder 驱动的消息而已,只注册一个 Binder 线程也是可以工作的,比如 service manager就是这样的。实际上 Zygote 尽管没有采取 Binder 机制,它也不是单线程的,但它在 fork() 前主动停止了其他线程,fork() 后重新启动了。

Android的Launcher启动流程 “Launcher部分启动流程”

研究代码从:AndroidManifest.xml、自定义的Application.java开始。

Android系统启动时,系统需要一个Home应用程序来负责将这些应用程序展示出来;也就是该应用的目的在于:Android系统启动后,第一个启动的应用程序。在Android系统中,这个默认的Home应用程序就是Launcher。

要把某个应用程序作为Home,只需要在Android.xml文件中添加一个category:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.HOME" />
    <category android:name="com.aliyun.ushell.action.detailpage" />
</intent-filter>

对于AndroidManifest.xml文件中的几个属性说明:

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.aliyun.ushell"  coreApp="true" android:sharedUserId="android.uid.system"
    android:versionCode="2"
    android:versionName="1.2.3" 
    >

其中android:sharedUserId决定是否需要系统签名;android:theme决定整个应用的theme和style;andrid:debuggable决定应用是否处于调试模式。

疑问:

1. Launcher是如何被启动的?Android系统为什么在启动时会默认启动Launcher?

2. Launcher主要做什么工作?

Android系统开机会启动Launcher,Launcher是由ActivityManager启动的,而ActivityManager是由SystemServer启动。

此处就用到了在AndroidManifest.xml文件中添加的intent-filter属性值:category_home。一般绑定使用上述的三个category,也就是关键词:main/default/home。

Launcher的主要工作是:监听应用的安装、更新、删除等导致Launcher数据库变化的操作。Launcher数据都是使用ContentProvider来提供数据,也就是需要自定义ContentResolver监听指定Uri数据的变化。

private final ContentObserver mObserver = new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        final int nightSwitch = Global.getInt(UShellApplication.this.getContentResolver(), SWITCH_KEY, -1);
        final int nightOn = Global.getInt(UShellApplication.this.getContentResolver(), ON_KEY, -1);
        final boolean wallpaperOn = (Global.getInt(UShellApplication.this.getContentResolver(), WALLPAPER_KEY, DEFAULT_WALLPAPER) == 1);
        mWallpaperOn = wallpaperOn;
        if (readTime() || nightSwitch != mNightSwitch || nightOn != mNightOn) {
            mNightSwitch = nightSwitch;
            mNightOn = nightOn;
            if (!Utilities.IS_ZHONGHONG) {
                onTimeChanged();
            } else {
                onZHChanged(null);
            }
        }
    }
};

Launcher启动的过程主要就是加载界面数据然后显示出来,界面数据都是系统App有关的数据(可能包含Launcher数据库)。

以上是关于Android:启动流程的主要内容,如果未能解决你的问题,请参考以下文章

Android 启动流程

Android 10.0 Activity的启动流程

Android的开机启动流程

Android Framework——AMS、PMS的启动流程

Android应用进程启动过程(前篇)

Tiny4412 Android 启动流程