乐于分享
好东西不私藏

第 1 篇:App 发起启动

第 1 篇:App 发起启动

文章中代码基于 Android 15 版本,旨在串流程,打破遇到问题无从下手的窘境。

结论startActivity 没抛异常 ≠ 界面已经出来。只说明 ATMS 已接单,窗口还要等事务下发、onCreate/onResume、attach、绘制。本文只讲:这一行调用怎么进到系统、怎么验证「请求已进 ATMS」、以及别把「接单」当「已创建窗口」。

堆栈格式与 printStackTrace() 一致:自上而下 = 从当前/最内层到根/入口,便于对照日志 trace 分析。


一、你遇到的现象 / 问题

  • 点了图标或按钮,startActivity 没抛异常,但界面迟迟不出或「没反应」。
  • 想确认:请求到底有没有进 system_server? 目标 Activity 有没有入栈?

→ 下面用调用堆栈表示「进系统」的路径(与 总览 同一格式);再往后是可复现操作 + 真实示例,照着做即可验证。


二、主流程:App 一行调用 → ATMS(调用堆栈)

格式同 printStackTrace():上=当前/最内层,下=根/入口。进程块用 ▼ 标题;跨进程用一行标出「调用方 ──► 被调方」和接口名。

▼ system_server · ATMS 入口(决策点 1 起点)  at ActivityStarter.execute  at ActivityTaskManagerService.startActivityAsUser   // 内为 getActivityStartController().obtainStarter(...).setCaller(...).execute()  at ActivityTaskManagerService.startActivityBinder: App ──► system_server (IActivityTaskManager.startActivity)▼ App 进程  at ActivityTaskManager.getService().startActivity  at Instrumentation.execStartActivity  at Activity.startActivityForResult  at Activity.startActivity

指路:真正进系统的是 Instrumentation.execStartActivity → Binder → ATMS;startActivityAsUser 后交 obtainStarter(...).execute(),即决策点 1(见总览)。


三、三种入口汇入 ATMS(调用堆栈)

下面列出最常用的三种入口(对应 ATMS 的 startActivity/startActivityAsUser 与 startActivityIntentSender);ATMS 侧还有 startActivities(批量)、startActivityFromRecents(最近任务)、startActivityAndWaitstartActivityWithConfig 等接口,用于其他场景,此处不展开。以下调用栈为典型路径,与 AOSP 代码一致;实际栈可能因版本或分支略有差异。

入口 1:Activity 内 startActivity

▼ system_server  at ActivityTaskManagerService.startActivityAsUser  at ActivityTaskManagerService.startActivity  ...Binder: App ──► system_server (IActivityTaskManager.startActivity)▼ App 进程  at ActivityTaskManager.getService().startActivity  at Instrumentation.execStartActivity  at Activity.startActivityForResult  at Activity.startActivity

入口 2:PendingIntent.send(不经过当前 App 的 Instrumentation)

▼ system_server  at ActivityTaskManagerService.startActivityIntentSender  ...Binder: 调用方进程 ──► system_server (startActivityIntentSender)▼ 调用方进程(如 Notification、其他 App)  at IntentSender.sendIntent  at PendingIntent.send

入口 3:非 Activity 的 Context 内 startActivity(如 Application、Service)

▼ system_server  at ActivityTaskManagerService.startActivityAsUser  at ActivityTaskManagerService.startActivity  ...Binder: App ──► system_server (IActivityTaskManager.startActivity)▼ App 进程(如 Service 所在进程)  at ActivityTaskManager.getService().startActivity  at Instrumentation.execStartActivity  at ContextImpl.startActivity  at Service.startActivity / Application 内调用等

指路:入口 1、3 在 system_server 侧均为 startActivity / startActivityAsUser,区别在调用方栈(Activity 内 vs ContextImpl/Service);入口 2 走 startActivityIntentSender,不经过当前 App 的 Instrumentation。


四、为什么会误判?(原理只讲一层)

  • 「调用成功」
    :Binder 返回非致命码(如 START_SUCCESS),checkStartActivityResult 不抛 → 只表示 ATMS 已接单
  • 「已创建窗口」
    :目标进程已执行 handleResume、ViewRootImpl、finishDrawing 等(决策点 2/3)。

中间还有:进程创建、scheduleTransaction 下发、onCreate/onResume、attach 窗口、Transition。所以没抛异常不能推出「系统已经去建窗口」,排查「点了没反应」要看 dumpsys / 事务是否下发。


五、可复现操作 + 真实示例

环境与前提

  • 环境
    :AOSP 源码树、已连接设备(真机或模拟器)、adb 可用。
  • 前提
    :已安装本仓库示例 App startactivitydemo(见下)。

真实示例 App:startactivitydemo

  • 位置
    :本仓库示例工程 startactivitydemo(Gradle 工程,可与文档一起发布);若需随系统镜像发布,可将该工程放入 AOSP 树并在 product mk 中加入对应模块名。
  • 行为
    :主界面一个按钮「启动 SecondActivity」;点击即 startActivity(new Intent(MainActivity.this, SecondActivity.class))

