Android App启动流程深度解析(一):从Activity.startActivity开始
前言
在Android应用开发中,启动流程是最基础也是最重要的机制之一。作为一名Android开发者,理解应用启动的完整流程对于性能优化、问题排查和架构设计都至关重要。本系列文章将从最上层的Activity.startActivity()
方法开始,自上而下深入分析Android应用启动的完整流程。
版本说明
本文分析的代码基于Android 10(API 29)及以上版本。在Android 10中,Google对Activity管理架构进行了重大调整:
- Android 9及之前:所有Activity相关功能由
ActivityManagerService
(AMS)统一管理 - Android 10及之后:将Activity和Task管理功能拆分到新的
ActivityTaskManagerService
(ATMS),AMS保留其他核心功能
这个变更有以下背景:
- 解耦Activity管理与系统其他核心功能
- 为多窗口、自由形态窗口等新特性提供更好的支持
- 改善系统服务的模块化程度
从Activity.startActivity开始
让我们从最常见的场景出发——一个Activity启动另一个Activity。开发者最熟悉的调用方式就是startActivity()
方法。
Activity.startActivity()
@Override
public void startActivity(Intent intent) {this.startActivity(intent, null);
}
这是Activity
类中最简单的startActivity
重载方法。可以看到它调用了另一个重载方法,并传入了一个null的Bundle
参数。
Activity.startActivity(Intent, Bundle)
public void startActivity(Intent intent, @Nullable Bundle options) {if (options != null) {startActivityForResult(intent, -1, options);} else {startActivityForResult(intent, -1);}
}
这个方法检查是否有附加的options Bundle,然后调用startActivityForResult()
方法。注意这里传入的requestCode是-1,表示我们不需要返回结果。
Activity.startActivityForResult()
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {// 检查是否有父Activityif (mParent == null) {options = transferSpringboardActivityOptions(options);// 关键调用Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {mStartedActivity = true;}cancelInputsAndStartExitTransition(options);} else {// 如果有父Activity,则通过父Activity启动if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {mParent.startActivityFromChild(this, intent, requestCode);}}
}
这个方法有几个关键点:
- 首先检查是否有父Activity,如果没有则继续流程,否则通过父Activity启动
- 使用
Instrumentation
的execStartActivity
方法执行实际的启动操作 - 如果有返回结果,则通过
ActivityThread
发送结果 - 处理Activity过渡动画
Instrumentation.execStartActivity()
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {// 获取IApplicationThread对象IApplicationThread whoThread = (IApplicationThread) contextThread;// 记录来源Activityif (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess(who);// 关键调用:通过ActivityTaskManager启动Activityint result = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);// 检查启动结果checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;
}
这个方法做了以下几件事:
- 处理ActivityMonitor(用于测试)
- 准备Intent数据
- 通过
ActivityTaskManager.getService()
获取AMS的代理对象,调用startActivity
方法 - 检查启动结果
ActivityTaskManager.getService()
public static IActivityTaskManager getService() {return IActivityTaskManagerSingleton.get();
}private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =new Singleton<IActivityTaskManager>() {@Overrideprotected IActivityTaskManager create() {// 获取ActivityTaskManagerService的代理对象final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);return IActivityTaskManager.Stub.asInterface(b);}};
这里通过Binder机制获取了系统服务ActivityTaskManagerService
的代理对象。ATMS是Android 10之后从AMS中拆分出来的专门管理Activity和Task的服务。
checkStartActivityResult()
public static void checkStartActivityResult(int res, Object intent) {switch (res) {case ActivityManager.START_INTENT_NOT_RESOLVED:case ActivityManager.START_CLASS_NOT_FOUND:throw new ActivityNotFoundException("Unable to find explicit activity class "+ ((Intent)intent).getComponent().toShortString()+ "; have you declared this activity in your AndroidManifest.xml?");case ActivityManager.START_PERMISSION_DENIED:throw new SecurityException("Not allowed to start activity "+ ((Intent)intent).getComponent().toShortString());// 其他错误处理...}
}
这个方法将ATMS返回的结果转换为相应的异常,开发者常见的"Activity未在Manifest中声明"的错误就是在这里抛出的。
流程概览
到目前为止,我们看到的调用流程如下:
Activity.startActivity()
Activity.startActivity(Intent, Bundle)
Activity.startActivityForResult()
Instrumentation.execStartActivity()
ActivityTaskManager.getService().startActivity()
这个流程已经从应用进程进入了系统进程(system_server),后续的处理将在ATMS中进行。
为什么需要Instrumentation?
你可能注意到在流程中有一个Instrumentation
类参与其中。Instrumentation是Android测试框架的核心部分,但它也参与正常的Activity启动流程。它的主要作用有:
- 提供一种监控系统与应用交互的机制
- 在测试中可以替换组件行为
- 在正常运行时作为Activity生命周期回调的中间层
小结
本文从最常用的Activity.startActivity()
方法开始,逐步深入分析了Android应用启动的前半段流程。我们了解到:
- 启动请求最终通过
Instrumentation
转发到系统服务 - 通过Binder机制与系统服务
ActivityTaskManagerService
交互 - 基本的错误检查和处理机制
附:关键差异对比表
组件/版本 | Android 9及之前 | Android 10及之后 |
---|---|---|
核心服务 | ActivityManagerService (AMS) | ActivityTaskManagerService (ATMS) |
获取服务方式 | ActivityManager.getService() | ActivityTaskManager.getService() |
管理范围 | 包含Activity管理在内的所有功能 | 专注Activity和Task管理 |
Binder接口 | IActivityManager | IActivityTaskManager |
兼容性说明
虽然架构发生了变化,但上层API保持了兼容:
// 这两种写法在Android 10+上效果相同,但后者是推荐的新方式
startActivity(intent); // 仍然可用
ActivityTaskManager.getService().startActivity(...); // 新方式
系统通过兼容层处理了API差异,因此开发者无需修改现有代码。
为什么需要拆分ATMS?
在Android 10的架构变更中,拆分ATMS的主要考虑包括:
-
职责单一化:
- AMS原本承担了太多职责(内存管理、进程管理、Activity管理等)
- 拆分后ATMS专注于Activity和Task管理
-
多窗口支持:
- 新的多窗口模式需要更复杂的Activity栈管理
- 独立服务可以更灵活地实现这些功能
-
性能优化:
- 减少AMS的锁竞争
- 并行处理Activity相关操作
代码路径差异
在分析启动流程时,需要注意不同版本的代码路径差异:
Android 9及之前:
// 老版本通过AMS启动Activity
ActivityManager.getService().startActivity(...)
Android 10及之后:
// 新版本通过ATMS启动Activity
ActivityTaskManager.getService().startActivity(...)