Android (6.0) 系统启动流程梳理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaojigao/article/details/78851470

Android 系统启动流程梳理

1:Android系统基本架构

     Android其本质就是在标准的Linux系统上增加了Java虚拟机,并在Java虚拟机上搭建了一个JAVA的application framework,所有的应用程序都是基于JAVA的application framework之上。

Android主要应用于ARM平台,但不仅限于ARM,也可以在X86等体系结构的机器上同样运行。

系统架构层次

android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。

蓝色的代表java程序,黄色的代码为运行JAVA程序而实现的虚拟机,绿色部分为C/C++语言编写的程序库,红色的代码内核(linux内核+driver)。在Application Framework之下,由C/C++的程序库组成,通过JNI完成从JAVA到C的调用。

1.1应用层

Android 应用层就是在Android系统平台基础之上,开发的各类APP,调用系统提供的各种API函数,实现内容丰富多彩的应用。

1.2 应用程序框架层

     Framework层为我们开发应用程序提供了非常多的API,我们通过调用特殊的API构造我们的APP,满足我们业务上的需求。同时Framework层运行众多的系统服务,对这个系统的运行状态进行管理,同时给上层应用提供各种接口。Framework层大部分是Java语言实现的,在这层里定义的API都是用Java语言编写。但是又因为它包含了JNI的方法,JNI用C/C++编写接口,根据函数表查询调用核心库层里的底层方法,最终访问到Linux内核。Framework层的作用有3个。

1)制定Android应用的架构规范,控制应用的运行,资源的加载,对应用的运行进行全程控制。

2)用Java语言编写一些规范化的模块封装成框架,供APP层开发者调用开发出具有特殊业务的手机应用。

3)用Java Native Interface调用core lib层的本地方法,JNI的库是在ART虚拟机启动时加载进去的,ART会直接去寻址这个JNI方法,然后去调用。

1.3 运行时

Android运行时包含核心库和Dalvik虚拟机两部分。

1)核心库:

    核心库提供了Java5 se API的多数功能,并提供Android的核心API,如android.os,android.net,android.media等。

2)ART虚拟机:

ART虚拟机是基于apache的java虚拟机,并被改进以适应低内存,低处理器速度的移动设备环境。ART虚拟机依赖于Linux内核,实现进程隔离与线程调试管理,安全和异常管理,垃圾回收等重要功能。

1.4 系统运行库层

系统类库大部分由C/C++编写,所提供的功能通过Android应用程序框架为开发者所使用。主要的系统类库及说明如下表:

系统类库名称

说明

Surface Manager

执行多个应用程序时,管理子系统的显示,另外也对2D3D图形提供支持

Media Framework

基于PacketVideoOpenCore的多媒体库,支持多种常用的音频和视频格式的录制和回放

SQLite

本地小型关系数据库,Android提供了一些新的SQLite数据库API,以替代传统的耗费资源的JDBC API

OpenGL|ES

基于OpenGL ES 1.0API标准实现的3D跨平台图形库

FreeType

用于显示位图和矢量字体

WebKit

Web浏览器的软件引擎

SGL

底层的2D图形引擎

Libcbionic l ibc

继承自BSDC函数库bionic libc,更适合基于嵌入式Linux的移动设备

SSL

安全套接层,是为网络通信提供安全及数据完整性的一种安全协议

1.5 Linux内核层

Android以Linux操作系统内核为基础,借助Linux内核服务实现硬件设备驱动,进程和内存管理,网络协议栈,电源管理,无线通信等核心功能。

Android内核对Linux内核进行了增强,增加了一些面向移动计算的特有功能。例如,低内存管理器LMK(Low Memory Keller),匿名共享内存(Ashmem),以及轻量级的进程间通信Binder机制等。这些内核的增强使Android在继承Linux内核安全机制的同时,进一步提升了内存管理,进程间通信等方面的安全性。下表列举了Android内核的主要驱动模块:

驱动名称

说明

Android电源管理(PowerManage)

针对嵌入式设备的,基于标准Linux电源管理系统的,轻量级的电源管理驱动

