安卓应用启动流程

news/2024/9/20 2:31:38/文章来源:https://www.cnblogs.com/Joooook/p/18415200

安卓应用启动流程

目录

  • 1 冷启动热启动
  • 2 zygote和SystemServer
  • 3 应用启动流程简述(记得补充)
  • 4 从点击图标到通知Zygote
    • 4.1 Launcher
    • 4.2 Activity.java
    • 4.3 Instrumentation.java
    • 4.4 ActivityTaskManager.java
    • 4.5 ActivityTaskManagerService.java
    • 4.6 ActivityStarter.java
    • 4.7 RootWindowContainer.java
    • 4.8 回到ActivityTaskManagerService.java
    • 4.9 ActivityManagerService.java
    • 4.10 ProcessList.java
    • 4.11 ZygoteProcess.java
  • 5 Zygote创建Activity进程
    • 5.1 ZygoteServer.java
    • 5.2 ZygoteConnection.java
    • 5.3 ZygoteInit.java
    • 5.4 RuntimeInit.java
  • 6 初始化Application实例
    • 6.1 ActivityThread.java
  • 7 小结
  • 8 引用

1 冷启动热启动

Activity启动过程中,一般会牵涉到应用启动的流程。应用启动又分为冷启动热启动

  1. 冷启动:点击桌面图标,手机系统不存在该应用进程,这时系统会重新fork一个子进程来加载Application并启动Activity,这个启动方式就是冷启动。
  2. 热启动:应用的热启动比冷启动简单得多,开销也更低。在热启动中,因为系统里已有该应用的进程,所以系统的所有工作就是将您的 Activity 带到前台。 冷启动是应用完全从0开始启动,涉及到更多的内容,所以就应用冷启动的过程展开讨论。

作者:天才木木木木
链接:https://juejin.cn/post/6844904116561379341
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2 zygote和SystemServer

在进入应用启动流程前,先简单回顾一下。

zygote是在系统启动后init进程fork出来的。

  • zygote有一个socket,用于接受消息,当有应用申请启动的时候,会通过socket通知zygote进程,其会fork自己来创建应用进程。
  • init过程中,zygoteforkSystemServer进程。

SystemServer是由zygote进程fork出来的第一个进程,其管理着很多重要服务,比如ActivityManagerServicePackageManagerServiceWindowManagerService

3 应用启动流程简述(记得补充)

从用户点击图标开始到应用创建再到第一个Activity启动

4 从点击图标到通知Zygote

4.1 Launcher

  • LauncherAndroid系统启动后,Activity Manager Service (AMS)加载的第一个应用程序
  • Launcher又被称为桌面程序,负责Android桌面的启动和管理
  • 用户使用的应用程序(App)都是通过Launcher来启动的

源码:/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

Launcher中有这么一段代码,创建桌面快捷方式

其中绑定了点击事件

跟进源码:/packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java

对于App图标来说最终都是调用startAppShortcutOrInfoActivity方法。

而后最终会调用startActivitySafely,这里的launcherLauncher类,所以回到Launcher.java代码。

其中的startActivitySafely会继续往上调用

继承关系:LauncherStatefulActivityBaseDraggingActivityBaseActivityActivity

startActivitySafely是在BaseActivity中实现的AppLauncher的接口方法

源码:/packages/apps/Launcher3/src/com/android/launcher3/views/AppLauncher.java

于是乎流程进入到了Activity.java

4.2 Activity.java

Activity源码位于/frameworks/base/core/java/android/app/Activity.java

startActivity会调用startActivityForResult

startActivityForResult

以下是通义给出的解释:

这段代码是 startActivityForResult 方法的一部分,这个方法用于启动一个 Activity,并期望从该 Activity 获取返回的结果。当目标 Activity 完成后,它会回调当前 ActivityonActivityResult 方法,并附带请求码(requestCode)以及结果数据。

关键点包括:

  • intent 参数是一个 Intent 对象,它包含了要启动的目标 Activity 的信息。
  • requestCode 是一个整型值,当目标 Activity 结束时会通过 onActivityResult 回调传递回来。这有助于识别哪个 Activity 返回了结果。
  • options 参数是可选的 Bundle 对象,可以用来指定 Activity 启动的一些额外选项。

