Activity的启动流程

小伙伴们面试的时候是不是被问过Activity的启动流程很多啊。那我们就来看看吧。个人感觉这类文章代码细节太多,反而容易迷失在源码调用之中,从而忽略了Activity启动过程的本质。所以本文就简单地定性地对Activity启动过程进行描述,不会贴上大篇幅的源码。本文是根据Android11.0系统源码讲述的。

冷启动与热启动

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

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

应用启动流程

一般来说,冷启动包括了以下内容:

  1. 启动进程 点击图标发生在Launcher应用的进程,startActivity()函数最终调用的是Instrumentation中execStartActivity

/frameworks/base/core/java/android/app/Activity.java

startActivity

调用的是startActivityForResult 

 startActivityForResult

调用的是Instrumentation 里面的  

 /frameworks/base/core/java/android/app/Instrumentation.java

这个圈起来的地方android9.0以及9.0以前是这样调用的,直接调用的是AMS的startActivity

9.0之后是这样调用的,调用的是ATM的startActivity

ActivityTaskManager.getService 是获取的什么呢

  public static IActivityManager getService() {
4126          return IActivityManagerSingleton.get();
4127      }
4128  
4129      private static final Singleton<IActivityManager> IActivityManagerSingleton =
4130              new Singleton<IActivityManager>() {
4131                  @Override
4132                  protected IActivityManager create() {
4133                      final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
4134                      final IActivityManager am = IActivityManager.Stub.asInterface(b);
4135                      return am;
4136                  }
4137              };
4138  

 获取的是IActivityManager,通过跨进程进入到ActivityManagerService中的startActivity

/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

 @Override
1210      public final int startActivity(IApplicationThread caller, String callingPackage,
1211              String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
1212              String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
1213              Bundle bOptions) {
1214          return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
1215                  resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
1216                  UserHandle.getCallingUserId());
1217      }
    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
1245              @Nullable String callingFeatureId, Intent intent, String resolvedType,
1246              IBinder resultTo, String resultWho, int requestCode, int startFlags,
1247              ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
1248  
1249          final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
1250  
1251          assertPackageMatchesCallingUid(callingPackage);
1252          enforceNotIsolatedCaller("startActivityAsUser");
1253  
1254          if (intent != null && intent.isSandboxActivity(mContext)) {
1255              SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
1256                      SdkSandboxManagerLocal.class);
1257              sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
1258                      intent, Binder.getCallingUid(), callingPackage
1259              );
1260          }
1261  
1262          if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
1263              SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
1264                      SdkSandboxManagerLocal.class);
1265              if (sdkSandboxManagerLocal == null) {
1266                  throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
1267                          + " an activity from an SDK sandbox uid.");
1268              }
1269              sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
1270          }
1271  
1272          userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
1273                  Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
1274  
1275          // TODO: Switch to user app stacks here.
1276          return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
1277                  .setCaller(caller)
1278                  .setCallingPackage(callingPackage)
1279                  .setCallingFeatureId(callingFeatureId)
1280                  .setResolvedType(resolvedType)
1281                  .setResultTo(resultTo)
1282                  .setResultWho(resultWho)
1283                  .setRequestCode(requestCode)
1284                  .setStartFlags(startFlags)
1285                  .setProfilerInfo(profilerInfo)
1286                  .setActivityOptions(opts)
1287                  .setUserId(userId)
1288                  .execute();
1289  
1290      }

跳转到/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