低内存管理器(Low Memory Keller

低内存管理器(Low Memory Keller可以根据需要杀死进程来释放需要的内存。扩展了LinuxOOM机制,形成独特的LMK机制

匿名共享内存(Ashmem

为进程之间提供共享内存资源,同时为内核提供回收和管理内存的机制

日志(Android Logger

一个轻量级的日志设备

定时器(Anroid Alarm

提供了一个定时器用于把设备从睡眠状态唤醒

物理内存映射管理(Android PMEM

DSP及其他设备只能工作在连续的物理内存上,PMEM用于向用户空间提供连续的物理内存区域映射

Android定时设备

可以执行对设备的定时控制功能

Yaffs2文件系统

Android采用大容量的NAND闪存作为存储设备,使用Yaffs2作为文件系统管理大容量MTD NAND FlashYaffs2占用内存小,垃圾回收简洁迅速。

Android网络

Linux内核的网络代码进行了改动,增加了网络认证机制。可在IPV4IPV6和蓝牙中设置,由ANDROID_PARANOID_NETWORK宏来启用此特性。

2: Android 启动流程简介

2.1 简介

       Android 系统与其他操作系统一样,启动都需要经历上电,然后硬件初始化,系统内核启动,系统上层启动,以及最终的系统桌面启动几个部分。其中Android系统启动详细可以分为以下七个步骤。见下图。

2.1.1 :上电

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

2.1.2 :引导程序

      引导程序是在Android操作系统开始运行前的一个小程序。它是针对特定的主板与芯片的。目前设备制造商大部分都是用的是bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。例如某些OEM厂商的手机防刷机制就是在这里实现的。

引导程序主要实现以下两个功能:

1:初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态。

2:加载内核到RAM,然后将运行流程交个内核。

2.1.3 :内核

内核[kernel]是整个操作系统的最底层,它负责整个硬件的驱动,以及提供各种系统所需的核心功能,如果内核不认识某个最新的硬件,那么硬件也就无法被驱动,你也就无法使用该硬件。

内核主要有以下几项功能:进程管理,内存管理,文件系统 ,网络,设备驱动,系统调用接口。

2.1.4 init进程

Android系统是基于Linux系统的,在Linux系统上进行了深度定制,因此它的启动流程与liunx系统一致,在系统内核加载完成之后,会去执行init来启动系统的init进程。其中init进程就是在kernel-3.10/init/main.c的run_init_process函数中启动的。

android的init进程是android第1个进程。其主要实现以下几个功能:

1. 创建文件系统目录并挂载相关的文件系统
2. 屏蔽标准的输入输出/初始化内核log系统
3. 初始化属性域
4. 完成SELinux相关工作
5. 重新设置属性
6. 创建epoll句柄
7. 装载子进程信号处理器
8. 设置默认系统属性
9. 解析init.rc
10. 向执行队列中添加其他action
 2.1.5 Zygote

zygote,是Android搞出来的一个东西。主要是为了提高应用的启动速度,因为在Java中,不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote依然是Android系统的核心,zygote是受精卵的意思,可以认为是Android framework大家族的祖先。

zygote在android中主要有以下三个作用:

1:建立运行时环境并启动虚拟机。

2:fork SystemService,启动SystemService。

3:fork其他应用进程。

2.1.6:SystemSerer

完成了上面几步之后,运行环境请求Zygote运行系统服务。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。系统服务包含了所有的System Services。

SystemServer的主要服务:

核心服务:

启动电源管理器;

创建Activity管理器;

启动电话注册;

启动包管理器;

设置Activity管理服务为系统进程;

启动上下文管理器;

启动系统Context Providers;

启动电池服务;

启动定时管理器;

启动传感服务;

启动窗口管理器;

启动蓝牙服务;

启动挂载服务。

其他服务:

启动状态栏服务;

启动硬件服务;

启动网络状态服务;

启动网络连接服务;

启动通知管理器;

启动设备存储监视服务;

启动定位管理器;

启动搜索服务;

启动剪切板服务;

启动登记服务;

启动壁纸服务;

启动音频服务;

启动耳机监听;

2.1.7 启动系统界面

启动launcher进行界面显示。

3:init进程详解

Init进程,它是一个由内核启动的用户级进程,当Linux内核启动之后,运行的第一个进程是init,这个进程是一个守护进程,确切的说,它是Linux系统中用户控件的第一个进程,所以它的进程号是1。它的生命周期贯穿整个linux 内核运行的始终, linux中所有其它的进程的共同始祖均为init进程,可以通过“adb shell ps | grep init”查看进程号。

3.1 init.cpp 流程介绍

Android init进程的入口文件在system/core/init/init.cpp中,由于init是命令行程序,所以分析init.cpp首先应从main函数开始:

在Android系统重启过程中,init.cpp的main中,主要实现以下功能。

1. 创建文件系统目录并挂载相关的文件系统

2. 屏蔽标准的输入输出/初始化内核log系统

3. 初始化属性域

4. 完成SELinux相关工作

5. 重新设置属性

6. 创建epoll句柄

7. 装载子进程信号处理器

8. 设置默认系统属性

9. 解析init.rc

10. 向执行队列中添加其他action

下面我们对init.cpp的main函数进行具体的流程分析。

int main(int argc,char** argv) {

   // 清除屏蔽字(file mode creation mask),保证新建的目录的访问权限不受屏蔽字影响

    umask(0);

    add_environment("PATH",_PATH_DEFPATH);

         // 判断是否是系统启动的第一阶段,只有启动参数中有--second-stage才为第二阶

         // 引入SELinux机制后,通过is_first_stage区分init运行状态

    bool is_first_stage = (argc == 1) ||(strcmp(argv[1], "--second-stage") != 0);

    if (is_first_stage) {

        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);

    }

    1)以上代码主要是:创建文件系统目录并挂载相关的文件系统

        

    // 重定向标准输入输出到/dev/_null_ -->  定义在system/core/init/Util.cpp中

    open_devnull_stdio();

    klog_init(); // 初始化klog

    klog_set_level(KLOG_NOTICE_LEVEL); // 设置klog的 level

    2)屏蔽标准的输入输出/初始化内核log系统

        

    if (!is_first_stage) {

        property_init(); // 为系统属性服务开辟内存空间

        process_kernel_dt();

                   // 解析/proc/cmdline文件获取必要的参数,如:qmeu, console, bootloader等

        process_kernel_cmdline();

        // 设置系统属性

        export_kernel_boot_props(); // 设置一些属性

    }

    3)初始化属性域

        

    selinux_initialize(is_first_stage);// 初始化seLinux

    4)完成SELinux相关工作

        

    if (is_first_stage) {

         // 按selinux policy要求,重新设置init文件属性

        if (restorecon("/init") ==-1) {

        }

        char* path = argv[0];

        char* args[] = { path,const_cast<char*>("--second-stage"), nullptr };

        if (execv(path, args) == -1) {   //执行init进程,重新进入main函数

        }

    }

    5)重新设置属性,并且再次进入main函数

    epoll_fd = epoll_create1(EPOLL_CLOEXEC);

    if (epoll_fd == -1) {

        ERROR("epoll_create1 failed:%s\n", strerror(errno));

        exit(1);

    }

    6)创建epoll句柄

        

    signal_handler_init(); // 始化SIGCHLD信号处理

    7)装载子进程信号处理器

        

        

    property_load_boot_defaults(); // 进程调用property_load_boot_defaults进行默认属性配置相关的工作

    start_property_service(); // 启动属性服务

    8)启动匹配属性的服务端

        

    init_parse_config_file("/init.rc");// 执行解析init.rc 的操作

   action_for_each_trigger("early-init", action_add_queue_tail);

   queue_builtin_action(wait_for_coldboot_done_action,"wait_for_coldboot_done");

   queue_builtin_action(mix_hwrng_into_linux_rng_action,"mix_hwrng_into_linux_rng");

    queue_builtin_action(keychord_init_action,"keychord_init");

    queue_builtin_action(console_init_action,"console_init"); // 界面显示Android 字符串

    action_for_each_trigger("init",action_add_queue_tail);

    queue_builtin_action(mix_hwrng_into_linux_rng_action,"mix_hwrng_into_linux_rng");

    char bootmode[PROP_VALUE_MAX];

    if (property_get("ro.bootmode",bootmode) > 0 && strcmp(bootmode, "charger") == 0) {

       action_for_each_trigger("charger", action_add_queue_tail);

    } else {

       action_for_each_trigger("late-init", action_add_queue_tail);

    }

   queue_builtin_action(queue_property_triggers_action,"queue_property_triggers");

    9)解析init.rc

        

    while (true) {

        if (!waiting_for_exec) { // 判断是否有事件需要处理

            execute_one_command(); // 依次执行每个action中携带command对应的执行函数

            restart_processes(); // 重启一些挂掉的进程

        }

        int timeout = -1; // 以下决定timeout的时间,将影响while循环的间隔

        // 有进程需要重启时,等待该进程重启

                   if (process_needs_restart) {

            timeout = (process_needs_restart -gettime()) * 1000;

            if (timeout < 0)

                timeout = 0;

        }

                    // 有action待处理,不等待

        if (!action_queue_empty() || cur_action){

            timeout = 0;

        }

                   // bootchart_sample应该是进行性能数据采样

        bootchart_sample(&timeout);

                   // 没有事件到来的话,最多阻塞timeout时间

        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) {

           //有事件到来,执行对应处理函数

        //根据上文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求

         ((void (*)()) ev.data.ptr)();

        }

    }

    10)向执行队列中添加其他action

    return 0;

}

3.2  init.rc介绍

Android init.rc文件由系统第一个启动的init程序解析,init.rc文件基本组成单位是section, section分为三种类型,分别由三个关键字(所谓关键字即每一行的第一列)来区分,这三个关键字是 on、service、import.在init.rc文件中一条语句通常是占据一行。单词之间是通过空格符来相隔的.如果需要在单词内使用空格,那么得使用转义字符"\",如果在一行的末尾有一个反斜杠,那么是换行折叠符号,应该和下一行合并成一起来处理,这样做主要是为了避免一行的字符太长,与C语言中的含义是一致的。注释是以#号开头。

1:import类型的section表示引入另外一个.rc文件,例如

import init.test.rc

相当包含另外一些section, 在解析完init.rc文件后会解析引入的.rc文件

2:on类型的section表示一系列命令的组合, 例如:

on init

    #Create cgroup mount point for memory

   Mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000

   mkdir /sys/fs/cgroup/memory 0750 root system

   mount cgroup none /sys/fs/cgroup/memory memory

这样一个section包含了一个mount命令和两个mkdir命令,命令的执行是以section为单位的,所以这三个命令是一起执行的,不会单独执行, 那什么时候执行呢?这是由init.c的main()所决定的,main()里在某个时间会调用,action_for_each_trigger("init",action_add_queue_tail);这就把 ” on init “开始的这样一个section里的所有命令加入到一个执行队列,在未来的某个时候会顺序执行队列里的命令,所以调用action_for_each_trigger()的先后决定了命令执行的先后。

3:service类型的section表示一个可执行程序

service surfaceflinger/system/bin/surfaceflinger

      class main

      user system

      group graphics drmrpc

      onrestart restart zygote

surfaceflinger作为一个名字标识了这个service, /system/bin/surfaceflinger表示可执行文件的位置, class、user、group、onrestart这些关键字所对应的行都被称为options, options是用来描述的service一些特点,不同的service有着不同的options。service类型的section标识了一个service(或者说可执行程序), 那这个service什么时候被执行呢?是在

class_start 这个命令被执行的时候,这个命令行总是存在于某个on类型的section中,“class_start core”这样一条命令被执行,就会启动类型为core的所有service。

例如

on boot

 …………

 class_start core

  因此在执行on boot 的时候 就会启动所有定义为core的服务,而服务的类型就是在其第二行定义的class属性,如: class main class core。

所以可以看出Android的启动过程主要就是on类型的section被执行的过程。

4: zygote

4.1 zygote简介

app_process是在程序执行期间将其名字修改为zygote的。zygote是受精卵的意思,主要作用就是进行细胞分裂,是android系统执行APK程序的核心服务。zygote进程首先加载启动ART虚拟机,然后在加载一些系统核心类和资源,这些都是其他APK程序都可能要用到的资源。最后zygote进程进入监听状态。一旦Android上层有创建新APK进程的需求,zygote进程便会为其分裂出新的进程。这个APK新进程,一开始便拥有了ART虚拟机和zygote预先加载的各种系统类和资源,能大大加速apk应用的启动,同时也能节省很大的内存开支。