如果当前 Activity 没有父 Activity (mParent == null),则会调用 Instrumentation 类的 execStartActivity 方法来启动新的 Activity。如果 requestCode 大于等于 0,则标记 mStartedActivitytrue,这样可以避免在 Activity 初始化期间的闪烁现象,直到收到启动的 Activity 的结果为止。

如果当前 Activity 有一个父 Activity,则会调用父 Activity 的 startActivityFromChild 方法来启动新的 Activity,同时传递 requestCodeoptions

4.3 Instrumentation.java

源码:/frameworks/base/core/java/android/app/Instrumentation.java

Instrumentation.javaexecStartActivity有两种实现。execStartActivity (带 UserHandle 参数) 方法允许开发者显式地指定用于启动 Activity 的用户。而未带UserHandle参数的方法会使用默认用户启动Activity

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String resultWho,Intent intent, int requestCode, Bundle options,  UserHandle user )public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target,Intent intent, int requestCode, Bundle options)

execStartActivity (不带 UserHandle 参数) 为例,红框处为关键代码。

进入到了ActivityTaskManager

4.4 ActivityTaskManager.java

源码:/frameworks/base/core/java/android/app/ActivityTaskManager.java

ActivityTaskManager.getService()能够获取到ActivityTaskManagerService的实例对象。

Singleton是单例模式的对象创建,也就是一个进程中只有一个该对象。

这里的ServiceManager应当对应的是当前进程的ServiceManager的单例,所以这里的调用是LauncherServiceManager单例。

当应用启动的时候AMS会将系统服务注册进进程的ServiceManager里。getService函数是直接从单例的数组中中获取的。

获取到的IBinder是对应Binder的引用信息,可以理解为所需要调用的(在这里为ActivityTaskManagerService)系统服务的引用信息。

而后返回系统服务所提供的服务接口。

为了能够流畅的理解启动流程,在这里不严谨地描述一下Binder机制的作用,具体的Binder机制会在后面的文章中学习。

之后的任务就交给了ActivityTaskManagerService

4.5 ActivityTaskManagerService.java

源码地址:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

startActivityAsUser方法通过ActivityStartControllerobtainStarter方法获取了ActivityStarter对象实例,并调用ActivityStarterexecute方法

4.6 ActivityStarter.java

源码位置/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

ActivityStarter中最终会调用RootWindowContainerresumeFocusedTasksTopActivities方法

int execute() {//...res = executeRequest(mRequest);//...
}private int executeRequest(Request request) {//...// 创建ActivityRecord对象final ActivityRecord r = new ActivityRecord.Builder(mService).setCaller(callerApp)// ...构造参数.build();// 调用startActivityUnchecked方法mLastStartActivityResult = startActivityUnchecked(...);//...
}private int startActivityUnchecked(...) {//...// 调用startActivityInnerresult = startActivityInner(...);//...
}int startActivityInner(...) {//...// 调用RootWindowContainer的resumeFocusedTasksTopActivities方法mRootWindowContainer. resumeFocusedTasksTopActivities (...);//...
}

4.7 RootWindowContainer.java

RootWindowContainerWindowManagerService的主要组成部分之一,是一个管理窗口的容器。

resumeFocusedTasksTopActivities将会调用TaskTaskFragmentPause前台程序,为新的应用程序启动做准备。

源码位置:/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

Task.java中的resumeTopActivityUncheckedLocked

Task.java中的resumeTopActivityInnerLocked

TaskFragment.java中的resumeTopActivity

简单总结一下如图

startProcessAsync就将交回给ActivityTaskManagerService.java

4.8 回到ActivityTaskManagerService.java

处理完窗口容器数据以后(核心工作是将前台程序Pause),再次回到了ActivityTaskManagerService

源码地址/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

startProcessAsync使用调用ActivityManagerInternalstartProcess方法

这里传入的mAmInternal变量是通过类搜索得到的。

ActivityManagerInternal的实现类是ActivityManagerService,所以这里就相当于给ActivityManagerService发消息。

这里使用的Handler机制是安卓中线程之间的通信方式,两种Service就是在同一进程下的不同进程。

4.9 ActivityManagerService.java

源码地址:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

startProcess

startProcessLocked

4.10 ProcessList.java

源码地址:/frameworks/base/services/core/java/com/android/server/am/ProcessList.java