执行execute

 然后看executeRequest 中代码

 再看startActivityUnchecked

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
1459              IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1460              int startFlags, ActivityOptions options, Task inTask,
1461              TaskFragment inTaskFragment, @BalCode int balCode,
1462              NeededUriGrants intentGrants, int realCallingUid) {
1463          int result = START_CANCELED;
1464          final Task startedActivityRootTask;
1465  
1466          // Create a transition now to record the original intent of actions taken within
1467          // startActivityInner. Otherwise, logic in startActivityInner could start a different
1468          // transition based on a sub-action.
1469          // Only do the create here (and defer requestStart) since startActivityInner might abort.
1470          final TransitionController transitionController = r.mTransitionController;
1471          Transition newTransition = transitionController.isShellTransitionsEnabled()
1472                  ? transitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
1473          RemoteTransition remoteTransition = r.takeRemoteTransition();
1474          try {
1475              mService.deferWindowLayout();
1476              transitionController.collect(r);
1477              try {
1478                  Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
1479                  result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
1480                          startFlags, options, inTask, inTaskFragment, balCode,
1481                          intentGrants, realCallingUid);
1482              } finally {
1483                  Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
1484                  startedActivityRootTask = handleStartResult(r, options, result, newTransition,
1485                          remoteTransition);
1486              }
1487          } finally {
1488              mService.continueWindowLayout();
1489          }
1490          postStartActivityProcessing(r, result, startedActivityRootTask);
1491  
1492          return result;
1493      }

继续看startActivityInner,如图红色框标志的代码

跳转到 frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

看resumeFocusedTasksTopActivities

resumeTopActivityUnCheckedLocked 

接着到  /frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java 中resumeTopActivityUnCheckedLocked ,调用红色边框线内代码

 

resumeTopActivityInnerLocked 

 /frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java

判断如果进程存在,执行realStartActivityLocked;进程不存在,执行mService.startProcessAsync。这样就回到了开头我们说的冷启动,就会发送请求给Zygote进程,fork出新进程。

/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

 跳转到ActivityManagerService中的startProcess

 然后接着看startProcessLocked

跳转到 /frameworks/base/services/core/java/com/android/server/am/ProcessList.java

中startProcessLocked,执行如下代码

 startProcess中执行的是Process start

ZYGOT_PROCESS start 调用的是

/frameworks/base/core/java/android/os/ZygoteProcess.java 里的start

startViaZygote: 

看第一个参数openZygoteSocketIfNeeded, 

调用的attemptConnectionToPrimaryZygote

connect: 

创建了Socket,然后连接zygote

 

回过头来看startViaZygote这个方法,最后返回的是

 然后调用attemptUsapSendArgsAndGetResult

usapWriter.write 写数据,usapReader.read读数据,完成AMS和Zygote之间的通讯。

Zygote是如何创建进程的呢,其实是和system_server创建进程一样的,最终执行的是ActivityThread中的main方法

/frameworks/base/core/java/android/app/ActivityThread.java

 public static void main(String[] args) {
7612          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
7613  
7614          // Install selective syscall interception
7615          AndroidOs.install();
7616  
7617          // CloseGuard defaults to true and can be quite spammy.  We
7618          // disable it here, but selectively enable it later (via
7619          // StrictMode) on debug builds, but using DropBox, not logs.
7620          CloseGuard.setEnabled(false);
7621  
7622          Environment.initForCurrentUser();
7623  
7624          // Make sure TrustedCertificateStore looks in the right place for CA certificates
7625          final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
7626          TrustedCertificateStore.setDefaultUserDirectory(configDir);
7627  
7628          // Call per-process mainline module initialization.
7629          initializeMainlineModules();
7630  
7631          Process.setArgV0("<pre-initialized>");
7632  
7633          Looper.prepareMainLooper();
7634  
7635          // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
7636          // It will be in the format "seq=114"
7637          long startSeq = 0;
7638          if (args != null) {
7639              for (int i = args.length - 1; i >= 0; --i) {
7640                  if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
7641                      startSeq = Long.parseLong(
7642                              args[i].substring(PROC_START_SEQ_IDENT.length()));
7643                  }
7644              }
7645          }
7646          ActivityThread thread = new ActivityThread();
7647          thread.attach(false, startSeq);
7648  
7649          if (sMainThreadHandler == null) {
7650              sMainThreadHandler = thread.getHandler();
7651          }
7652  
7653          if (false) {
7654              Looper.myLooper().setMessageLogging(new
7655                      LogPrinter(Log.DEBUG, "ActivityThread"));
7656          }
7657  
7658          // End of event ActivityThreadMain.
7659          Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
7660          Looper.loop();
7661  
7662          throw new RuntimeException("Main thread loop unexpectedly exited");
7663      }
7664  