为什么zygote进程要预先加载系统资源。zygote进程实际上是利用fork分裂出新的进程的,Linux内核采用了写时复制技术:内核只为新生成的子进程创建虚拟空间结构,它们来自于父进程的虚拟地址结构,但是不为子进程的虚拟地址分配物理内存,它们共享父进程的物理空间。这样,子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,而代码段继续共享父进程的物理空间(两者的代码完全相同)。

因为Android上层APK程序不会去修改zygote进程预先加载的系统类和系统资源,所以就不需要为每个APK进程重新分配这些资源,所有APK程序都共用在zygote预先加载的这些资源,所以性能自然也就提高了。

zygote在init.rc中的配置

import/init.${ro.zygote}.rc

在Android源码/system/core/rootdir中,有如上图所示的四个与zygote相关的文件,因此,究竟是将这个四个文件中的哪一个导入到init.rc中是由ro.zygote这个只读属性决定的。

下面是 init.zygote64_32.rc 的内容

service zygote /system/bin/app_process64 -Xzygote/system/bin --zygote --start-system-server --socket-name=zygote

    class main

    socket zygotestream 660 root system

    onrestartwrite /sys/android_power/request_state wake

    onrestartwrite /sys/power/state on

    onrestartrestart media

    onrestartrestart netd

 

service zygote_secondary /system/bin/app_process32-Xzygote /system/bin --zygote --socket-name=zygote_secondary

    class main

    socketzygote_secondary stream 660 root system

onrestart restart zygote

其中 service zygote/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server--socket-name=zygote表示启动一个服务,名称叫做zygote,其对应的执行文件是/system/bin/app_process64,传递给执行文件的参数是后面的四个,即,  -Xzygote /system/bin --zygote--start-system-server --socket-name=zygote。

class main 表示在启动是在 class_start core 的时候启动。

socket zygote stream 660 root system表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。这里定义的socket的类型为unix domain socket,它是用来作本地进程间通信用的。

最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。

其中app_process64 和app_process32 就是zygote进程的可执行程序,启动后会改名成zygote。

顾名思义,zygote_secondary即app_process32是一个运行在32位的进程,它所连接的库也都是32位的。而zygote就是运行在64位的进程,它所连接的库都是64位的。正常情况下,一个进程如果要正确运行,就必须从可执行程序入口开始到所有使用的库都保持32/64位的一致性。因为zygote进程是所有第三方应用程序的父进程,所以可以认为,如果应用程序是32位的,那没他的父进程也肯定是32位,换句话说,如果需要启动某个32位的应用,那么肯定是通过32位的zygote进程fork出来的。

4.2 zygote 流程分析

      经过查看mk文件,我们可以找到,app_process的源代码在frameworks\base\cmds\app_process\app_main.cpp这个文件。下面就通过这个cpp文件的main函数,梳理下zygote的启动过程中具体做了哪些事情。备注;下面代码进行了删除,只保留部分核心代码。

static const char ZYGOTE_NICE_NAME[] ="zygote";

int main(int argc,char* const argv[])

{

    // 初始化一个AppRuntime对象

    AppRuntime runtime(argv[0],computeArgBlockSize(argc, argv));

     //解析传递进来的参数,

         // 由前面的分析,可以知道,这里的参数是

         //-Xzygote /system/bin --zygote--start-system-server --socket-name=zygote

    bool zygote = false;

    bool startSystemServer = false;

    bool application = false;

    String8 niceName;

    String8 className;

    while (i < argc) {

        const char* arg = argv[i++];

        if (strcmp(arg, "--zygote")== 0) {

            zygote = true;

            niceName = ZYGOTE_NICE_NAME;

        } else if (strcmp(arg,"--start-system-server") == 0) {

            startSystemServer = true;

        } else if (strcmp(arg,"--application") == 0) {

            application = true;

        } else if (strncmp(arg,"--nice-name=", 12) == 0) {

            niceName.setTo(arg + 12);

        } else if (strncmp(arg, "--",2) != 0) {

            className.setTo(arg);

            break;

        } else {

            --i;

            break;

        }

    }

    // 由上面的部分,我们可以得到,zygote是true,niceName的值是zygote,startSystemServer是true,className是null,因此下面直接进到else里面

        

    if (!className.isEmpty()) {

    } else {

            // 创建/data/dalvik-cache

        maybeCreateDalvikCache();

         // 构建参数,这个参数将会传递到下面的java中      

           if (startSystemServer) {

           args.add(String8("start-system-server"));

        }

        String8abiFlag("--abi-list=");

        args.add(abiFlag);

        for (; i < argc; ++i) {

            args.add(String8(argv[i]));

        }

    }

    // 设置当前进程的名字为zygote

    if (!niceName.isEmpty()) {

        set_process_name(niceName.string());

    }

    if (zygote) { // 因为前面zygote=true,因此这里直接进去,调用runtime.start,

        runtime.start("com.android.internal.os.ZygoteInit",args, zygote);

}

………………

        

上面的代码主要是初始化一个runtime,然后解析参数,根据参数,设置自身的进程名称,然后调用runtime.start进一步启动。从源码中可以看到class AppRuntime : public AndroidRuntime  ,因此因为AppRuntime继承自AndroidRuntime,但是AppRuntime并没有实现其start方法,因此这里调用的是AndroidRuntime的start方法。

接下来,我们看看AndroidRuntime的start方法具体都做了哪些事情。其代码在frameworks\base\core\jni\AndroidRuntime.cpp。

voidAndroidRuntime::start(const char* className, const Vector<String8>&options, bool zygote)

{

         //启动java虚拟机

    JniInvocation jni_invocation;

    jni_invocation.Init(NULL);

    JNIEnv* env;

    if (startVm(&mJavaVM, &env, zygote)!= 0) {

        return;

    }

    onVmCreated(env);

    // 注册JNI

    if (startReg(env) < 0) {

        ALOGE("Unable to register allandroid natives\n");

        return;

    }

    // 根据上面传递进来的参数,启动相应的java程序

    char* slashClassName = toSlashClassName(className);

    jclass startClass =env->FindClass(slashClassName);

    if (startClass == NULL) {

        ALOGE("JavaVM unable to locateclass '%s'\n", slashClassName);

    } else {

        jmethodID startMeth =env->GetStaticMethodID(startClass, "main",

                    "([Ljava/lang/String;)V");

        if (startMeth == NULL) {

            ALOGE("JavaVM unable to findmain() in '%s'\n", className);

        } else {

                       // 调用相应的Java文件的main函数。从此进入java世界

           env->CallStaticVoidMethod(startClass, startMeth, strArray);

        }

    }

    ………………

}

这个函数的作用是启动Android系统运行时库,它主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数

关于VM的启动,startVM绝大部分都是设置虚拟机的参数,然后调用JNI_CreateJavaVM来启动VM。关于VM的详细介绍,可以参考下面的链接了解下VM的原理。

http://blog.csdn.net/innost/article/details/50377905

   下面介绍下startReg注册JNI函数的过程。

intAndroidRuntime::startReg(JNIEnv* env)

{

     // 调用register_jni_procs继续执行

    if (register_jni_procs(gRegJNI,NELEM(gRegJNI), env) < 0) {

        env->PopLocalFrame(NULL);

        return -1;

    }

    return 0;

}

// 这个register_jni_procs就是根据传递进来的参数控制,下面看下这个参数是如何定义的

static intregister_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)

{

    for (size_t i = 0; i < count; i++) {

        if (array[i].mProc(env) < 0) { // 循环调用gRegJNI数组中的每一个函数,进行JNI函数的注册

            return -1;

        }

    }

    return 0;

}

