Android系统启动过程学习

使用 android 手机已经长时间了,同时,从大学学习 android 开发开始,也进行过多款 android app 项目的开发,但是对 android 内部的启动过程,即当我们从按下电源键开机开始, android 系统内部是如何运行的,由于android 系统的内核使用的是 linux 内核,那么在启动过程中,android 系统和桌面Linux系统的启动过程是否是一样的?我们在之前的一篇博客中,曾学习过Linux内核的启动过程,在这里,我们学习一下android系统的启动过程,并从大体代码上讲解其启动过程。

启动步骤

在android系统的启动过程中,大体可以分为以下几个步骤:

这里写图片描述

android启动过程分析

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

当电源按下的时候,会引导固化在芯片中的代码从预定义的位置开始启动,并加载引导程序到内存,即RAM中,然后执行。

第二步 引导程序运行

引导程序,英文名称为Boot Loader,顾名思义,其为启动加载器,其主要作用是引导android系统内核的启动。引导程序是运行的第一个程序。其主要作用是在引导内核启动之前,检测相关硬件以及外部的RAM,设置网络,内存等,并根据相关参数或输入数据设置内核。
Boot Loader引导程序可以在\bootable\bootloader\legacy\usbloader中找到,一般的加载器包含着两个重要的文件:

  1. init.S初始化堆栈,清空BBS栈,调用main.c的_main()函数
  2. main.c初始化硬件(闹钟,主板,键盘,控制台),创建Linux标签

第三步 内核运行

当引导程序引导内核启动之后,android的内核运行和linux的内核运行相似。内核启动的时候,设置缓存,被保护的存储器,计划列表,加载驱动。当内核完成系统设置之后,便找到系统文件中”init”文件,然后启动系统的第一个进程。

第四步 init运行

init进程是android系统运行的第一个进程,也就是说所有的android进程都是直接或间接的被init进程创建的。在init进程运行过程中,主要负责两个事情,一个是挂载系统目录,像/dev,/proc,/sys等,另外一件事情是执行init.rc文件。

  • init位于/system/core/init目录中。
  • init.rc位于/system/core/rootdir目录中。
  • /system/core/init/readme.txt文件中可以学习.rc文件的相关语法,我们将在下面的博客中学习该语法。

总体来说,在init.rc文件中,主要是启动相关进程和服务,同时设置相关参数和挂载相关目录。

我们先来看一下init中的相关代码:


int main(int argc, char **argv)
{
    //.....
#ifndef NO_DEVFS_SETUP
    mkdir("/dev", 0755);
    mkdir("/proc", 0755);
    mkdir("/sys", 0755);

    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
    mkdir("/dev/socket", 0755);
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    mount("proc", "/proc", "proc", 0, NULL);
    mount("sysfs", "/sys", "sysfs", 0, NULL);

    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));

    open_devnull_stdio();
    klog_init();
#endif
    property_init();

    //.......

    is_charger = !strcmp(bootmode, "charger");

    INFO("property init\n");
    if (!is_charger)
        property_load_boot_defaults();

    INFO("reading config file\n");

    if (!charging_mode_booting())
       init_parse_config_file("/init.rc");
    else
       init_parse_config_file("/lpm.rc");

    /* Check for an emmc initialisation file and read if present */
    if (emmc_boot && access("/init.emmc.rc", R_OK) == 0) {
        INFO("Reading emmc config file");
            init_parse_config_file("/init.emmc.rc");
    }

    /* Check for a target specific initialisation file and read if present */
    if (access("/init.target.rc", R_OK) == 0) {
        INFO("Reading target specific config file");
            init_parse_config_file("/init.target.rc");
    }

    //.......

在这些事情处理完成之后,在init.rc中便会启动zygote进程。


service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

第五步 zygote进程

在java中不同的虚拟机实例会为不同的应用分配不同的内存。假如android应用应该尽可能快的启动,但如果android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此为了解决这个问题,Android系统创造了Zygote。Zygote让Dalvik虚拟机共享代码,低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟机进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。

Zygote加载进程:


 public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());

            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            gcAndFinalize();

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // If requested, start system server directly from Zygote
            if (argv.length != 2) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            if (argv[1].equals("start-system-server")) {
                startSystemServer();  //启动系统服务
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            Log.i(TAG, "Accepting command socket connections");

            runSelectLoop();

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
  1. 加载ZygoteInit类,代码位于/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中。
  2. registerZygoteSocket()为zygote命令连接注册一个服务器套接字。
  3. preload()预加载类,资源文件以及OpenGL。

第六步 系统服务或服务

在Zygote完成相应的初始化之后,开始申请启动系统服务,系统服务是android系统中供上层运行的基础。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。同一个系统服务在Android SDK可以让System Services形式获得。

核心服务:

  1. 启动电源管理器;
  2. 创建Activity管理器;
  3. 启动电话注册;
  4. 启动包管理器;
  5. 设置Activity管理服务为系统进程;
  6. 启动上下文管理器;
  7. 启动系统Context Providers;
  8. 启动电池服务;
  9. 启动定时管理器;
  10. 启动传感服务;
  11. 启动窗口管理器;
  12. 启动蓝牙服务;
  13. 启动挂载服务。

其他服务:

  1. 启动状态栏服务;
  2. 启动硬件服务;
  3. 启动网络状态服务;
  4. 启动网络连接服务;
  5. 启动通知管理器;
  6. 启动设备存储监视服务;
  7. 启动定位管理器;
  8. 启动搜索服务;
  9. 启动剪切板服务;
  10. 启动登记服务;
  11. 启动壁纸服务;
  12. 启动音频服务;
  13. 启动耳机监听;
  14. 启动AdbSettingsObserver(处理adb命令)。

第七步 引导完成

一单系统服务启动,android系统的引导过程就完成了。此时,”ACTION_BOOT_COMPLETE”开机启动广播就发出去了。

posted @ 2016-12-21 10:03  陈洪波  阅读(217)  评论(0编辑  收藏  举报