编译与安装(推荐:在仓库内用 Gradle,无需 AOSP 树):

进入 startactivitydemo 工程目录后执行:

./gradlew assembleDebugadb install -r app/build/outputs/apk/debug/app-debug.apk

(若目录内暂无 gradlew,可先执行 gradle wrapper 或使用 Android Studio 打开 startactivitydemo 工程后构建。)

操作步骤(照着做即可)

步骤
你执行
预期结果(验证点)
1
设备上打开 StartActivity 示例
看到按钮「启动 SecondActivity」
2
终端执行:adb logcat -s ActivityTaskManager
清空或保持运行,准备抓 log
3
点击 「启动 SecondActivity」
设备跳转到 SecondActivity 界面
4
看终端 log
出现 ATMS/ActivityStarter 相关 start 输出 → 请求已进 ATMS
5
另开终端:adb shell dumpsys activity activities
输出里能搜到 SecondActivity 或 com.example.android.startactivitydemo → 目标已入栈

真实日志片段(步骤 4 可能看到的)

点击按钮后,logcat 中可能出现类似输出(具体行因版本/DEBUG 开关略有差异):

ActivityTaskManager: startActivity: callingPackage=com.example.android.startactivitydemo ...ActivityTaskManager: ... (ActivityStarter / startActivityAsUser 等相关行)

若开启 DEBUG_ACTIVITY_STARTS,会有更细的 start 日志。

真实 dumpsys 片段(步骤 5 可能看到的)

在 dumpsys activity activities 输出中搜索 SecondActivity,可能看到类似:

* Task id 123  * ActivityRecord{... com.example.android.startactivitydemo/.SecondActivity ...}

说明该 Activity 已在栈中,可继续用 top-resumed / visible 看是否已是前台。

常用命令(复现时直接用)

adb logcat -s ActivityTaskManageradb logcat | grep -E "ActivityTaskManager|ActivityStarter|ActivityStartController"adb shell dumpsys activity activitiesadb shell dumpsys activity top-resumedadb shell dumpsys activity visible

六、方法速查(仅本篇涉及)

上面堆栈涉及的主要类与方法,下表速查。

方法
说明
Activity
startActivity、startActivityForResult
App 侧入口;-1 表示不关心结果
Instrumentation
execStartActivity
封装 Binder 调用 ATMS,返回后 checkStartActivityResult
ActivityTaskManager
getService().startActivity
获取 IActivityTaskManager 并发起 Binder
ActivityTaskManagerService
startActivity、startActivityAsUser
ATMS 入口;校验后 obtainStarter
ActivityStartController
obtainStarter(…).execute()
链式设参,进入 ActivityStarter

七、这套方法能复用在哪里

适用场景
不适用场景
排查「点了没反应」:确认请求是否已进 ATMS、目标是否入栈
分析 ANR 根因(需看主线程栈、binder 阻塞等)
区分「接单」与「已创建窗口」,避免误判
分析界面卡顿、掉帧(需看 Choreographer、SurfaceFlinger)
用 logcat + dumpsys 做启动链路上的「断点」验证
多进程/多 App 通信细节(需结合后续 Binder、事务下发篇)

八、下一步可以怎么做

  • 继续排查
    :若已确认请求进 ATMS、目标已入栈,但界面仍不出现,可看 第 2 篇:AMS/ATMS 如何决定能不能启动:该篇包含「能不能启动」的决策主干,以及决策通过后 ClientLifecycleManager.scheduleTransaction 的触发时机;再结合 dumpsys activity activities 看目标 Activity 状态。
  • 扩展观察
    :用 PendingIntent.send 触发启动,抓 log 对比:应走 ATMS.startActivityIntentSender,不经过当前进程的 Instrumentation.execStartActivity
  • 若你遇到「startActivity 没报错但界面不出」的同类问题,可按本文步骤先确认「进 ATMS + 入栈」再往后续链路上追;有具体日志/场景也可以按项目规范提 issue 或交流。

Android 14→15→16:这个环节变化点

  • 决策点变更
    :startActivity 入口仍为 Instrumentation → ATMS;PendingIntent 仍走 ATMS.startActivityIntentSender。若后续版本将「启动校验」前移到其他服务(如 PermissionController),以该版本 release note 为准。
  • 关键类/接口变更
    ActivityTaskManagerServiceActivityStarterIActivityTaskManager 在本环节为主入口,类名未变;若 AIDL 增删方法,需对照 IActivityTaskManager.aidl
  • 观测点变更
    dumpsys activity activitiesdumpsys activity intents 输出格式可能随版本微调;log tag 仍以 ActivityTaskManagerActivityStarter 为主。新版本若有启动 trace tag,以 systrace/perfetto 文档为准。

本文由 Jinno2025 原创,转载请注明出处。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 第 1 篇:App 发起启动

评论 抢沙发

6 + 4 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