static constRegJNIRec gRegJNI[] = {

   REG_JNI(register_com_android_internal_os_RuntimeInit),

    REG_JNI(register_android_os_SystemClock),

    REG_JNI(register_android_util_EventLog),

    REG_JNI(register_android_util_Log),

   REG_JNI(register_android_content_AssetManager),

   REG_JNI(register_android_content_StringBlock),

         下面还有很多

随便进去一个。发下最终就是调用jniRegisterNativeMethods来注册JNI方法

intregister_android_util_Log(JNIEnv* env)

{

    return jniRegisterNativeMethods(env,"android/debug/JNITest",

        gMethods, NELEM(gMethods));

}

通过上面的分析,我们知道在AndroidRuntime的start 函数最后,启动了ZygoteInit类的main函数。这里我们继续看下ZygoteInit类的main函数具体都做了哪些事情。源码路径:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public static voidmain(String argv[]) {

    try {

        //创建了一个socket接口,用来和ActivityManagerService通讯,主要是后面新创建应用的时候用

        registerZygoteSocket(socketName);

        // 加载各种系统资源

                   preload();

        //启动systemServer

        if (startSystemServer) {

            startSystemServer(abiList,socketName);

        }

                   // 进入循环等待,等待其他进程链接前面创建的socket接口

        runSelectLoop(abiList);

        closeServerSocket(); // zygote 退出

    } catch (MethodAndArgsCaller caller) {

        caller.run(); // 很重要,startSystemServer之后,会跑出异常回到到这里

    } catch (RuntimeException ex) {

    }

}

从上面精简过的代码可以看到,ZygoteInit的main函数中调用registerZygoteSocket创建了socket接口,这个socket是用来等待ActivityManagerService进行链接,来请求Zygote创建新的进程的,

然后调用了preload函数加载各种类资源,然后调用startSystemServer启动SystemServer,最后调用runSelectLoop进入循环等待其他进程的链接请求。

 privatestatic void registerZygoteSocket(String socketName) {

     if (sServerSocket == null) {

         int fileDesc;

         final String fullSocketName =ANDROID_SOCKET_PREFIX + socketName;

         try {

             String env =System.getenv(fullSocketName);

                             //将env转换成一个文件描述符。

             fileDesc = Integer.parseInt(env);

         }

         try {

             FileDescriptor fd = newFileDescriptor();

             fd.setInt$(fileDesc);

             sServerSocket = newLocalServerSocket(fd);

         }

     }

 }

 这个函数很简单,就是根据传进来的socketName和ANDROID_SOCKET_PREFIX,获得一个名称为 ANDROID_SOCKET_zygote的环境变量的值, 然后调用LocalServerSocket创建一个服务端的socket,然后将其保存在ZygoteInit的静态变量sServerSocket中。

static voidpreload() {

    preloadClasses(); // 加载相关的类

    preloadResources(); // 加载资源

    preloadOpenGL(); // 加载OpenGL

    preloadSharedLibraries(); // 加载系统的Lib

    preloadTextResources(); // 加载文字资源

    WebViewFactory.prepareWebViewInZygote();// 初始化WebView

}

preload(),这个函数非常直观,就是调用各个preload函数,加载相应的资源。这里重点介绍下preloadClasses和preloadResources这个函数。

private staticfinal String PRELOADED_CLASSES = "/system/etc/preloaded-classes";

private static voidpreloadClasses() {

    InputStream is;

    try {

        is = newFileInputStream(PRELOADED_CLASSES);

    } catch (FileNotFoundException e) {}

    try {

        BufferedReader br = newBufferedReader(new InputStreamReader(is), 256);

        String line;

        while ((line = br.readLine()) != null){

            line = line.trim();

            if (line.startsWith("#")|| line.equals("")) {

                continue;

            }

            try { Class.forName(line, true, null); }

        }

    }

}

这个函数的逻辑还是比较清楚的,就是调用FileInputStream,读取/system/etc/preloaded-classes问中的内容,然后对其每一行进行加载,这个preloaded-classes文件在源码的frameworks\base下面,文件内容有三千多行,因此这里加载时比较耗时的。

private static voidpreloadResources() {

    final VMRuntime runtime = VMRuntime.getRuntime();

    try {

        mResources = Resources.getSystem(); //创建Resources实例对象

        mResources.startPreloading();

        TypedArray ar =mResources.obtainTypedArray(

               com.android.internal.R.array.preloaded_drawables);

        intN = preloadDrawables(runtime, ar);

        ar.recycle();

        ar = mResources.obtainTypedArray(

               com.android.internal.R.array.preloaded_color_state_lists);

        N = preloadColorStateLists(runtime, ar);

        ar.recycle();

        mResources.finishPreloading();

    } catch (RuntimeException e) {

    }

}

private static intpreloadDrawables(VMRuntime runtime, TypedArray ar) {

    int N = ar.length();

    for (int i=0; i<N; i++) {

        int id = ar.getResourceId(i, 0);

        if (id != 0) {

            if (mResources.getDrawable(id, null) == null){

            }

        }

    }

    return N;

}

private static intpreloadColorStateLists(VMRuntime runtime, TypedArray ar) {

    int N = ar.length();

    for (int i=0; i<N; i++) {

        int id = ar.getResourceId(i, 0);

        if (id != 0) {

            if (mResources.getColorStateList(id, null) ==null) {

            }

        }

    }

    return N;

}

preloadResources则主要加载framework-res.apk中的资源,该函数中分别调用preloadDrawables()和preloadColorStateLists()加载这两类资源。加载的原理很简单,就是把这些资源读出来放到一个全局变量中,只要该类对象不被销毁,这些全局变量就会一直保存。

保存Drawable资源的全局变量是mResources,该变量的类型是Resources类,由于该类内部会保存一个Drawable资源列表,因此,实际上缓存这些Drawable资源是在Resources内部;保存Color资源的全局变量也是mResources,同样,Resources类内部也有一个Color资源的列表。

private static voidrunSelectLoop(String abiList) throws MethodAndArgsCaller {

    fds.add(sServerSocket.getFileDescriptor());

    peers.add(null);

    while (true) {

        StructPollfd[] pollFds = newStructPollfd[fds.size()];

                   // 等待其他进程链接

        try {

            Os.poll(pollFds, -1);

        } catch (ErrnoException ex) {

            throw newRuntimeException("poll failed", ex);

        }

        for (int i = pollFds.length - 1; i>= 0; --i) {

            if ((pollFds[i].revents &POLLIN) == 0) {

                continue;

            }

            if (i == 0) {

                                     //创建客户端连接

                ZygoteConnection newPeer =acceptCommandPeer(abiList);

                peers.add(newPeer);

               fds.add(newPeer.getFileDesciptor());

            } else {

                                     // 处理客户事件

                boolean done =peers.get(i).runOnce();

                if (done) {

                    peers.remove(i);

                    fds.remove(i);

                }

            }

        }

    }

}

这个函数的流程很简单,就是循环等待客户端链接,然后调用runOnce执行客户的需求。

     Zygote 是Android创建java世界的盘古,它创建了java虚拟机,同时fock出了framework的核心SystemServer。至此Zygote就介绍完了。

 

5:FrameWork的核心SystemServer

SystemServer是由Zygote进程fock处理的一个进程,它是系统的一个重要的守护进程。SystemServer进程主要的作用是启动各种系统服务,比如ActivityManagerService,PackageManagerService,WindowManagerService等服务,我们平时熟知的各种系统性的服务其实都是在SystemServer进程中启动的,而当我们的应用需要使用各种系统服务的时候其实也是通过与SystemServer进程通讯获取各种服务对象的句柄的进而执行相应的操作的.

根据前面的zygote的分析,我们知道了systemServer在Android的启动过程中是肯定要启动的。因为在init.rc里面,已经指定了要start-system-server = true.

下面我们就梳理下SystemServer的初始化流程。

private staticboolean startSystemServer(String abiList, String socketName)

        throws MethodAndArgsCaller,RuntimeException {

    这里删除部分代码,这部分代码主要是构建parsedArgs参数

    int pid;

    try { // 调用Zygote.forkSystemServer创建新进程

        pid =Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,…parsedArgs.effectiveCapabilities);

    } catch (IllegalArgumentException ex) {

    }

    /* For child process */

if (pid == 0) {

//fock函数会有两个返回,一个是在主线程,一个是在子线程中, pid == 0 表示在子线程中,

        handleSystemServerProcess(parsedArgs);

    }

    return true;

}

 public static int forkSystemServer(int uid,int gid, int[] gids, int debugFlags,

         int[][] rlimits, longpermittedCapabilities, long effectiveCapabilities) {

     int pid = nativeForkSystemServer(

             uid, gid, gids, debugFlags,rlimits, permittedCapabilities, effectiveCapabilities);

     return pid;

 }

forkSystemServer直接调用nativeForkSystemServer函数,这个函数实现在com_android_internal_os_Zygote.cpp中,其代码路径在frameworks\base\core\jni下。