由于代码实在太长,这里就摘要一下

startProcessLocked中定义了创建Activity完成后回调的入口点

最终会调用startProcess

startProcess代码主要做了以下事情

  1. 数据隔离:根据系统的配置,可能需要对应用的数据目录进行隔离处理。这涉及到文件系统的挂载操作。
  2. 选择合适的Zygote进程:根据应用的需求选择普通的Zygote进程、Webview Zygote进程或者是App Zygote进程来启动应用。这里是启动App,所以是App Zygote
  3. 启动应用进程:调用不同的方法来启动应用进程,这些方法会根据选择的Zygote类型有所不同。
  4. 异步准备存储目录:如果需要绑定挂载应用存储目录,则异步执行目录的准备工作,以避免阻塞应用启动过程。

4.11 ZygoteProcess.java

源码地址:/frameworks/base/core/java/android/os/ZygoteProcess.java

startViaZygote全是设置参数

然后到zygoteSendArgsAndGetResult

再到attemptZygoteSendArgsAndGetResult,与Zygote的通信就在这里面。

5 Zygote创建Activity进程

Zygote进程是在Android系统启动过程中创建的,创建完成后会通过ZygoteServer来监听消息

5.1 ZygoteServer.java

ZygoteServer监听消息的方法是runSelectLoop

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

runSelectLoop中会调用ZygoteConnectionprocessCommand

5.2 ZygoteConnection.java

这段代码是 Zygote 进程中的一个关键部分,用于处理来自客户端的命令,以启动新的应用程序进程。

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

  1. 调用 forkAndSpecializeforkSimpleApps
    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, ..., parsedArgs.mAppDataDir);
    ...
    Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), ..., parsedArgs.mNiceName);
    
    调用 forkAndSpecializeforkSimpleApps 方法来创建新的进程,并对其进行配置。
  2. 处理子进程和父进程
    if (pid == 0) {// 在子进程中...return  handleChildProc (parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
    } else {// 在父进程中...handleParentProc(pid, serverPipeFd);return null;
    }
    
    根据 fork() 的返回值来区分父进程和子进程,并分别处理。

handleParentProc中,会将创建好的进程pid发回给请求方(ActivityManagerService)。

handleChildProc中会调用ZygoteInit.``zygoteInit来初始化应用程序

5.3 ZygoteInit.java

Zygote进程的初始化逻辑也是在ZygoteInit中,这里fork创建的进程也是一个Zygote进程,所以也要进行ZygoteInit

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

5.4 RuntimeInit.java

源码地址:/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

进入到findStaticMain,这个方法中,将通过反射找到之前传入的entryPoint(android.app.ActivityThread),然后调用其main方法。

到这里Zygote进行fork子进程的流程已经结束了,接下来将交给ActivityThread进行app的实例创建。

6 初始化Application实例

6.1 ActivityThread.java

源码地址:/frameworks/base/core/java/android/app/ActivityThread.java

attach方法如下

这里的调用栈就不深入了,接下来会调用到bindApplication方法

这里的HActivityThread的一个内置类

最终调用handleBindApplication,进行app实例化。

在实例化中调用的是InstrumentationnewApplication方法。

每个Activity都持有一个Instrumentation,它是由ActivityThread创建出来的一个单例。 这个类就是完成对ApplicationActivity初始化和生命周期的工具类,ActivityThread要创建或执行Activity生命周期方法时,都需要通过Instrumentation来进行具体的操作。

调用OnCreate函数。

至此应用启动的流程就算基本结束了。

7 小结

实际上应用启动后续还需要加载第一个Activity并将其带到前台显示,但由于都是类似的流程,就不再过多赘述了。主要从应用启动流程的学习可以对ZygoteAMS有一些更深入的了解。在启动流程中遇到了BinderHandlerLooper等安卓重要的机制,甚至还涉及到了反射,对后面这些机制的学习也有很大的帮助。

8 引用

Android桌面Launcher源码浅析 - 博客园
Android应用启动流程分析 - 稀土掘金
Android应用程序启动源码浅析-(三万字长文慎点&Android14) - 博客园
Android Application 启动流程分析及其源码调用探究 - 稀土掘金
Android之ServiceManager服务 - 博客园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/797591.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

