本文以图文并茂的形式简单介绍一个 App 从启动到主页面显示经历了哪些流程, 以及实现的原理. 不介绍具体源码, 仅仅构建一个大体框架.
一, 流程概述
启动流程:
1点击桌面 App 图标, Launcher 进程采用 Binder IPC 向 system_server 进程发起 startActivity 请求;
2system_server 进程接收到请求后, 向 zygote 进程发送创建进程的请求;
3Zygote 进程 fork 出新的子进程, 即 App 进程;
4App 进程, 通过 Binder IPC 向 sytem_server 进程发起 attachApplication 请求;
5system_server 进程在收到请求后, 进行一系列准备工作后, 再通过 binder IPC 向 App 进程发送 scheduleLaunchActivity 请求;
6App 进程的 binder 线程 (ApplicationThread) 在收到请求后, 通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
7主线程在收到 Message 后, 通过发射机制创建目标 Activity, 并回调 Activity.onCreate()等方法.
8到此, App 便正式启动, 开始进入 Activity 生命周期, 执行完 onCreate/onStart/onResume 方法, UI 渲染结束后便可以看到 App 的主界面.
上面的一些列步骤简单介绍了一个 App 启动到主页面显示的过程, 可能这些流程中的一些术语看的有些懵, 什么是 Launcher, 什么是 zygote, 什么是 applicationThread.....
下面我们一一介绍.
二, 理论基础
1.zygote
zygote 意为 "受精卵".Android 是基于 Linux 系统的, 而在 Linux 中, 所有的进程都是由 init 进程直接或者是间接 fork 出来的, zygote 进程也不例外.
在 Android 系统里面, zygote 是一个进程的名字. Android 是基于 Linux System 的, 当你的手机开机的时候, Linux 的内核加载完成之后就会启动一个叫 "init" 的进程. 在 Linux System 里面, 所有的进程都是由 init 进程 fork 出来的, 我们的 zygote 进程也不例外.
我们都知道, 每一个 App 其实都是
● 一个单独的 dalvik 虚拟机
● 一个单独的进程
所以当系统里面的第一个 zygote 进程运行之后, 在这之后再开启 App, 就相当于开启一个新的进程. 而为了实现资源共用和更快的启动速度, Android 系统开启新进程的方式, 是通过 fork 第一个 zygote 进程实现的. 所以说, 除了第一个 zygote 进程, 其他应用所在的进程都是 zygote 的子进程, 这下你明白为什么这个进程叫 "受精卵" 了吧? 因为就像是一个受精卵一样, 它能快速的分裂, 并且产生遗传物质一样的细胞!
2.system_server
SystemServer 也是一个进程, 而且是由 zygote 进程 fork 出来的.
知道了 SystemServer 的本质, 我们对它就不算太陌生了, 这个进程是 Android Framework 里面两大非常重要的进程之一 -- 另外一个进程就是上面的 zygote 进程.
为什么说 SystemServer 非常重要呢? 因为系统里面重要的服务都是在这个进程里面开启的, 比如
ActivityManagerService,PackageManagerService,WindowManagerService 等等.
3.ActivityManagerService
ActivityManagerService, 简称 AMS, 服务端对象, 负责系统中所有 Activity 的生命周期.
ActivityManagerService 进行初始化的时机很明确, 就是在 SystemServer 进程开启的时候, 就会初始化 ActivityManagerService.
下面介绍下 Android 系统里面的服务器和客户端的概念.
其实服务器客户端的概念不仅仅存在于 web 开发中, 在 Android 的框架设计中, 使用的也是这一种模式. 服务器端指的就是所有 App 共用的系统服务, 比如我们这里提到的 ActivityManagerService, 和前面提到的 PackageManagerService,WindowManagerService 等等, 这些基础的系统服务是被所有的 App 公用的, 当某个 App 想实现某个操作的时候, 要告诉这些系统服务, 比如你想打开一个 App, 那么我们知道了包名和 MainActivity 类名之后就可以打开
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- ComponentName cn = new ComponentName(packageName, className);
- intent.setComponent(cn);
- startActivity(intent);
但是, 我们的 App 通过调用 startActivity()并不能直接打开另外一个 App, 这个方法会通过一系列的调用, 最后还是告诉 AMS 说:"我要打开这个 App, 我知道他的住址和名字, 你帮我打开吧!" 所以是 AMS 来通知 zygote 进程来 fork 一个新进程, 来开启我们的目标 App 的. 这就像是浏览器想要打开一个超链接一样, 浏览器把网页地址发送给服务器, 然后还是服务器把需要的资源文件发送给客户端的.
知道了 Android Framework 的客户端服务器架构之后, 我们还需要了解一件事情, 那就是我们的 App 和 AMS(SystemServer 进程)还有 zygote 进程分属于三个独立的进程, 他们之间如何通信呢?
App 与 AMS 通过 Binder 进行 IPC 通信, AMS(SystemServer 进程)与 zygote 通过 Socket 进行 IPC 通信. 后面具体介绍.
那么 AMS 有什么用呢? 在前面我们知道了, 如果想打开一个 App 的话, 需要 AMS 去通知 zygote 进程, 除此之外, 其实所有的 Activity 的开启, 暂停, 关闭都需要 AMS 来控制, 所以我们说, AMS 负责系统中所有 Activity 的生命周期.
在 Android 系统中, 任何一个 Activity 的启动都是由 AMS 和应用程序进程 (主要是 ActivityThread) 相互配合来完成的. AMS 服务统一调度系统中所有进程的 Activity 启动, 而每个 Activity 的启动过程则由其所属的进程具体来完成.
4.Launcher
当我们点击手机桌面上的图标的时候, App 就由 Launcher 开始启动了. 但是, 你有没有思考过 Launcher 到底是一个什么东西?
Launcher 本质上也是一个应用程序, 和我们的 App 一样, 也是继承自 Activity
- packages/apps/Launcher2/src/com/Android/launcher2/Launcher.java
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- View.OnTouchListener {
- }
Launcher 实现了点击, 长按等回调接口, 来接收用户的输入. 既然是普通的 App, 那么我们的开发经验在这里就仍然适用, 比如, 我们点击图标的时候, 是怎么开启的应用呢? 捕捉图标点击事件, 然后 startActivity()发送对应的 Intent 请求呗! 是的, Launcher 也是这么做的, 就是这么 easy!
5.Instrumentation 和 ActivityThread
每个 Activity 都持有 Instrumentation 对象的一个引用, 但是整个进程只会存在一个 Instrumentation 对象.
Instrumentation 这个类里面的方法大多数和 Application 和 Activity 有关, 这个类就是完成对 Application 和 Activity 初始化和生命周期的工具类. Instrumentation 这个类很重要, 对 Activity 生命周期方法的调用根本就离不开他, 他可以说是一个大管家.
ActivityThread, 依赖于 UI 线程. App 和 AMS 是通过 Binder 传递信息的, 那么 ActivityThread 就是专门与 AMS 的外交工作的.
6.ApplicationThread
前面我们已经知道了 App 的启动以及 Activity 的显示都需要 AMS 的控制, 那么我们便需要和服务端的沟通, 而这个沟通是双向的.
客户端 -->服务端
而且由于继承了同样的公共接口类, ActivityManagerProxy 提供了与 ActivityManagerService 一样的函数原型, 使用户感觉不出 Server 是运行在本地还是远端, 从而可以更加方便的调用这些重要的系统服务.
服务端 -->客户端
还是通过 Binder 通信, 不过是换了另外一对, 换成了 ApplicationThread 和 ApplicationThreadProxy.
他们也都实现了相同的接口 IApplicationThread
- private class ApplicationThread extends ApplicationThreadNative {}
- public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}
- class ApplicationThreadProxy implements IApplicationThread {}
好了, 前面罗里吧嗦的一大堆, 介绍了一堆名词, 可能不太清楚, 没关系, 下面结合流程图介绍.
三, 启动流程
1. 创建进程
1先从 Launcher 的 startActivity()方法, 通过 Binder 通信, 调用 ActivityManagerService 的 startActivity 方法.
2一系列折腾, 最后调用 startProcessLocked()方法来创建新的进程.
3该方法会通过前面讲到的 socket 通道传递参数给 Zygote 进程. Zygote 孵化自身. 调用 ZygoteInit.main()方法来实例化 ActivityThread 对象并最终返回新进程的 pid.
4调用 ActivityThread.main()方法, ActivityThread 随后依次调用 Looper.prepareLoop()和 Looper.loop()来开启消息循环.
方法调用流程图如下:
更直白的流程解释:
1App 发起进程: 当从桌面启动应用, 则发起进程便是 Launcher 所在进程; 当从某 App 内启动远程进程, 则发送进程便是该 App 所在进程. 发起进程先通过 binder 发送消息给 system_server 进程;
2system_server 进程: 调用 Process.start()方法, 通过 socket 向 zygote 进程发送创建新进程的请求;
3zygote 进程: 在执行 ZygoteInit.main()后便进入 runSelectLoop()循环体内, 当有客户端连接时便会执行 ZygoteConnection.runOnce()方法, 再经过层层调用后 fork 出新的应用进程;
4新进程: 执行 handleChildProc 方法, 最后调用 ActivityThread.main()方法.
2. 绑定 Application
上面创建进程后, 执行 ActivityThread.main()方法, 随后调用 attach()方法.
将进程和指定的 Application 绑定起来. 这个是通过上节的 ActivityThread 对象中调用 bindApplication()方法完成的. 该方法发送一个 BIND_APPLICATION 的消息到消息队列中, 最终通过 handleBindApplication()方法处理该消息. 然后调用 makeApplication()方法来加载 App 的 classes 到内存中.
方法调用流程图如下:
更直白的流程解释:
(如果看不懂 AMS,ATP 等名词, 后面有解释)
3. 显示 Activity 界面
经过前两个步骤之后, 系统已经拥有了该 application 的进程. 后面的调用顺序就是普通的从一个已经存在的进程中启动一个新进程的 activity 了.
实际调用方法是 realStartActivity(), 它会调用 application 线程对象中的 scheduleLaunchActivity()发送一个 LAUNCH_ACTIVITY 消息到消息队列中, 通过 handleLaunchActivity()来处理该消息. 在 handleLaunchActivity()通过 performLaunchActiivty()方法回调 Activity 的 onCreate()方法和 onStart()方法, 然后通过 handleResumeActivity()方法, 回调 Activity 的 onResume()方法, 最终显示 Activity 界面.
更直白的流程解释:
四, Binder 通信
简称:
- ATP: ApplicationThreadProxy
- AT: ApplicationThread
- AMP: ActivityManagerProxy
- **AMS: **ActivityManagerService
图解:
1system_server 进程中调用 startProcessLocked 方法, 该方法最终通过 socket 方式, 将需要创建新进程的消息告知 Zygote 进程, 并阻塞等待 Socket 返回新创建进程的 pid;
2Zygote 进程接收到 system_server 发送过来的消息, 则通过 fork 的方法, 将 zygote 自身进程复制生成新的进程, 并将 ActivityThread 相关的资源加载到新进程 App process, 这个进程可能是用于承载 activity 等组件;
3 在新进程 App process 向 servicemanager 查询 system_server 进程中 binder 服务端 AMS, 获取相对应的 Client 端, 也就是 AMP. 有了这一对 binder c/s 对, 那么 App process 便可以通过 binder 向跨进程 system_server 发送请求, 即 attachApplication()
4system_server 进程接收到相应 binder 操作后, 经过多次调用, 利用 ATP 向 App process 发送 binder 请求, 即 bindApplication.
system_server 拥有 ATP/AMS, 每一个新创建的进程都会有一个相应的 AT/AMP, 从而可以跨进程 进行相互通信. 这便是进程创建过程的完整生态链.
以上大概介绍了一个 App 从启动到主页面显示经历的流程, 主要从宏观角度介绍了其过程, 具体可结合源码理解.
自己是从事了七年开发的 Android 工程师, 不少人私下问我, 2019 年 Android 进阶该怎么学, 方法有没有?
没错, 年初我花了一个多月的时间整理出来的学习资料, 希望能帮助那些想进阶提升 Android 开发, 却又不知道怎么进阶学习的朋友.[包括高级 UI, 性能优化, 架构师课程, NDK,Kotlin, 混合式开发(ReactNative+Weex),Flutter 等架构技术资料] , 希望能帮助到您面试前的复习且找到一个好的工作, 也节省大家在网上搜索资料的时间来学习.
来源: http://www.jianshu.com/p/473bad5ada47