static jintcom_android_internal_os_Zygote_nativeForkSystemServer(

        jlong effectiveCapabilities) {

  pid_t pid = ForkAndSpecializeCommon(env, uid,gid, gids ,........ NULL, NULL);

  if (pid > 0) {

      gSystemServerPid = pid; //将子进程SystemServer的pid存在zygote进程的全局变量中

      int status;

      if (waitpid(pid, &status, WNOHANG) ==pid) {

       // 父进程的函数退出之前,需要检查刚刚创建的SystemServer是否正常,如果crash;此时需要重启zygote

          RuntimeAbort(env);

      }

  }

  return pid;

}

static pid_tForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,

                                    ........

                                     jstringinstructionSet, jstring dataDir) {

  SetSigChldHandler(); //设置信号处理函数

  pid_t pid = fork();

  if (pid == 0) {

    //根据传入参数进行对应的处理,例如设置进程名,设置各种id(用户id,组id)等

     ........

    //反注册掉信号监听器

      UnsetSigChldHandler();

  } else if (pid > 0) {

    // the parent process

  }

  return pid;

}

从上面的代码可以看出,ForkAndSpecializeCommon最终是通过fork的方式,分裂出子进程。

这里需要关注一下的是,在zygote进程fork之前,调用SetSigChldHandler函数注册了一个子进程信号监听器。由于子进程共享父进程中的堆及栈信息,因此在子进程中也会有相应的信号处理器。

为了避免该信号监听器对子进程的影响,可以看到在子进程中进行了UnsetSigChldHandler的操作。这里我们看下SetSigChldHandler的具体实现。

static voidSigChldHandler(int /*signal_number*/) {

  pid_t pid;

  int status;

  while ((pid = waitpid(-1, &status,WNOHANG)) > 0) {

    if (pid == gSystemServerPid) {

      kill(getpid(), SIGKILL);

    }

}}

从上面的代码可以看出,SetSigChldHandler函数将注册一个信号处理器,来监听子进程的死亡。当子进程死亡后,利用SigChldHandler进行操作。需要注意的是,zygote的信号监听器,关注的是zygote所有的子进程,而不只是SystemServer进程(每次创建一个新的进程时,zygote都会注册对应的监听器)。所有zygote的子进程中,zygote只关心了SystemServer的死活。当SystemServer发生crash的时候,zygote会自杀,导致init进程重启zygote,最终导致Android上层重启。当其它子进程crash时,zygote只打印了log信息。

下面我们在看看handleSystemServerProcess的执行流程。

private static voidhandleSystemServerProcess(

        ZygoteConnection.Arguments parsedArgs){

    // 关闭从zygote那里继承下来的socket

    closeServerSocket();

         if (parsedArgs.niceName != null) {

                   // 修改进程名为system_server

        Process.setArgV0(parsedArgs.niceName);

    }

    final String systemServerClasspath =Os.getenv("SYSTEMSERVERCLASSPATH");

    if (systemServerClasspath != null) {

       performSystemServerDexOpt(systemServerClasspath);

                   //对环境变量SYSTEMSERVERCLASSPATH中的jar包进行dex优化

    }

   if (parsedArgs.invokeWith != null) {}

   else {

      //利用systemServerClass对应的路径构建对应的ClassLoader

     ClassLoader cl = null;

     if (systemServerClasspath != null) {

         cl = newPathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());

        Thread.currentThread().setContextClassLoader(cl);

     }

      //将剩余参数及classLoader递交给RuntimeInit的zygoteInit函数

    RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs, cl);

  }

}

从上面的代码可以看出,接下来的流程进入到RuntimeInit中的zygoteInit函数。zygoteInit函数将根据classLoader和参数,完成不同进程所需要的初始化工作。

public static finalvoid zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

         throws ZygoteInit.MethodAndArgsCaller{

     commonInit(); // 进行一些常规初始化

     nativeZygoteInit(); //

applicationInit(targetSdkVersion, argv,classLoader);

 }

函数nativeZyoteInit实现在AndroidRuntime.cpp中,主要用于为Binder通信打下基础,在AndroidRuntime中函数调用gCurRuntime->onZygoteInit();,由于gCurRuntime是在AndroidRuntime的初始化函数中初始化为this,但是AndroidRuntime得初始化是在app_main的main函数中通过AppRuntime runtime(argv[0], computeArgBlockSize(argc,argv));进行初始化的,因此这里gCurRuntime指代的是AppRuntime,这个对象。因此这里调用的是AppRuntime的onZygoteInit函数,这个函数中通过proc->startThreadPool()启动一个线程池用于Binder通信。

    

private static voidapplicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

         throws ZygoteInit.MethodAndArgsCaller{

      ………… 构造参数,然后调用invokeStaticMain进一步处理

     invokeStaticMain(args.startClass,args.startArgs, classLoader);

 }

    private static void invokeStaticMain(StringclassName, String[] argv, ClassLoader classLoader)

            throws ZygoteInit.MethodAndArgsCaller{

        // 参数传入,className = "com.android.server.SystemServer"

        try {

            cl = Class.forName(className, true,classLoader);

        }

        Method m;

        try {// 找到com.android.server.SystemServer类的main函数

            m = cl.getMethod("main",new Class[] { String[].class });

        }

        // 主动抛出一个异常,

        throw newZygoteInit.MethodAndArgsCaller(m, argv);

    }

这下直接懵逼了,这里抛出个异常就没有下文了?通过查看代码我们发现,在Zygoteinit的main函数中,对这个异常有进行捕获的地方,因此这里调用流程会退回到Zygoteinit的main函数中。

catch(MethodAndArgsCallercaller){

    caller.run(); // 调用caller的run函数

}

MethodAndArgsCaller的run函数如下

public void run(){

    try{

        mMethod.invoke(null, new Object[] {mArgs });

// mMethod为com.android.server.SystemServer的main函数,这里就调用到了SystemServer的main函数中

    } catch(IllegalAccessException ex){

        ......

    }

}

从上面的代码可以看到,run方法单纯地利用反射调用对应类的main方法(此处是SystemServer.java的main方法)。

这里的问题是,为什么不在RuntimeInit.java的invokeStaticMain中,直接利用反射调用每个类的main方法?

参考invokeStaticMain中抛出异常的注释,我们可以推测出,这与linux的exec函数族的意图相似。

注意到,我们此时运行在SystemServer进程中。由于zygote进程fork的原因,SystemServer调用到invokeStaticMain时,整个堆栈实际上包含了大量zygote进程复制过来的调用信息。此时,我们通过抛异常捕获的方式,让位于栈底的ZygoteInit.main函数来进行处理,可起到刷新整个调用栈的作用(旧的无用调用出栈)。

public static voidmain(String[] args) {

      new SystemServer().run();

  }

 private void run() {

         //检查系统时间,要是在1970年之前,许多API会crash掉,

     if (System.currentTimeMillis() <EARLIEST_SUPPORTED_TIME) {

        SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);

     }

         // 确保传进系统的binder总是以前台优先权运行.

    BinderInternal.disableBackgroundScheduling(true);

    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);

    android.os.Process.setCanSelfBackground(false);

     // 准备 main looper thread

          Looper.prepareMainLooper();

     // Initialize native services.

          //加载android_servers.so库,

    System.loadLibrary("android_servers");

     // Check whether we failed to shut downlast time we tried.

          // 检查上一次关机是否失败

     performPendingShutdown();

     // Initialize the system context.

          // 初始化系统context

     createSystemContext();

     // Create the system service manager.

          // 创建 system service manager对象,添加到本地服务中

     mSystemServiceManager = newSystemServiceManager(mSystemContext);

    LocalServices.addService(SystemServiceManager.class,mSystemServiceManager);

     try {

         startBootstrapServices();

         startCoreServices();

         startOtherServices();

     } catch (Throwable ex) {}

     Looper.loop();

 }

SystemServer的run函数比较清晰,除了初步的设置之外,主要是做了以下几个操作

1:调用System.loadLibrary("android_servers")加载native的库,

2:调用Looper.prepareMainLooper创建loop,

3:调用createSystemContext创建SystemServer的Context,但是这里创建的Context是一个残缺的,后面等系统的服务启动完毕之后,会进行完善,使其成为一个标准的Context对象。这部分这里不做介绍,后续有机会在详细介绍。

4:调用new SystemServiceManager(mSystemContext)创建system service manager对象,添加到本地服务中

5:调用startXXXServices 以此启动系统的各项核心服务。

       SystemServer启动服务的方法比较简单,这里介绍下通过SystemServiceManager.startService启动服务的流程