AMS是通过thread.attah管理新进程中的Activity的

 

其中  final IActivityManager mgr = ActivityManager.getService(); 获取到AMS,然后mgr.attachApplication 添加 ApplicationThread

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT如何在一分钟内完成论文数据分析?

数据上传 PPMAN-AI 01 由于技术限制&#xff0c;目前InfinitePaper AI仅支持上传1份文件&#xff0c;且大小不超过10M。但是&#xff0c;在强大的代码解释器面前&#xff0c;这都是小问题。我们只需要将可能用到的文件打包成压缩文件上传即可&#xff0c;之后要求GPT直接解压…

动画渲染案例 | 《舒克贝塔·五角飞碟》欢乐开年,经典IP唤醒童年回忆

《舒克贝塔五角飞碟》是由杭州童话大王影视有限公司、天津猫眼微影文化传媒有限公司出品&#xff0c;郑亚旗执导和编剧的动画电影。蓝海创意云为该片提供了渲染服务。电影于2023年12月30日正式上映&#xff0c;上映不到一个月时间累计票房突破5000万大关&#xff0c;并被评为“…

css1基础选择器

大纲 一.标签选择器 比较简单&#xff0c;前面直接写目标标签 二.类选择器 应用 例子 三.多类名选择器&#xff08;调用时中间用空格隔开&#xff09; 四.id选择器 应用 五.通配符选择器 应用 六.总结

大模型日报-20240204

刚刚&#xff0c;字节版GPTs「扣子」上线了 https://mp.weixin.qq.com/s/efNjbeK8Zul39nLzQuawCg 在持续一年的大模型热潮之后&#xff0c;「智能体」成为了科技公司们新的押注方向之一。近日&#xff0c;字节跳动正式推出「Coze 扣子」AI Bot 开发平台。任何用户都可以快速、…

数据孤岛是什么?企业如何应对?

数据孤岛指的是数据在组织内部无法自由流通和共享的状态&#xff0c;这种现象不仅影响了业务的高效运作&#xff0c;也威胁着企业的创新和竞争力。本文将深入探讨数据孤岛问题&#xff0c;分析其产生的原因以及对企业的影响&#xff0c;最后提出有效的应对策略。 一、数据孤岛…

npm---设置淘宝镜像时报“certificate has expired“的错误

今天使用vue create my-app 创建项目时&#xff0c;竟然报错&#xff1a; Error: Command failed: npm info vue-cli-version-marker --json --registryhttps://registry.npm.taobao.org npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request t…

速度规划:用s形曲线规划速度------pencv c++绘图(2)

理论篇 应用篇 实现变速规划 #include <iostream> #include <opencv2/opencv.hpp> // 包含OpenCV头文件 #include <chrono> #include <thread>using namespace std;#define _CRT_SECURE_NO_WARNINGS #define a_max 1.0 #define J 0.2 #define v_m…

商家转账到零钱功能申请方法

商家转账到零钱是什么&#xff1f; 商家转账到零钱功能整合了企业付款到零钱和批量转账到零钱&#xff0c;支持批量对外转账&#xff0c;操作便捷。如果你的应用场景是单付款&#xff0c;体验感和企业付款到零钱基本没差别。 商家转账到零钱的使用场景有哪些&#xff1f; 商…

基于YOLOv8的工业油污缺陷检测,多种优化方法---自研新型轻量级的实时检测算法(四)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了工业油污缺陷检测整个过程&#xff0c;从数据集到训练模型到结果可视化分析&#xff0c;以及如何优化提升检测性能。 &#x1f4a1;&#x1f4a1;&#x1f4a1;加入 自研新型轻量级的实时检测算法 mAP0.5由原始…

