Android系统启动流程

该文章参考了(http://gityuan.com/2016/02/01/android-booting/)和
(https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode/blob/master/article/android/framework/01_system_start.md)(https://blog.csdn.net/freekiteyu/article/details/79175010)三篇文章,如有侵权请通知删除

我们的Android手机平时开机仅仅需要长按电源键就能开机,但实际上我们在Android系统中开机要走很多流程,今天我们就拨开这层面纱,看看Android系统到底是如何启动起来的。

Android 系统是基于 Linux 内核的,所以启动过程与 Linux 系统有很多相似的地方。由于 Android 属于嵌入式设备,并没有像计算机上那样的 BIOS 程序, 取而代之的是 Bootloader —— 系统启动加载器。 它类似于 BIOS,在系统加载前,用以初始化硬件设备,建立内存空间的映像图,为最终调用系统内核准备好环境。由于 Android 属于嵌入式设备,并没有像计算机上那样的 BIOS 程序, 取而代之的是 Bootloader —— 系统启动加载器。 它类似于 BIOS,在系统加载前,用以初始化硬件设备,建立内存空间的映像图,为最终调用系统内核准备好环境。

在 Android 里没有硬盘,而是 ROM,它类似于硬盘存放操作系统,用户程序等。 ROM 跟硬盘一样也会划分为不同的区域,用于放置不同的程序,在 Android 中主要划分为一下几个分区:

/boot:存放引导程序,包括内核和内存操作程序。
/system:相当于电脑 C 盘,存放 Android 系统及系统应用。
/recovery:恢复分区,可以进入该分区进行系统恢复。
/data:用户数据区,包含了用户的数据:联系人、短信、设置、用户安装的程序。
/cache:安卓系统缓存区,保存系统最常访问的数据和应用程序。
/misc:包含一些杂项内容,如系统设置和系统功能启用禁用设置。
/sdcard:用户自己的存储区,可以存放照片,音乐,视频等文件。

Bootloader
那么 Bootloader 是如何被加载的呢?

与计算机启动过程类似,当按下电源按键后,引导芯片代码开始从预定义的地方(固化在 ROM 中的预设代码)开始执行,芯片上的 ROM 会寻找 Bootloader 代码,并加载到内存(RAM)中。

接着 Bootloader 开始执行,Bootloader 会读取 ROM 找到操作系统并将 Linux 内核加载到 RAM 中。

当 Linux 内核启动后会初始化各种软硬件环境,加载驱动程序,挂载根文件系统,Linux 内核加载的最后阶段会启动并执行第一个用户空间进程 init 进程。

Linux 内核
Android 系统本质上就是一个基于 Linux 内核的操作系统,与 Ubuntu Linux、Fedora Linux 类似,我们要了解 Android 系统,必定先要了解一些 Linux 内核的知识。

Linux 内核的东西特别多,本文也不可能全部讲完,本文主要介绍 Android 系统启动流程,所以这里主要介绍一些内核启动相关的知识。

Linux 内核启动过程主要涉及 3 个特殊的进程,swapper 进程(又称为 idle 进程,PID = 0), init 进程(PID = 1)和 kthreadd 进程(PID = 2),这三个进程是内核的基础。

idle 进程是 Linux 系统第一个进程,是 init 进程和 kthreadd 进程的父进程。
init 进程是 Linux 系统第一个用户进程,是 Android 系统应用程序的始祖,我们的 app 都是直接或间接以它为父进程。
kthreadd 进程是 Linux 系统内核管家,所有的内核线程都是直接或间接以它为父进程。

在这里插入图片描述
idle进程是 Linux 系统的第一个进程(init 进程是第一个用户进程),也是唯一一个没有通过 fork 或者 kernel_thread 产生的进程,它在完成初始化操作后,主要负责进程调度、交换。
idle 进程是 Linux 系统的第一个进程,进程号是 0,在完成系统环境初始化工作之后,开启了两个重要的进程,init 进程和 kthreadd 进程,执行完创建工作之后,开启一个无限循环,负责进程的调度。
kthreadd 进程由 idle 通过 kernel_thread 创建,并始终运行在内核空间, 负责所有内核线程的调度和管理,所有的内核线程都是直接或者间接的以 kthreadd为 父进程。
init 进程启动分为前后两部分,前一部分是在内核启动的,主要是完成创建和内核初始化工作,内容都是跟 Linux 内核相关的;后一部分是在用户空间启动的,主要完成 Android 系统的初始化工作。
Android 系统一般会在根目录下放一个 init 的可执行文件,也就是说 Linux 系统的 init 进程在内核初始化完成后,就直接执行 init 这个文件,这个文件的源代码在 /system/core/init/init.cpp。
在这里插入图片描述
接下来就着重讲一下所有用户空间的鼻祖init进程
先给一张图了解一下:
在这里插入图片描述
init进程会启动servicemanager(binder服务管家), Zygote进程(Java进程的鼻祖). Zygote进程会创建 system_server进程以及各种app进程,下图是这几个系统重量级进程之间的层级关系。

接下来按照顺序来介绍init执行流程。
首先Kerner启动后会调用/system/core/init/Init.cpp的main()方法.
这里贴一下它的main方法

int main(int argc, char** argv) {
    ...
    klog_init();  //初始化kernel log
    property_init(); //创建一块共享的内存空间,用于属性服务
    signal_handler_init();  //初始化子进程退出的信号处理过程

    property_load_boot_defaults(); //加载/default.prop文件
    start_property_service();   //启动属性服务器(通过socket通信)
    init_parse_config_file("/init.rc"); //解析init.rc文件

    //执行rc文件中触发器为 on early-init的语句
    action_for_each_trigger("early-init", action_add_queue_tail);
    //执行rc文件中触发器为 on init的语句
    action_for_each_trigger("init", action_add_queue_tail);
    //执行rc文件中触发器为 on late-init的语句
    action_for_each_trigger("late-init", action_add_queue_tail);

    while (true) {
        if (!waiting_for_exec) {
            execute_one_command();
            restart_processes();
        }
        int timeout = -1;
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }
        if (!action_queue_empty() || cur_action) {
            timeout = 0;
        }

        epoll_event ev;
        //循环 等待事件发生
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
    return 0;
}

由此可见init进程的主要功能点有:

分析和运行所有的init.rc文件;
生成设备驱动节点; (通过rc文件创建)
处理子进程的终止(signal方式);
提供属性服务property service。

接下来重点就是解析init.rc文件了。
1.init.rc会创建所有java进程的鼻祖Zygote进程。
当Zygote进程启动后, 便会执行到frameworks/base/cmds/app_process/App_main.cpp文件的main()方法. 然后Zygote进程会创建Java虚拟机,并注册JNI方法,真正成为Java进程的母体,用于孵化Java进程. 在创建完system_server进程后,zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。接着system_server进程会创建PathClassLoader类加载器,并且会在此过程中创建Binder线程池,Java进程的调用栈的栈桢清空和 利用率提升就是通过此过程中的applicationInit方法抛出的ZygoteInit.MethodAndArgsCaller(m, argv)异常来实现的。之后会创建一个SystemServer对象,再运行run方法来创建必要的服务。

start: 创建AMS, PMS, LightsService, DMS.
phase100: 进入Phase100, 创建PKMS, WMS, IMS, DBMS, LockSettingsService, JobSchedulerService, MmsService等服务;
phase480 && 500: 进入Phase480, 调用WMS, PMS, PKMS, DisplayManagerService这4个服务的systemReady();
Phase550: 进入phase550, 执行AMS.systemReady(), 启动SystemUI, WebViewFactory, Watchdog.
Phase600: 进入phase600, 执行AMS.systemReady(), 执行各种服务的systemRunning().
Phase1000: 进入1000, 执行finishBooting, 启动启动on-hold进程.

这个时候System_server主线程的启动工作就算完成了, 进入Looper.loop()状态,等待其他线程通过handler发送消息再处理。

2.init.rc会创建service_manager。
ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder 服务。ServiceManager 进程主要是启动 Binder,提供服务的查询和注册。
ServiceManager 会启动 binder IPC,管理所有的 Android 系统服务。
3.init.rc会创建mountd
mountd的责任是负责设备安装 Daemon,负责设备安装及状态通知。
4.init.rc会创建debuggerd
启动 debug system,处理调试进程的请求,debuggerd守护进程会打开插座服务端,当需要调用debuggerd服务时,先通过客户端进程向debuggerd服务端建立socket连接,然后发送不同的请求给debuggerd服务端,当服务端收到不同的请求,则会采取相应的抛售操作。
5.init.rc会创建rild
启动 radio interface layer daemon 服务,处理电话相关的事件和请求,使用的是socket通讯方式。Andoid将RIL层分为两个代码空间:RILD管理框架,AT相关的xxxril.so动态链接库。
6.init.rc会创建media_server
它启动多个服务,这说几个重要的:

AudioFlinger:音频系统中的核心服务
AudioPolicyService:音频系统中关于音频策略的重要服务
MediaPlayerService:多媒体系统中的重要服务
CameraService:有关照相和摄像的重要服务

其中音视频解码也是在这里进行的。它也是通过Binder进行通讯的。
7、init.rc会创建surface_flinger
启动 SurfaceFlinger 服务, 负责图像绘制,是应用 UI 的核心,其功能是合成所有 Surface 并渲染到显示设备。SurfaceFlinger 进程主要是启动 FrameBuffer,初始化显示系统。它也是通过Binder通讯的。
以上工作执行完后,init 进程就会进入 loop 状态。接下来我们看到的就是system_server进程的下的应用程序管理器Launcher的主页面了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值