publicSystemService startService(String className) {

    final Class<SystemService>serviceClass;

    try {// 这里根据传入的参数,实例化相关的Java对象,这里就会调用到类的静态方法

        serviceClass =(Class<SystemService>)Class.forName(className);

    } catch (ClassNotFoundException ex) {

    }

    return startService(serviceClass);

}

public <Textends SystemService> T startService(Class<T> serviceClass) {

    final T service;

    try {// 调用getConstructor返回制定参数类型访问权限是public的构造器。

        Constructor<T> constructor =serviceClass.getConstructor(Context.class);

        调用newInstance对其进行初始化,

        service = constructor.newInstance(mContext);

    }

    mServices.add(service);

    try {

        service.onStart();// 调用onStart启动相应的服务

    } catch (RuntimeException ex) {}

    return service;

}

通过上面的代码,可以发现其实startService启动服务的流程非常简单,就是调用Class.forName实例化Java对象,然后调用getConstructor获取到类的构造器,然后使用newInstance对其进行初始化,下面是ActivityManagerService的中的启动类。

public static finalclass Lifecycle extends SystemService {

    private final ActivityManagerServicemService;

    public Lifecycle(Context context) {

        super(context);

        mService = new ActivityManagerService(context);

    }

    @Override

    public void onStart() {

        mService.start();

    }

    public ActivityManagerService getService(){

        return mService;

    }

}

Android系统在SystemServer中,启动了framework层几乎所有的服务,大约有四十个左右,在此不做详细介绍,有兴趣的同学可以自行查看代码。至此SystemServer启动完成,系统进入就绪状态,下面我们分析系统launcher的启动流程。

6:Android launcher的启动流程梳理

在分析launcher的启动之前,我们先在这里贴下SystemServer启动launcher的调用栈。这里在Process的zygoteSendArgsAndGetResult打印的启动launcher的调用栈。通过调用栈我们可以很清楚的看到代码的调用流程。

 android.os.Process.zygoteSendArgsAndGetResult(Process.java:541)

 android.os.Process.startViaZygote(Process.java:698)

 android.os.Process.start(Process.java:493)

 com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3329)

 com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3183)

 com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3071)

 com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1400)

 com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2009)

 com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1554)

 com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2739)

 com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:2236)

 com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:2467)

 com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1682)

 com.android.server.am.ActivityStackSupervisor.startHomeActivity(ActivityStackSupervisor.java:912)

 com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:3458)

ActivityManagerService.systemReady调用了startHomeActivityLocked开始启动launcher的操作

 com.android.server.am.ActivityManagerService.systemReady(ActivityManagerService.java:11823)

 startOtherServices函数中调用到了ActivityManagerService.systemReady函数

 com.android.server.SystemServer.startOtherServices(SystemServer.java:1098)

 com.android.server.SystemServer.run(SystemServer.java:276)

 com.android.server.SystemServer.main(SystemServer.java:168)

 这里就可以看出Zygote在启动SystemServer的时候采用异常,这样减少调用栈中的很多无用的调用信息。

 java.lang.reflect.Method.invoke(Native Method)

 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:736)

 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)

通过前面的分析,我们知道SystemServer在启动之后,调用了startXXXServices启动了好多服务,但是launcher具体是在哪里启动的呢,这里我们就继续分析SystemServer的代码查找launcher的启动流程。

 private void startOtherServices() {

  mActivityManagerService.systemReady(newRunnable() {

    public void run() {

      startSystemUi(context);

      if (networkScoreF != null)networkScoreF.systemReady();

      Watchdog.getInstance().start();

      if (wallpaperF != null)wallpaperF.systemRunning();

    }

  });

 }

通过上面对于startOtherServices精简我们知道在startOtherServices的最后,调用mActivityManagerService.systemReady函数,并且传入了一个Runnable参数,然后在Runnable进行了大量的初始化,首先是启动SystemUi,然后调用各个服务的systemReady函数,接着初始化Watchdog,然后调用各个函数的systemRunning进行系统就绪的最后动作,但是我们的launcher是在哪里启动的呢,这里就需要看下ActivityManagerService的systemReady函数的具体实现了。

 public void systemReady(final Runnable goingCallback){

                    // 进行各种初始化

      if (goingCallback != null)goingCallback.run();

       // 进行各种初始化。然后调用startHomeActivityLocked启动launcher,

        startHomeActivityLocked(mCurrentUserId,"systemReady");

 }

上面是精简之后的systemReady函数,这个函数的功能很简单,就是对PackageManagerService进行最后的初始化,然后调用前面传递进来的回调函数,最后调用startHomeActivityLocked启动我们期待已久的launcher。代码进入到这里,我们就会眼前豁然一亮,原来系统马上就OK。但是,PackageManagerService启动launcher的步骤还是比较复杂的,下面我们进行startHomeActivityLocked的代码流程梳理。

void startHomeActivity(Intent intent,ActivityInfo aInfo, String reason) {

       moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);

       startActivityLocked(null ****** );

    }

final int startActivityLocked(…………) {

       int err = ActivityManager.START_SUCCESS;

           定义了一个err参数,然后根据各种情况判断当前启动的应用是否符合规范,这里判断非常多,在此不做详细介绍。

           //上面的检查确认没有错误之后 这里创建 ActivityRecord

       ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid,callingPackage,

                intent, resolvedType, aInfo,mService.mConfiguration, resultRecord, resultWho,

                requestCode,componentSpecified, voiceSession != null, this, container, options);

           //这里调用startActivityUncheckedLocked继续启动HOME

       err = startActivityUncheckedLocked(r, sourceRecord, voiceSession,voiceInteractor,

                startFlags, true, options,inTask);

       return err;

    }

  // 这个函数非常长,大约六百多行,主要是根据当前状态,设置启动参数。

final intstartActivityUncheckedLocked(………………) {

   final Intent intent = r.intent;

   final int callingUid = r.launchedFromUid;

   

    //前面进行各种检查之后,这里调用targetStack.startActivityLocke继续启动应用。

   targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition,options);

   return ActivityManager.START_SUCCESS;

}

在ActivityStackSupervisor的startHomeActivity直接调用startActivityLocked继续启动,然后在startActivityLocked,调用startActivityUncheckedLocked,这两个函数中,主要是对启动前对要启动的应用的各项情况进行检查,确认应用可以正常启动,然后在startActivityUncheckedLocked,对应用的各项启动参数进行设置,完成之后调用startActivityLocked继续处理。

 final void startActivityLocked(ActivityRecordr, boolean newTask,

        boolean doResume, boolean keepCurTransition,Bundle options) {

    TaskRecord rTask = r.task;

    final int taskId = rTask.taskId;

         // 各种判断之后,调用resumeTopActivitiesLocked继续启动

   mStackSupervisor.resumeTopActivitiesLocked(this, r, options);

  }

  这个函数主要是对Task进行各种判断,根据Task确认是要在之前已有的进程中运行当前的Activity,还是需要新启动进程。因为首次启动,因此前面的的都是徒劳,最终调用resumeTopActivitiesLocked继续启动。

 

  booleanresumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,

            Bundle targetOptions) {

          调用resumeTopActivityLocked继续处理

       result = targetStack.resumeTopActivityLocked(target, targetOptions);

      return result;

  }

 

  final booleanresumeTopActivityLocked(ActivityRecord prev, Bundle options) {

      boolean result = false;

      try {

              // 调用resumeTopActivityInnerLocked继续处理

          result =resumeTopActivityInnerLocked(prev, options);

      } finally {

          mStackSupervisor.inResumeTopActivity= false;

      }

      return result;

  }

 

 private booleanresumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {

     这个函数前面代码很多,主要是在启动应用之前,对目前正在运行的应用状态进行处理,

          // 调用startSpecificActivityLocked启动新的进程

    mStackSupervisor.startSpecificActivityLocked(next, true, false);

     return true;

}

voidstartSpecificActivityLocked(ActivityRecord r,

        boolean andResume, boolean checkConfig){

    调用PackageManagerService的startProcessLocked启动新的进程。

    mService.startProcessLocked(r.processName,r.info.applicationInfo, true, 0,

            "activity",r.intent.getComponent(), false, false, true);

}

