首页/新闻资讯/正文详情

Android14应用冷启动源码2,从 Zygote fork 到 onCreate:Activity 启动流程六阶段拆解

发布时间:2026/11/2 21:08:56 来源:云帆数科 栏目:资讯中心
Android14应用冷启动源码2,从 Zygote fork 到 onCreate:Activity 启动流程六阶段拆解
继续上一篇 Android14 应用冷启动源码从 ActivityThread.attach 到 AttachApplicationHelper-CSDN博客 这一篇继续追踪剩余的应用启动流程。现在已经看到ActivityStackSupervisor的realStartActivityLocked方法了。看下代码太庞大重点是这一段final LaunchActivityItem launchActivityItem LaunchActivityItem.obtain(r.token, r.intent, System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), deviceId, r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken); // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem ResumeActivityItem.obtain(r.token, isTransitionForward, r.shouldSendCompatFakeFocus()); } else { lifecycleItem PauseActivityItem.obtain(r.token); } // Schedule transaction. mService.getLifecycleManager().scheduleTransactionAndLifecycleItems( proc.getThread(), launchActivityItem, lifecycleItem);LaunchActivityItem.obtain(...) 这里把启动 Activity 所需的数据——r.token目标标识、r.intent、r.infoActivityInfo、配置、保存的状态、结果、新 Intent、profiler 信息等——打包成一个命令对象。andResume true启动完这个 Activity 之后紧接着要走 Resume让它可见、获得焦点所以搭配 ResumeActivityItem。 栈顶activity启动走这个分支。 而andResume为false时只创建不需要立刻 onResume。最后一段代码scheduleTransactionAndLifecycleItems第一个参数是ApplicationThread 代理。继续追踪下这里mService就是ActivityTaskManagerService对象getLifecycleManager代码在这里看下ClientLifecycleManager的scheduleTransactionAndLifecycleItems方法代码/** * Schedules a single transaction item with a lifecycle request, delivery to client application. * throws RemoteException * see ClientTransactionItem */ void scheduleTransactionAndLifecycleItems(NonNull IApplicationThread client, NonNull ClientTransactionItem transactionItem, NonNull ActivityLifecycleItem lifecycleItem) throws RemoteException { // The behavior is different depending on the flag. // When flag is on, we wait until RootWindowContainer#performSurfacePlacementNoTrace to // dispatch all pending transactions at once. if (Flags.bundleClientTransactionFlag()) { final ClientTransaction clientTransaction getOrCreatePendingTransaction(client); clientTransaction.addTransactionItem(transactionItem); clientTransaction.addTransactionItem(lifecycleItem); onClientTransactionItemScheduledLocked(clientTransaction); } else { // TODO(b/260873529): cleanup after launch. final ClientTransaction clientTransaction ClientTransaction.obtain(client); clientTransaction.addCallback(transactionItem); clientTransaction.setLifecycleStateRequest(lifecycleItem); scheduleTransaction(clientTransaction); } }它有两个分支由 Flags.bundleClientTransactionFlag() 控制flag 关闭旧路径立即组装 ClientTransaction 并发出。flag 开启新路径先不发出把事务项攒进一个 pending 事务里等 RootWindowContainer#performSurfacePlacementNoTrace 时统一 dispatch。注释写得很直白we wait until ... to dispatch all pending transactions at once。这是新版的性能优化把多次 Binder 调用合并成一次减少 IPC 次数。ClientTransaction.obtain(client)创建事务client 就是 proc.getThread()即 ApplicationThread 代理。事务知道“发给谁”。addCallback(transactionItem)挂上 LaunchActivityItem即“启动指令”。setLifecycleStateRequest(lifecycleItem)挂上 ResumeActivityItem 或 PauseActivityItem即“目标生命周期”。scheduleTransaction(clientTransaction)这里才是真正发出。代码如下继续追踪调用了ClientTransaction的schedule方法mClient.scheduleTransaction(this); 这一行就是 SystemServer 侧发出 Binder 调用的最后一环。mClient 是 IApplicationThread 代理scheduleTransaction(this) 就是把整个 ClientTransaction 打包通过 Binder 发到 App 进程。到这里SystemServer 侧的“组装 → 发出”就闭环了。调用到ApplicationThread的scheduleTransaction方法这里ActivityThread里面没定义scheduleTransaction方法在它的父类ClientTransactionHandler里sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); 切换到主线程看下这个执行事务的消息重点看mTransactionExecutor.execute(transaction); 执行事务。看TransactionExecutor的execute方法如下重点看executeTransactionItems(transaction); 方法如下记得第一个事务是LaunchActivityItem应该是走else分支执行executeNonLifecycleItem。另一个事务是生命周期的后面再来看。先看executeNonLifecycleItem。executeNonLifecycleItem方法如下private void executeNonLifecycleItem(NonNull ClientTransaction transaction, NonNull ClientTransactionItem item, boolean shouldExcludeLastLifecycleState) { final IBinder token item.getActivityToken(); ActivityClientRecord r mTransactionHandler.getActivityClient(token); if (token ! null r null mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) { // The activity has not been created but has been requested to destroy, so all // transactions for the token are just like being cancelled. Slog.w(TAG, Skip pre-destroyed transaction item:\n item); return; } if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) Resolving callback: item); final int postExecutionState item.getPostExecutionState(); if (item.shouldHaveDefinedPreExecutionState()) { final int closestPreExecutionState mHelper.getClosestPreExecutionState(r, postExecutionState); if (closestPreExecutionState ! UNDEFINED) { cycleToPath(r, closestPreExecutionState, transaction); } } item.execute(mTransactionHandler, mPendingActions); item.postExecute(mTransactionHandler, mPendingActions); if (r null) { // Launch activity request will create an activity record. r mTransactionHandler.getActivityClient(token); } if (postExecutionState ! UNDEFINED r ! null) { cycleToPath(r, postExecutionState, shouldExcludeLastLifecycleState, transaction); } }重点看item.execute(mTransactionHandler, mPendingActions); 这句代码。启动事务LaunchActivityItem的execute方法如下final ActivityClientRecord r new ActivityClientRecord(mActivityToken, mIntent, mIdent,mInfo, mOverrideConfig, ...);---- LaunchActivityItem 是从 SystemServer 的 LaunchActivityItem.obtain(...) 打包过来的经过 Binder 传输后它的字段在 App 端被还原。这一行把这些字段组装成 App 端真正能用的 ActivityClientRecord。ActivityClientRecord 是 App 端的“Activity 记录”可以理解为 SystemServer 侧 ActivityRecord 的客户端镜像。关键字段mActivityToken就是 SystemServer 侧的 r.token两边靠它关联同一个 ActivitymIntent、mInfo启动的 Intent 和 ActivityInfomState、mPersistentState保存的状态用于恢复mPendingResults、mPendingNewIntents启动时要投递的结果和新 Intent。然后client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);这里的 client 是 ClientTransactionHandler 类型实际对象就是 ActivityThread因为 ActivityThread extends ClientTransactionHandler。所以这一行就是调用 ActivityThread.handleLaunchActivity(...)。ActivityThread的handleLaunchActivity方法如下Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, int deviceId, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged true; if (r.profilerInfo ! null) { mProfiler.setProfiler(r.profilerInfo); mProfiler.startProfiling(); } // Make sure we are running with the most recent config and resource paths. applyPendingApplicationInfoChanges(r.activityInfo.packageName); mConfigurationController.handleConfigurationChanged(null, null); updateDeviceIdForNonUIContexts(deviceId); if (localLOGV) Slog.v( TAG, Handling launch of r); // Initialize before creating the activity if (ThreadedRenderer.sRendererEnabled (r.activityInfo.flags ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! 0) { HardwareRenderer.preload(); } WindowManagerGlobal.initialize(); // Hint the GraphicsEnvironment that an activity is launching on the process. GraphicsEnvironment.hintActivityLaunch(); final Activity a performLaunchActivity(r, customIntent); if (a ! null) { r.createdConfig new Configuration(mConfigurationController.getConfiguration()); reportSizeConfigurations(r); if (!r.activity.mFinished pendingActions ! null) { pendingActions.setOldState(r.state); pendingActions.setRestoreInstanceState(true); pendingActions.setCallOnPostCreate(true); } // Trigger ActivityWindowInfo callback if first launch or change from relaunch. handleActivityWindowInfoChanged(r); } else { // If there was an error, for any reason, tell the activity manager to stop us. ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED, null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } return a; }final Activity a performLaunchActivity(r, customIntent); 这句代码是重点。然后看performLaunchActivity这个方法太庞大。前面是准备 ActivityInfo 和 ClassLoader然后创建activity对象里面最终是调用反射构造activity对象。然后重点看activity.attach方法attach() 内部会做几件关键事创建 PhoneWindow、设置 WindowManager、调用 attachBaseContext() 把 ContextImpl 注入进去。这是 Activity 从“裸对象”变成“有 Context 的 Activity”的分界点也是 Application 和 Activity 共享同一套 Context 体系的连接处。然后重点看这一句代码mInstrumentation.callActivityOnCreate(activity, r.state);callActivityOnCreate里面最终会调用activity的onCrate方法。这一行最终回调到自己写的 Activity.onCreate()。到这里跨进程启动指令的完整旅程就结束了——SystemServer 发出的 LaunchActivityItem经过 Binder、H、TransactionExecutor最终到onCreate。ok. 回顾了下从ActivityThread的main方法开发main里面调用attach方法中间经过很长的调用链最终执行到了activity的onCreate。 调用链实在太长细节很容易忘总结下如下┌─────────────────────────── Zygote fork ───────────────────────────┐│ ││ App 进程 (主线程) ││ ActivityThread.main() ││ └─ attach() ││ └─ mgr.attachApplication(mAppThread, startSeq) ────────────┼── Binder ──┐│ │ │└────────────────────────────────────────────────────────────────────┘ ││┌─────────────────────────── system_server ────────────────────────────────────────┘││ AMS.attachApplication()│ └─ attachApplicationLocked(thread, pid, uid, startSeq)│ ├─ thread.asBinder().linkToDeath(adr, 0) ← 监听 App 死亡│ ├─ thread.bindApplication(...) ──────────────┼── Binder ──┐ (oneway)│ └─ app.makeActive(thread, mProcessStats) ← 通道登记│ │└────────────────────────────────────────────────────────────────────┘│┌─────────────────────────── App 进程 (Binder 线程) ──────────────────┘││ ApplicationThread.bindApplication()│ └─ queueOrSendMessage(H.BIND_APPLICATION, data)│├─────────────── 切主线程 ───────────────┐│ ││ App 进程 (主线程) ▼│ H.handleMessage(BIND_APPLICATION)│ └─ handleBindApplication(data)│ ├─ app data.info.makeApplicationInner(...) ← Application 实例│ ├─ installContentProviders(app, ...) ← Provider 先于 onCreate│ ├─ mInstrumentation.callApplicationOnCreate(app) ← Application.onCreate()│ └─ mgr.finishAttachApplication(startSeq, ...) ── Binder ──┐│ │└────────────────────────────────────────────────────────────────────┘│┌─────────────────────────── system_server ──────────────────────────┘││ AMS.finishAttachApplicationInner()│ └─ mAtmInternal.attachApplication(wpc) ← LocalServices同进程│ └─ ATMS.LocalService.attachApplication(wpc)│ └─ RootWindowContainer.attachApplication(wpc)│ └─ AttachApplicationHelper.process(app)│ └─ accept() → forAllActivities(this) → test(r)│ └─ realStartActivityLocked(r, app, andResume, ...)│ ├─ LaunchActivityItem.obtain(...) ← 启动指令│ ├─ ResumeActivityItem.obtain(...) ← 目标状态│ └─ ClientTransaction.schedule()│ └─ mClient.scheduleTransaction(t) ── Binder ──┐│ │└─────────────────────────────────────────────────────────────────────────────────────┘│┌─────────────────────────── App 进程 (Binder 线程) ───────────────────────────────────┘││ ApplicationThread.scheduleTransaction()│ └─ ActivityThread.scheduleTransaction() ← 实际在父类 ClientTransactionHandler│ └─ sendMessage(H.EXECUTE_TRANSACTION, transaction)│├─────────────── 切主线程 ───────────────┐│ ││ App 进程 (主线程) ▼│ H.handleMessage(EXECUTE_TRANSACTION)│ └─ TransactionExecutor.execute()│ └─ executeTransactionItems()│ └─ executeNonLifecycleItem()│ └─ LaunchActivityItem.execute()│ └─ ActivityThread.handleLaunchActivity()│ └─ performLaunchActivity()│ ├─ mInstrumentation.newActivity(...) ← 反射创建│ ├─ activity.attach(...) ← 注入 Context│ └─ mInstrumentation.callActivityOnCreate(...) ← Activity.onCreate()压缩成六个阶段整条链路很长但本质上只有三次关键切换整条链路再长本质上只有三次关键切换1、App → 系统attachApplicationApp 把 ApplicationThread 这个 Binder 对象交给系统。2、系统 → AppbindApplication 和 scheduleTransaction系统通过 ApplicationThread 代理反向调用 App。3、Binder 线程 → 主线程两次 sendMessage(H.XXX)分别在 bindApplication 和 scheduleTransaction 之后把工作从 Binder 线程池抛给主线程。一句话记忆attach 交通道 → bindApplication 造 Application → finishAttachApplication 报完成 → realStartActivityLocked 发事务 → LaunchActivityItem 造 Activity。 两次 Binder 往返两次 H 切主线程起点是 ActivityThread.main()终点是 Activity.onCreate()。

