Activity的启动流程

news2024/11/15 10:44:37

小伙伴们面试的时候是不是被问过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.coloradmin.cn/o/1430815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微软的Copilot for Sales(销售助手)和Copilot for Service(服务助手)现已全面开放

深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领域的领跑者。点击订阅&#xff0c;与未来同行&#xff01; 订阅&#xff1a;https://rengongzhineng.io/ 。 微…

Redis 的持久化机制是什么?各自的优缺点?

Redis 提供两种持久化机制 RDB&#xff08;默认&#xff09; 和 AOF 机制: RDB&#xff1a;是Redis DataBase缩写快照 RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中&#xff0c;对应产生的数据文件为dump.rdb。通过配置文件中的save参数来…

vulhub中Adminer ElasticSearch 和 ClickHouse 错误页面SSRF漏洞复现(CVE-2021-21311)

Adminer是一个PHP编写的开源数据库管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。 在其4.0.0到4.7.9版本之间&#xff0c;连接 ElasticSearch 和 ClickHouse 数据库时存在一处服务端请求伪造漏洞&#xff08…

【PCL】(九)点云体素下采样

&#xff08;九&#xff09;Filtering 体素下采样 点云样例&#xff1a; https://raw.github.com/PointCloudLibrary/data/master/tutorials/table_scene_lms400.pcd 以下程序实现对读取的点云进行体素下采样&#xff0c;并将得到的点云保存。 voxel_grid.cpp #include <…

Web APIs 1 DOM操作

Web APIs 1 引入&#xff1a;const优先Web API 基本认知01 作用和分类02 什么是DOM03 DOM树04 DOM对象 获取DOM对象01 根据CSS选择器获取02 其他获取DOM元素方法 操作元素内容01 innerText 属性02 innerHTML 属性 操作元素属性操作元素的常用属性操作元素的样式属性操作表单元素…

FPGA项目(15)——基于FPGA的DDS信号发生器

1.相关概念 DDS&#xff08;Direct Digital Synthesis&#xff0c;直接数字合成&#xff09;是一种通过数字技术生成精确频率和相位可调的信号的方法。它基于数字时钟和数值控制的方式&#xff0c;通过累加器、相位累积器和查表器等组件&#xff0c;以数字方式实现信号的频率和…

RK35x8-RTC(RX8025T)驱动加载

RTC芯片简介 RX8025-T是EPSON 推出的一款拥有I2C接口和温度补偿功能的新型实时时钟芯片&#xff0c;内部集成32.768KHz温度补偿晶体振荡器&#xff0c;可用于各种需要高精度时钟的场合。通过设置相应补偿的控制位&#xff0c;可以实现不同间隔的温度补偿功能&#xff0c;从而大…

聊聊并发编程,另送5本Golang并发编程新书

大家好&#xff0c;我是飞哥&#xff01; 并发编程并不是一个新话题&#xff0c;但是我觉得在近几年以及未来的时间里&#xff0c;并发编程将显得越来越重要。 为什么这样讲&#xff0c;让我们先回到一个基本的问题上来&#xff0c;为什么我们要采用并发编程&#xff1f;关于这…

Gson源码解读

一&#xff0c;概述 gson作为流行的json工具&#xff0c;笔者使用较多。本文主要目的是解读下Gson的源码实现&#xff0c;就没有然后了。 二&#xff0c;实例 实例如下图所示&#xff0c;笔者简单调用gson的toJson方法获得json字符串&#xff0c;fromJson则从json字符串解析…

基于单片机的造纸纸浆液位控制系统结构设计

摘要:为适应无人化与高效化制浆造纸生产体系&#xff0c;造纸企业趋于以嵌入式技术优化造纸过 程中的纸浆液位控制系统&#xff0c;以单片机与传感器相互耦合实现纸浆液位控制。本文基于单片机 设计了造纸纸浆液位控制系统&#xff0c;其结构由控制模块、信息采集模块、物联网模…

ASP.NET Core 自定义解压缩提供程序

写在前面 在了解ASP.NET Core 自定义请求解压缩中间件的应用时&#xff0c;依据官方文档操作下来碰到了几个问题&#xff0c;这边做个记录。 关键点就是配置 Content-Encoding&#xff0c;参数需要和代码中添加的提供程序的Key保持一致&#xff1b; builder.Services.AddRequ…

(bean配置类的注解开发)学习Spring的第十三天

bean配置类的注解开发 问题提出 用类充当配置文件 applicationcontext.xml : Configuration注解标识此类为配置类,替代原有xml文件 看原配置文件applicationcontext.xml代码 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http:/…

ctfshow——文件包含

文章目录 web 78——php伪协议第一种方法——php://input第二种方法——data://text/plain第三种方法——远程包含&#xff08;http://协议&#xff09; web 78——str_replace过滤字符php第一种方法——远程包含&#xff08;http://协议&#xff09;第二种方法——data://&…

FPGA项目(16)——基于FPGA的音乐演奏电路

1.设计要求 能在实验箱上&#xff0c;循环播放一段音乐。&#xff08;需要源码的直接看最后一节&#xff09; 2.设计原理 组成乐曲的每个音符的发音频率值及其持续的时间是乐曲能连续演奏所需要的两个基本要素&#xff0c;问题是如何来获取这两个要素所对应的数值以及通过纯硬件…

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…

探索前端开发框架:React、Angular 和 Vue 的对决(一)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Linux下vim命令详解

vim #创建或编辑新的文件 #这将在当前目录下创建一个名为fi.txt的新文本文件。如果文件已经存在&#xff0c;将会编辑现有文件。 [rootsever ~]#vim fi.txt #对于普通的文本编辑操作&#xff0c;可以使用以下键盘命令&#xff1a; - i&#xff1a;进入插入模式&#xff…

[职场] 英语面试自我介绍 #微信#笔记#媒体

英语面试自我介绍 英语面试自我介绍1 I am very happy to introduce myself here.I was born in Liaoning Province.I graduated from Nankai University and majored in International Trade.I like music and reaing books,especially economical books.It is my honor to ap…

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小二乘支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于OOA-LSSVM鱼鹰算法…

Java数组声明、创建、赋值和使用

目录 数组的定义数组的创建访问数组元素遍历数组数组实例分析 数组的定义 数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据&#xff0c;按照一定的先后次序排列组合而成。其中&#xff0c;每一个数据称作一个元素&#xff0c;每个元素可以通过一个索引&#…