private final voidstartProcessLocked(ProcessRecord app, String hostingType,

         String hostingNameStr, StringabiOverride, String entryPoint, String[] entryPointArgs) {

         // 整理新建进程需要的参数,然后调用Process.start启动新进程

         Process.ProcessStartResult startResult= Process.start(entryPoint,

                 app.processName, uid, uid,gids, debugFlags, mountExternal,

                 app.info.targetSdkVersion,app.info.seinfo, requiredAbi, instructionSet,

                 app.info.dataDir, entryPointArgs);

       

}

后面这部分函数调用有很多函数体非常长,主要是在应用启动前,对应用的启动环境以及启动参数当前系统状态和新启动进行的参数等等进行判断和处理,代码流程非常繁杂,在此不做介绍。从前面的代码中我们看到ActivityManagerService最终调用到了Process.start启动了新的进程,下面我们就到Process.start函数中看看都干了些啥。

public static finalProcessStartResult start() {

   try {

       return startViaZygote(processClass,niceName,……………… zygoteArgs);

   } catch (ZygoteStartFailedEx ex) {

   }

 }

  private static ProcessStartResultstartViaZygote(final String processClass,) throws ZygoteStartFailedEx {

     synchronized(Process.class) {

         ArrayList<String> argsForZygote= new ArrayList<String>();

        argsForZygote.add("--runtime-args");

        argsForZygote.add("--setuid=" + uid);

        argsForZygote.add("--setgid=" + gid);

         if ((debugFlags &Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {

            argsForZygote.add("--enable-jni-logging");

         }

         // 这里定义了argsForZygote,然后将前面传递进来的所有参数都添加到argsForZygote

         }

         argsForZygote.add(processClass);

         if (extraArgs != null) {

             for (String arg : extraArgs) {

                 argsForZygote.add(arg);

             }

         }

                    // 调用zygoteSendArgsAndGetResult继续执行。

         returnzygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

     }

 }

 private static ProcessStartResultzygoteSendArgsAndGetResult(ArrayList<String> args)

        throws ZygoteStartFailedEx {

        final BufferedWriter writer =zygoteState.writer;

        final DataInputStream inputStream =zygoteState.inputStream;

       writer.write(Integer.toString(args.size()));

        writer.newLine();

        int sz = args.size();

        for (int i = 0; i < sz; i++) {

            String arg = args.get(i);

            if (arg.indexOf('\n') >= 0) {

                throw new ZygoteStartFailedEx(

                        "embedded newlinesnot allowed");

            }

                            // 向socket中写入参数,

            writer.write(arg);

            writer.newLine();

        }

        writer.flush();

        ProcessStartResult result = newProcessStartResult();

                   //获取zygote fock出来的应用的pid,然后返回此pid

        result.pid = inputStream.readInt();

        result.usingWrapper =inputStream.readBoolean();

        return result;

 } }

通过前面代码的分析,Process的函数调用就简单多了,这里主要就是整理参数,然后联系Zygote,将参数传递给Zygote继续处理,然后读取Zygote的返回结果。

至此启动launcher的流程,在SystemServer中的部分就基本走完了,下面我们看下Zygote中,是如何fock出来launcher进程的,以及Launcher进程是如何一步步启动的。

   

还记得我们前面讲解Zygote的时候,发现在Zygote的main函数最后,调用了runSelectLoop,这里我们就从这个函数入手,看下Zygote是如何创建新的进程的。

private static voidrunSelectLoop(String abiList) throws MethodAndArgsCaller {

while (true) {

    // 等待其他进程链接

     try {

        Os.poll(pollFds, -1);

     } catch (ErrnoException ex) {

        throw new RuntimeException("pollfailed", ex);

     }

          //创建客户端连接

     ZygoteConnection newPeer =acceptCommandPeer(abiList);

     peers.add(newPeer);

     fds.add(newPeer.getFileDesciptor());

         // 处理客户事件

     boolean done = peers.get(i).runOnce();

     if (done) {peers.remove(i);fds.remove(i);}

  }

}

前面的Os.poll等待客户链接,如果有客户进行链接就立即返回,然后调用acceptCommandPeer建立链接,新建立的链接会返回一个ZygoteConnection对象。然后会调用此对象的runOnce处理客户端的需求。下面我们看下ZygoteConnection的runOnce流程。

boolean runOnce()throws ZygoteInit.MethodAndArgsCaller {

 String args[];

 // 读取前面ActivityManagerService传递的参数信息,后面会对这下参数进行合法性判断

 args = readArgumentList();

 // 调用Zygote.forkAndSpecialize fock新的进程

 pid = Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid, parsedArgs.gids,

         parsedArgs.debugFlags, rlimits,parsedArgs.mountExternal, parsedArgs.seInfo,

         parsedArgs.niceName, fdsToClose,parsedArgs.instructionSet,

         parsedArgs.appDataDir);

 if (pid == 0) {// 在子线程中调用handleChildProc

     handleChildProc(parsedArgs, descriptors,childPipeFd, newStderr);

     return true;

 } }

这个函数首先读取ActivityManagerService传递的参数信息,然后对参数信息进行合法性判断,然后调用forkAndSpecialize fock新的进程,待新进程创建之后,在新进程中执行handleChildProc函数。这里我们先看下forkAndSpecialize函数。

public static intforkAndSpecialize(int uid, ………………, String appDataDir) {

   // 直接调用nativeForkAndSpecialize函数fock新的进程,

   int pid = nativeForkAndSpecialize( …………instructionSet, appDataDir);

    return pid;

}

nativeForkAndSpecialize 这个函数是nativie层的函数,这里就不进行详细分析,有兴趣的同学可以对照前面分析SystemServer启动的流程自行分析。这里我们继续看下handleChildProc函数。

private voidhandleChildProc(Arguments ………… r)throws ZygoteInit.MethodAndArgsCaller {

    // 关闭由Zygote集成过来的socket

    closeSocket();

    ZygoteInit.closeServerSocket();

    对新进程进程初步的设置

    调用RuntimeInit.zygoteInit函数

    RuntimeInit.zygoteInit(parsedArgs …………classLoader */);

}

是不是很熟悉,前面讲解SystemServer启动的时候,已经讲过了。

public static finalvoid zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

         throws ZygoteInit.MethodAndArgsCaller{

     commonInit();

     nativeZygoteInit();

     applicationInit(targetSdkVersion, argv,classLoader);

 }

  private static void applicationInit(inttargetSdkVersion, String[] argv, ClassLoader classLoader)

          throws ZygoteInit.MethodAndArgsCaller{

      // 调用invokeStaticMain,这里要特别注意,这里的args.startClass与启动SystemServer的不一样。

           启动SystemServer的时候这个参数是:com.android.server.SystemServer

           但是启动其他应用的时候这个参数是:android.app.ActivityThread

      invokeStaticMain(args.startClass,args.startArgs, classLoader);

  }

 // 这个函数前面在讲解SystemServer启动的时候也说过了。

 private static void invokeStaticMain(StringclassName, String[] argv, ClassLoader classLoader)

         throws ZygoteInit.MethodAndArgsCaller{

     Method m;

     try {

         m = cl.getMethod("main", newClass[] { String[].class });

     } catch (NoSuchMethodException ex) {

         throw new RuntimeException(

                 "Missing static main on "+ className, ex);

     } catch (SecurityException ex) {

         throw new RuntimeException(

                 "Problem getting staticmain on " + className, ex);

     }

     // 这里抛出异常,直接回到ZygoteInit的main函数中,在ZygoteInit的main函数中调用 caller.run();启动ActivityThread类的main函数。

     throw newZygoteInit.MethodAndArgsCaller(m, argv);

 }

到这里Zygote新进程以及创建OK,开始启动新的进程,从前面传递的参数我们可以得到这里要启动的是ActivityThread类的main函数,下面我们就看下ActivityThread类的main函数,分析应用是如何一步步启动的。

public static void main(String[]args) {

    

     Looper.prepareMainLooper();

     ActivityThread thread = newActivityThread();

     thread.attach(false);

     Looper.loop();

 }