相关推荐

课堂笔记4
课堂笔记4

课前练习求任意一个三位数&#xff0c;个十百位相加值#include <stdio.h>int main(){ int a,b,c,m,sum;printf("请输入任意一个三位数m")&#xff1b;scanf("%d",&m);am%10;bm/10%10;cm/100;sumabc;printf("%d\n",sum);return 0;}正… · 2026/11/1 1:55:31

RAG二 文档切分实战:从语义分层到长度优化
RAG二 文档切分实战:从语义分层到长度优化

1. 背景与目标在构建知识库或 RAG 检索链路时&#xff0c;Markdown 文档的切分质量直接决定了后续向量召回的效果。本文围绕一个基于 LangGraph 的导入流程节点&#xff0c;讲解如何先按标题做语义切分&#xff0c;再对超长块做递归二次切割&#xff0c;最终产出结构清晰、长度… · 2026/11/2 3:10:50

企业班车供应商怎么选:招标评审真正在看的五件事
企业班车供应商怎么选:招标评审真正在看的五件事

企业班车供应商怎么选&#xff1a;招标评审真正在看的五件事 一份班车招标文件发出去&#xff0c;收回七八份报价&#xff0c;价格差能拉到 30%。评审会上最先被翻开的&#xff0c;往往不是那张报价表。 这不是采购不专业&#xff0c;而是行业里的一个共识&#xff1a;班车是&q… · 2026/11/2 3:10:24

