[译]Android系统是如何启动应用程序的?从Zygote到Activity的onCreate()

2,677 阅读6分钟

本文解释了用户点击应用程序图标之后,Android系统是如何启动您的应用程序的。 为了将您的应用程序的启动界面呈现给用户,Android系统在背后做了很多繁重的工作。 本文将通过重点介绍其中的一些重要阶段以及它们之间的顺序来详细阐述应用程序的启动过程。

Android应用程序有两个特点:

  1. 拥有多个入口:Android应用程序由不同的组件组成,它们也可以调用其他应用的组件。这些组件就相当于应用程序的多个入口。因此,它们与具有单一入口的传统应用程序(如main()方法)并不相同。
  2. 拥有自己的小世界:每个Android应用程序都运行在一个单独的进程中,它有自己的Dalvik VM实例并被分配一个唯一的用户ID。

何时启动应用程序的进程?

在任何需要Android应用程序进程的时候启动。

每当用户或其他系统组件请求执行属于您的应用程序的组件(可能是service,activity或intent receiver)时,Android系统都会为您的应用程序启动一个新的进程(如果它尚未运行)。一般来说,这个进程会一直运行直到它被系统杀死。 应用程序的进程是按需创建的,并且在您看到应用程序的启动界面之前会发生许多事情。

每个应用程序都运行在它自己的进程中:默认情况下,每个Android应用程序都运行在自己的Android进程中,它是一个Linux进程,并且会启动一个线程。 例如,当您单击电子邮件中的超链接时,网页会在浏览器窗口中打开。 您的邮件客户端和浏览器是两个独立的应用程序,它们运行在两个单独的独立进程中。 click事件会导致Android平台启动一个新进程,以便它可以在自己的进程中实例化浏览器。这同样适用于应用程序中的其他任何组件。

Zygote : 孕育新的生命,新的进程

先让我们快速回顾下Android系统的启动过程。与大多数基于Linux的系统一样,首先引导加载程序会加载内核并启动init进程。然后,init进程产生称为“守护进程”的低级Linux进程,例如android调试守护进程,USB守护进程等。这些守护进程通常都是用于处理底层硬件接口的。

接下来init进程会启动一个非常有趣的进程,称为'Zygote'。

顾名思义,这是Android应用程序的起点。zygote进程在内部会先初始化一个Dalvik虚拟机的实例,继而加载所有Android应用程序框架和安装在系统上的各种应用程序所使用的常用类,最后进入一种监听状态,随时准备被复制。当系统其它模块希望创建新进程时,它们会向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源。

zygote进程启动之后,init进程会启动运行时进程(runtime process)。

然后zygote进程又启动一个称为系统服务(system server)的管理良好的进程。 系统服务进程会启动系统的所有核心服务,比如activity manager service、hardware services。 此时,系统已准备好启动第一个应用程序 - Home应用程序,该应用程序显示主屏幕,也称为应用程序启动器。

当用户点击启动器中的应用程序图标时...

点击事件被转换成执行startActivity(intent)方法,并通过Binder IPC路由到ActivityManagerService。ActvityManagerService会执行以下几个步骤:

  1. 收集intent的目标Activity的相关信息。这个过程是通过调用PackageManager的resolveIntent()方法完成的。默认使用的是PackageManager.MATCH_DEFAULT_ONLY和PackageManager.GET_SHARED_LIBRARY_FILES参数。
  2. 目标Activity的相关信息会被保存到intent中以避免重新执行此步骤。
  3. 调用grantUriPermissionLocked()方法来检查用户是否有足够的权限来调用intent的目标Activity。
  4. 如果用户有足够的权限,ActivityManagerService会检查目标Activity是否需要在新的任务栈中启动。任务栈的创建依赖于Intent的flag参数,比如FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TOP等。
  5. 最后检查该应用程序进程的ProcessRecord是否已经存在。如果ProcessRecord为null,ActivityManager会创建一个新的进程来实例化目标Activity。

正如你上面看到的,当用户点击一个图标并启动一个新的应用程序时,背后会发生许多事情。完整的过程如下图所示:

应用程序进程启动过程中的三个不同阶段:

  1. Process Creation
  2. Binding Application
  3. Launching Activity / Starting Service / Invoking intent receiver...

Process Creation

ActivityManagerService通过调用startProcessLocked()方法向Zygote请求创建一个新的进程,该方法通过socket连接向Zygote进程发送参数。于是Zygote便复制出一份自己的副本并调用ZygoteInit.main(),然后实例化ActivityThread对象并返回新创建进程的进程ID。

每个进程都默认有一个线程,即主线程。主线程有一个Looper实例来处理来自消息队列的消息,在遍历这个消息队列的时候,其中的run()方法每次都会调用Looper.loop()。Looper的工作就是从消息队列中取出消息并调用相应的方法来处理它们。ActivityThread随后会调用Looper.prepareLoop()和Looper.loop()来启动消息循环。

下面这个序列图详细描述了这一过程:

Application Binding:

下一步是将这个新创建的进程绑定到指定的应用程序上。首先ActivityManagerService调用bindApplication()方法,进而触发线程对象将BIND_APPLICATION消息发送到消息队列。Handler检索此消息,然后调用handleMessage()方法触发操作handleBindApplication()。该方法会调用makeApplication()方法将应用程序的某些特定的类加载到内存中。

下面这个序列图详细描述了这一过程:

Launching an Activity:

在上一步之后,系统已经创建好了应用程序进程,并将应用程序的类加载到了进程的专属内存中。

Activity的启动过程从realStartActivity()方法开始,首先ActivityManagerService会调用sheduleLaunchActivity()方法,进而触发线程对象将LAUNCH_ACTIVITY消息发送到消息队列。该消息由handleLaunchActivity()方法处理。

假设用户点击的是视频浏览器应用程序的图标,启动Activity的序列图如下所示。

Activity调用onCreate()方法后,便开启了属于它的生命周期。