安卓应用启动详解:从Zygote到你的Activity.onCreate()

翻译自:https://android.jlelse.eu/android-application-launch-explained-from-zygote-to-your-activity-oncreate-8a8f036864b

这篇文章讲解当用户点击应用图标时,安卓如何启动你的应用。安卓系统做了很多幕后工作,来使得你的launch activity对用户可见。本文通过重要阶段的讲解和调用序列详细讲解这一过程。

安卓应用在这两个方面是独特的:

多个入口点:Android应用程序由不同的组件组成,它们可以调用其他应用程序拥有的组件。这些组件大致对应于任何应用程序的多个入口点。因此,它们不同于具有像main()方法那样的单个入口点的传统应用程序。
拥有自己的小世界:每个Android应用程序都生活在自己的世界中,它在单独的进程中运行,拥有自己的Dalvik VM实例,并分配有唯一的用户ID。

Android进程何时开始?

必要时会启动Android进程。
每当用户或其他系统组件请求执行属于您应用程序的组件(可能是服务,活动或意图接收器)时,Android系统都会为您的应用程序启动一个新进程(如果尚未运行)。通常,进程一直运行直到被系统杀死。应用程序流程是按需创建的,在您看到应用程序的启动活动启动并运行之前,发生了许多事情。
每个应用程序都在其自己的进程中运行:默认情况下,每个Android应用程序都在其自己的Android进程中运行,而这个进程只不过是一个Linux进程,而该进程首先需要一个执行线程。例如,当您单击电子邮件中的超链接时,网页将在浏览器窗口中打开。您的邮件客户端和浏览器是两个单独的应用程序,它们分别在两个单独的进程中运行。click事件使Android平台启动新进程,以便它可以在其自身进程的上下文中实例化浏览器活动。这对于应用程序中的任何其他组件同样适用。

Zygote:孕育新生命,新过程

让我们退后一会儿,快速浏览一下系统启动过程。与大多数基于Linux的系统一样,启动加载程序在启动时将加载内核并启动init进程。然后,init会生成称为“守护程序”的低级Linux进程,例如android debug守护程序,USB守护程序等。这些守护程序通常处理低级硬件接口,包括无线电接口。

然后,初始化过程会启动一个非常有趣的过程,称为“zygote'。

顾名思义,这是其余Android应用程序的开始。这是初始化Dalvik虚拟机的第一个实例的过程。它还预加载Android应用程序框架和系统上安装的各种应用程序使用的所有常见类。因此,它准备进行复制。它统计侦听套接字接口上的将来请求,以产生新的虚拟机(VM)来管理新的应用程序进程。收到新请求后,它会分叉以创建一个新进程,该进程将获取预先初始化的VM实例。
zygote之后,init启动运行时过程。
然后zygote分叉以启动一个名为System server的托管良好的进程。系统服务器在其自己的上下文中启动所有核心平台服务,例如活动管理器服务和硬件服务。
此时,完整的堆栈已准备就绪,可以启动第一个应用程序流程-主页应用程序,该应用程序显示主屏幕(也称为启动器应用程序)。

当用户单击启动器中的应用程序图标时…

click事件被转换为startActivity(intent),并通过Binder IPC路由到ActivityManagerService。ActvityManagerService执行多个步骤

  1. 第一步是收集有关Intent对象目标的信息。这是通过在PackageManager对象上使用resolveIntent()方法来完成的。默认情况下,使用PackageManager.MATCH_DEFAULT_ONLYPackageManager.GET_SHARED_LIBRARY_FILES标志。
  2. 目标信息将保存回意图对象中,以避免重新执行此步骤。
  3. 下一个重要步骤是检查用户是否具有足够的特权来调用意图的目标组件。这是通过调用grantUriPermissionLocked()方法完成的。
  4. 如果用户具有足够的权限,ActivityManagerService会检查是否需要在新任务中启动目标活动。任务的创建取决于Intent标志(例如FLAG_ACTIVITY_NEW_TASK)和其他标志(例如FLAG_ACTIVITY_CLEAR_TOP)
  5. 现在,它的时间来检查ProcessRecord已经存在process.If的ProcessRecord为空,则ActivityManager有可能创造一个新的进程实例化目标的组成部分。

如您所见,当用户单击图标并启动新应用程序时,许多事情发生在幕后。这是全图:


image.png

流程启动分为三个不同的阶段:

  1. 流程创建
  2. 装订申请
  3. 启动活动/启动服务/调用意图接收器…

流程创建:

ActivityManagerService通过调用startProcessLocked()方法创建一个新进程,该方法通过套接字连接将参数发送到Zygote进程。Zygote派生自己并调用ZygoteInit.main(),然后实例化ActivityThread对象并返回新创建的进程的进程ID。

默认情况下,每个进程都有一个线程。主线程有一个Looper实例来处理来自消息队列的消息,并且它在run()方法的每次迭代中都调用Looper.loop()Looper的工作是从消息队列中弹出消息并调用相应的方法来处理它们。然后,ActivityThread通过随后调用Looper.prepareLoop()Looper.loop()来启动消息循环。

以下序列详细捕获了调用序列:

<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android应用启动:单击事件以执行Looper调用顺序</figcaption>

应用程序绑定:

下一步是将此新创建的过程附加到特定应用程序。这是通过在线程对象上调用bindApplication()来完成的。此方法将BIND_APPLICATION消息发送到消息队列。该消息由Handler对象检索,该对象随后调用handleMessage()方法以触发特定于消息的操作-handleBindApplication()。此方法调用makeApplication()方法,该方法将应用程序特定的类加载到内存中。

下图描述了该调用序列。

<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android应用启动:BIND_APPLICATION消息处理</figcaption>

启动活动:

在上一步之后,系统包含负责应用程序的进程,并将应用程序类加载到进程的私有内存中。在新创建的流程和现有流程之间,启动活动的调用顺序很常见。

实际的启动过程从realStartActivity()方法开始,方法在应用程序线程对象上调用sheduleLaunchActivity()。此方法将LAUNCH_ACTIVITY消息发送到消息队列。该消息由handleLaunchActivity()方法处理,如下所示。

假设用户单击“视频浏览器”应用程序。启动该活动的调用顺序如图所示。

<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android应用启动:LAUNCH_ACTIVITY消息处理</figcaption>

该活动通过onCreate()方法调用开始其托管生命周期。该活动通过onRestart()调用进入前台,并通过onStart()调用开始与用户进行交互。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容