平台雷达PLFM_RADAR:主动扫描与配置漂移检测实践
平台雷达PLFM_RADAR:主动扫描与配置漂移检测实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 21:08:06

平台可观测性实践:用雷达式监控打通日志、指标与告警
平台可观测性实践:用雷达式监控打通日志、指标与告警

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 21:08:06

PLFM雷达信号处理框架:相位建模驱动的微动感知方法
PLFM雷达信号处理框架:相位建模驱动的微动感知方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 21:08:06

FPGA与STM32协同实现LFM脉冲雷达:从信号生成到脉冲压缩的工程实战
FPGA与STM32协同实现LFM脉冲雷达:从信号生成到脉冲压缩的工程实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 21:08:06

VoiceStudio实测:AI语音合成与声音克隆全流程指南
VoiceStudio实测:AI语音合成与声音克隆全流程指南

“VoiceStudio”这个词最近在我常逛的几个音频制作社群里面频繁出现&#xff0c;一开始以为是某个插件的名字&#xff0c;点进去才发现是一个集语音合成、声音克隆、音频编辑于一体的AI语音工作台。我刚好手上有一个系列短视频的配音需求&#xff0c;索性拿完整项目实测了一轮&… · 2026/11/2 21:07:05

解决gitk显示竖条纹:Tcl/Tk与X11配置指南
解决gitk显示竖条纹:Tcl/Tk与X11配置指南

1. gitk显示竖条纹问题解析最近在Ubuntu 22.04上使用gitk查看版本历史时&#xff0c;遇到了一个奇怪的显示问题&#xff1a;界面出现了明显的竖条纹。这个问题看似简单&#xff0c;实际上涉及到Tcl/Tk图形库、X11显示协议和系统字体配置等多个技术层面的交互。gitk作为Git自带的… · 2026/11/2 21:07:05

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

雷达信号调制技术解析:从LFM到伪线性调频原理与应用
雷达信号调制技术解析:从LFM到伪线性调频原理与应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15

基于MAX14431与TM4C123的工业SPI隔离电路设计全攻略
基于MAX14431与TM4C123的工业SPI隔离电路设计全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15

PLFM_RADAR:相位线性调频雷达信号处理框架
PLFM_RADAR:相位线性调频雷达信号处理框架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码