IDEA创建JavaWeb项目(保姆级别)

文章目录 1.1 原始的 Web 项目1.1.1 创建 Java web 项目1.1.2 完善项目结构1.1.3 依赖添加1.1.4 部署服务器(Tomcat)1.1.5 启动项目 1.2 使用 Maven 创建 Web 项目1.2.1 使用 maven 创建 web1.2.2 配置编译路径和jar包存放位置1.2.3 部署服务器&#xff08;Tomcat&#xff09;1…

2024.2.3

单向循环链表的头插 头删 尾插和尾删 //头结点插入 Linklist insere_element(Linklist head,datatype element) {Linklist screat();s->dataelement;if(NULLhead){heads;}else{Linklist phead;while(p->next!head){pp->next;}s->nexthead;heads;p->nexthead;}r…

【51单片机】开发板&开发软件(Keil5&STC-ISP)简介&下载安装破译传送门(1)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

Netflix Mac(奈飞mac客户端) v2.13.0激活版

Clicker for Netflix Mac版是一款适用于Mac的最佳独立Netflix播放器&#xff0c;具有直接从从Dock启动Netflix&#xff0c;从触摸栏控制Netflix&#xff0c;支持画中画等多种功能&#xff0c;让你拥有更好的观看体验。 软件特色 •直接从Dock启动Netflix •从触摸栏控制Netflix…

迅为STM32MP157开发板底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块

底板扩展接口丰富 底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口CAMERA接口、ADC电位器、SPDIF、SDIO接口等。 支持多种显示屏 迅为在MP157开发板支持了多种屏幕&#xff0…

C# 使用 MailKit 发送邮件(附demo)

C# 使用 MailKit 发送邮件&#xff08;附demo&#xff09; 介绍安装包&#xff08;依赖&#xff09;案例简单代码属性介绍&#xff1a;MailboxAddress属性介绍&#xff1a;BodyBuilderSMTP 服务器端口SSL的案例&#xff1a;非SSL&#xff1a; 介绍一下SMTP 介绍 MailKit 是一…

2024年【高压电工】考试内容及高压电工模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工考试内容参考答案及高压电工考试试题解析是安全生产模拟考试一点通题库老师及高压电工操作证已考过的学员汇总&#xff0c;相对有效帮助高压电工模拟试题学员顺利通过考试。 1、【单选题】 FN5-10的型号含意是…

「Kafka」消费者篇

「Kafka」消费者篇 Kafka 消费方式 Kafka 消费者工作流程 消费者总体工作流程 新版本&#xff08;0.9之后&#xff09;的 offset 保存在 kafka 的 Topic 里&#xff0c;持久化到磁盘&#xff0c;可靠性有保障。 老版本&#xff08;0.9之前&#xff09;的 offset 保存在 Zook…

2.0 Hadoop 运行环境

由于 Hadoop 是为集群设计的软件&#xff0c;所以我们在学习它的使用时难免会遇到在多台计算机上配置 Hadoop 的情况&#xff0c;这对于学习者来说会制造诸多障碍&#xff0c;主要有两个&#xff1a; 昂贵的计算机集群。多计算机构成的集群环境需要昂贵的硬件.难以部署和维护。…

LeetCode_19_中等_删除链表的倒数第N个结点

文章目录 1. 题目2. 思路及代码实现&#xff08;Python&#xff09;2.1 计算链表长度2.2 栈 1. 题目 给你一个链表&#xff0c;删除链表的倒数第 n n n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a; h e a d [ 1 , 2 , 3 , 4 , 5 ] , n…

爬虫(二)

1.同步获取短视频 1.只要播放地址对Json数据解析&#xff0c;先把列表找出&#xff1a; 2.只想要所有的播放地址&#xff0c;通过列表表达式循环遍历这个列表拿到每个对象&#xff0c;再从一个个对象里面找到Video,再从Video里面找到播放地址(play_addr),再从播放地址找到播放…
最新文章