痞子衡嵌入式:JLink命令行以及JFlash对于下载算法的作用地址范围认定QN

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是JLink命令行以及JFlash对于下载算法的作用地址范围认定。最近痞子衡在给一个 RT1170 客户定制一个 Infineon MirrorBit 类型 64MB Flash 的 SEGGER 下载算法,做完之后在 JFlash 下测试小数据下载没有问题,但…

安卓系统启动流程解析

安卓系统启动流程 目录1 init阶段1.1 FirstStage 1.2 SELinux Setup 1.3 SecondStage2 init.rc的配置 3 Zygote的启动3.1 app_process 3.2 Zygoteinit.java4 SystemServer 5 总结 6 引用光看分析文章还是不够的,还是要和实践结合。 1 init阶段 init 命令的入口是init/main.cpp…

安卓架构

安卓架构 目录1 Linux 内核层 2 硬件抽象层 HAL 3 Native C/C++ 库 && Android Runtime 4 Java Framework 层 5 System Apps 层1 Linux 内核层 Android 平台的基础是 Linux 内核。例如,ART 依靠 Linux 内核来执行底层功能。Linux 内核的安全机制为 Android 提供了相应…

陈柯烽的第一次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc这个作业的目标 建立一个属于自己的博客,介绍自己以及表达对课程的期望姓名-学号 陈柯烽-2022329301006软件技术基础第一次作业 一、自我介绍 1、基本信息我叫陈柯烽,来自浙江宁波,是自动化22级一班的学生,我…

chm 文件打开只显示目录,不显示内容

chm 文件打开只显示目录,不显示内容解决方法:解除锁定OK 了

【好用安全保密】不用插件,压缩js、html、css、code【一眼就会系列】【亲测有效】

​ 仅用离线版Notepad搞定。不用插件及辅助工具,有效保证了文件信息安全。 (一般发布版本都是无注释的-压缩文件和已编译文件。为了信息安全性,所有都是离线-区域网研发。) ​ 总结: 先把文本中注释去掉。 notepad++ 【编辑】-【空白字符操作】-【移除行首和行尾空格】 …

《密码系统设计》第二周

第二周预习报告 学习内容Head First C 嗨翻 C 语言 第8章 《Windows C/C++加密解密实战》第3,5章 第三章重点 3.4,3.5, 特别3.4.4 第五章重点 5.3.7 课程 mindmapAI 对学习内容的总结(1分) 要求让AI阅读学习内容并进行总结总结 1. Head First C 嗨翻 C 语言 第8章函数指针:…

活动召集丨实时多模态 AI Builder 团聚!RTE Open Day@S创上海,9.20/21

9 月 20~21 日,上海, S创上海 2024,看见不一样的创新和技术。这场年轻、多元、活力十足的科技盛会,将汇聚创业者、开发者、艺术家和众多无法定义边界的跨界者。RTE 开发者社区的 Builders 和 RTE Open Day 也将玩乐其中!「有一群人在一起,就很好」。 来到第四期的 RTE O…

问题1:pytorch版本不同,文件运行速度不同

好像新版本更快一点哦,为什么呢? 版本1: PyTorch version: 1.12.1Is CUDA available? TrueCUDA version: 11.3cuDNN version: 8302版本2: PyTorch version: 2.3.1+cu121Is CUDA available? TrueCUDA version: 12.1cuDNN version: 8907

踩坑日志2:dataloader的num_workers问题

当我想用dataloader多开子进程加快图片加载速度时,发现报有关进程的错误:RuntimeError: An attempt has been made to start a new process before thecurrent process has finished its bootstrapping phase.This probably means that you are not using fork to start your…

深度!程序员生涯的垃圾时间(上)

深度好文!程序员的垃圾时间! 垃圾时间(Garbage time)是体育赛事中的术语,指一场比赛中双方分差过大,胜负已定。此时,比赛剩余的时间不再对最终结果产生决定性影响,剩下的时间就被称为垃圾时间。将这个词用在浩浩荡荡的技术革命、汹涌向前的历史车轮上,再合适不过。时代…

基于Java+Springboot+Vue开发的民宿预订管理系统

项目简介该项目是基于Java+Springboot+Vue开发的民宿预订管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的民宿预订管理系统项目,大学生可以在实践中学…