这个函数主要做了两件事情,首先调用prepareMainLooper创建一个消息循环,并且在执行完thread.attach之后使得当前进程进入到这个消息循环中。其次就是创建ActivityThread对象并且调用其attach函数,下面我们就看下这个attach函数具体都干了些啥。

 final ApplicationThread mAppThread = newApplicationThread();

 private class ApplicationThread extendsApplicationThreadNative {……}

 private void attach(boolean system) {

         RuntimeInit.setApplicationObject(mAppThread.asBinder());

         final IActivityManager mgr =ActivityManagerNative.getDefault();

         try {

             mgr.attachApplication(mAppThread);

         } catch (RemoteException ex) {

         }

 }

 attach函数中,首先调用ActivityManagerNative的getDefault获取一个ActivityManagerService的代理对象,然后调用其attachApplication方法,注意这里的参数是mAppThread。通过mAppThread对象的定义我们可以看到这个对象是在创建ActivityThread对象的时候就初始化了,而且这个ApplicationThread继承自ApplicationThreadNative。而ApplicationThreadNative主要是负责和ActivityManagerService通信,控制应用程序的生命周期的。

 下面我们就看下ActivityManagerService中的attachApplication方法。

 private final booleanattachApplicationLocked(IApplicationThread thread,int pid) {

        ProcessRecord app;

            app = mPidsSelfLocked.get(pid); // 获取fock进程的时候保存的对象

        app.makeActive(thread, mProcessStats);

        app.curAdj = app.setAdj = -100;

        app.curSchedGroup = app.setSchedGroup =Process.THREAD_GROUP_DEFAULT;

        app.forcingToForeground = null;

        app.hasShownUi = false;

        app.debugging = false;

        app.cached = false;

        app.killedByAm = false;

                   // 移除应用启动超时的消息

       mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

       // 初始化应用的进程信息,

       thread.bindApplication(processName,appInfo, providers, app.instrumentationClass,

               ……………………………………………………

              mCoreSettingsObserver.getCoreSettingsLocked());

       try {

           if(mStackSupervisor.attachApplicationLocked(app)) {

               didSomething = true;

           }

       }

        return true;

    }

attachApplicationLocked函数主要做了以下事情,

1)首先根据前面启动应用的记录获取ProcessRecord对象,然后对其信息进行进一步完善。

2)调用removeMessages方法,删除启动超时的计时,因为在应用启动的时候,AMS会对其设置一个超时消息,如果在此时间之内,应用没有调用attachApplicationLocked方法,就说明应用启动超时,这里就会弹出应用无响应的对话框。

3)然后调用bindApplication对应用的进程设置应用程序的信息,这里主要设置了以下信息,

 1: 初始化mConfiguration

 2: 设置进程名

 3: 本地语言设置

 4: 设置包名称

 5: 设置应用程序根路径

 6: 设置应用程序data路径

4)调用mStackSupervisor.attachApplicationLocked进一步处理。

这里我们看下attachApplicationLocked进一步处理。函数的具体实现。

 boolean attachApplicationLocked(ProcessRecordapp) throws RemoteException {

   for (int displayNdx =mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {

    ArrayList<ActivityStack> stacks =mActivityDisplays.valueAt(displayNdx).mStacks;

    for (int stackNdx = stacks.size() - 1;stackNdx >= 0; --stackNdx) {

     final ActivityStack stack =stacks.get(stackNdx);

     if (!isFrontStack(stack)) {continue;}

     ActivityRecord hr =stack.topRunningActivityLocked(null);

     if (hr != null) {

       if (hr.app == null && app.uid ==hr.info.applicationInfo.uid && processName.equals(hr.processName)) {

        try {

          if (realStartActivityLocked(hr, app,true, true)) {

              didSomething = true;

          }

        } catch (RemoteException e) {}

       }

     }

    }

   }

   return didSomething;

 }

循环获取Activity堆栈的顶端的Activity进行匹配,最终调用realStartActivityLocked继续执行。

final booleanrealStartActivityLocked(ActivityRecord r,…………checkConfig){

  app.forceProcessStateUpTo(mService.mTopProcessState);

   app.thread.scheduleLaunchActivity(newIntent(r.intent), r.appToken,

           ……………………

           newIntents, !andResume,mService.isNextTransitionForward(), profilerInfo);

}

realStartActivityLocked这个函数中进行了一些准备工作之后,最终调用了app.thread.scheduleLaunchActivity函数。

public final voidscheduleLaunchActivity(Intent intent, IBinder token, int ident,

        ……………………

        boolean notResumed, boolean isForward,ProfilerInfo profilerInfo) {

    ActivityClientRecord r = newActivityClientRecord();

    r.token = token;

    r.ident = ident;

    r.intent = intent;

    …………………………

    r.profilerInfo = profilerInfo;

    r.overrideConfig = overrideConfig;

    sendMessage(H.LAUNCH_ACTIVITY, r);

}

caseLAUNCH_ACTIVITY: {

      ………………

      handleLaunchActivity(r, null);

  } break

     通过上面的代码,我们看到,在scheduleLaunchActivity函数中初始化了ActivityClientRecord对象之后,发送LAUNCH_ACTIVITY消息,然后在LAUNCH_ACTIVITY消息中,调用了handleLaunchActivity函数。下面我们看下handleLaunchActivity函数的实现。

 

  private voidhandleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    // Initialize before creating the activity

    WindowManagerGlobal.initialize();

    // 加载有启动的Activity的类,并调用其onCreate函数

    Activity a = performLaunchActivity(r,customIntent);

    if (a != null) {

                   // resumeActivity

        handleResumeActivity(r.token, false,r.isForward,

                !r.activity.mFinished&& !r.startsNotResumed);

                                     }

   }

handleLaunchActivity,是启动Activity的主要函数,这里调用了performLaunchActivity,加载并启动相应的Activity类,然后调用其onCreate函数。紧接着调用handleResumeActivity函数,执行Activity的OnResume函数。这里我们看下performLaunchActivity。

private ActivityperformLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    ActivityInfo aInfo = r.activityInfo;

    if (r.packageInfo == null) {

        r.packageInfo =getPackageInfo(aInfo.applicationInfo, r.compatInfo,

                Context.CONTEXT_INCLUDE_CODE);

    }

         // 获得要启动的Activity的包名以及类名,他们使用ComponentName对象来描述

    ComponentName component =r.intent.getComponent();

    if (component == null) {

        component = r.intent.resolveActivity(

           mInitialApplication.getPackageManager());

        r.intent.setComponent(component);

    }

         // 将上面获取到的类文件加载到内存,并且创建一个Activity实类。

    Activity activity = null;

    try {

        java.lang.ClassLoader cl =r.packageInfo.getClassLoader();

        activity =mInstrumentation.newActivity(

                cl, component.getClassName(),r.intent);

       StrictMode.incrementExpectedActivityCount(activity.getClass());

        r.intent.setExtrasClassLoader(cl);

        r.intent.prepareToEnterProcess();

        if (r.state != null) {

            r.state.setClassLoader(cl);

        }

    } catch (Exception e) {

    }

    try {

        Application app =r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {

                            // 创建并初始化appContext对象

            Context appContext =createBaseContextForActivity(r, activity);

            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());

            Configuration config = newConfiguration(mCompatConfiguration);

                            //  使用appContext 和 r 来初始化Activity对象activity

            activity.attach(appContext, this,getInstrumentation(), r.token,

                    r.ident, app, r.intent,r.activityInfo, title, r.parent,

                    r.embeddedID,r.lastNonConfigurationInstances, config,

                    r.referrer,r.voiceInteractor);

            activity.mCalled = false;

                            // 调用Activity的OnCreate函数

            if (r.isPersistable()) {

               mInstrumentation.callActivityOnCreate(activity, r.state,r.persistentState);

            } else {

               mInstrumentation.callActivityOnCreate(activity, r.state);

            }

}}

nstrumentation的callActivityOnCreate函数

public voidcallActivityOnCreate(Activity activity, Bundle icicle) {

    prePerformCreate(activity);

    activity.performCreate(icicle); //调用Activity类的performCreate函数。

    postPerformCreate(activity);

}

Activity的performCreate函数

final voidperformCreate(Bundle icicle) {

    onCreate(icicle); // 调用自己的onCreate函数。

    mActivityTransitionState.readState(icicle);

    performCreateCommon();

}

        

这个函数的主要步骤比较多,主要要以下几点,

1)调用r.intent.getComponent获取要启动的应用的报名以及类名。

2)调用mInstrumentation.newActivity加载类文件到内存,并创建一个Activity实例对象。

3)创建appContext对象。

4)调用activity.attach,初始化Activity对象activity

5)调用callActivityOnCreate,调用Activity的OnCreate函数。

至此launcher的MainActivity组件的启动过程就分析完了。

猜你喜欢

转载自blog.csdn.net/zhaojigao/article/details/78851470