android1300_r83_0">Activity启动流程(基于android-13.0.0_r83)
整体流程
启动方式
Activity主要有三种方式
- 从 Launcher 桌面上点击 App 图标启动一个App。
- App 启动后,按 Home 键退回到 Launcher 界面,再点击 App 图标。
- 同个应用内启动,如从 Activity1 跳转到 Activity2。
启动过程涉及到的进程
- 要启动的Activity所在App 进程
- SystemServer进程
- Zygote
- 启动目标Activity的进程,如Launcher
Activity启动过程跟系统交互主要是通过Binder,其中主要涉及两个server,一个是SystemServer中注册的ActivityTaskManagerService,另外一个是app进程中的ApplicationThread。
ActivityTaskManagerService
- ActivityTaskManagerService(简称 ATMS)是 Android 系统中负责管理 Activity 和 Task 的核心服务之一,运行在system_server 进程中。
- 从 Android 10(Q)开始,Google 对 Activity 和 Task 的管理机制进行了重构,将原本在 ActivityManagerService(AMS)中的部分功能拆分到了 ActivityTaskManagerService 中。
- 负责管理 Activity 的生命周期、任务栈(Task)、多窗口模式(如分屏、自由窗口)等。
ATMS 的作用
- Activity 生命周期管理: 负责 Activity 的启动、暂停、恢复、销毁等生命周期回调。
- Task 管理: 管理任务栈(Task),包括 Task 的创建、销毁、重新排序等。
- 多窗口模式: 支持分屏、画中画、自由窗口等多窗口模式的实现。
- 启动模式(Launch Mode): 处理 Activity 的启动模式(如 standard、singleTop、singleTask、singleInstance)。
- 任务栈导航: 管理任务栈的导航行为(如返回栈、最近任务列表)。
- 与 WindowManagerService 协作: 与 WindowManagerService(WMS)协作,管理 Activity 的窗口显示。
ATMS 的相关架构
- ActivityManagerService(AMS): 负责进程管理、内存管理等,与 ATMS 协作完成 Activity 的管理。
- WindowManagerService(WMS): 负责窗口管理,与 ATMS 协作完成 Activity 的显示。
- ActivityStack: 表示一个任务栈(Task),管理栈中的 Activity。
- ActivityRecord: 表示一个 Activity 实例,包含 Activity 的状态信息。
ATMS 的核心功能
- Activity 生命周期管理
ATMS 负责处理 Activity 的生命周期回调,当应用启动一个 Activity 时,ATMS 会调用相应的生命周期方法,并确保 Activity 的状态正确切换。包括:
- onCreate()
- onStart()
- onResume()
- onPause()
- onStop()
- onDestroy()
- Task 管理
Task 是一个 Activity 的集合,通常表示一个用户任务(如打开一个应用)。ATMS 负责管理 Task 的创建、销毁和重新排序。
- 当用户点击桌面图标启动应用时,ATMS 会创建一个新的 Task。
- 当用户按下返回键时,ATMS 会销毁当前 Activity 并返回到上一个 Activity。
- 多窗口模式
ATMS 支持多种多窗口模式, ATMS 负责管理多窗口模式下 Activity 的布局和生命周期。包括:
- 分屏模式(Split-screen): 两个应用共享屏幕。
- 画中画模式(Picture-in-Picture): 视频播放时以小窗口形式显示。
- 自由窗口模式(Freeform): 类似于桌面操作系统的窗口模式。
-
启动模式(Launch Mode)
-
任务栈导航
ATMS 管理任务栈的导航行为,包括:
- 返回栈(Back Stack): 当用户按下返回键时,ATMS 会从返回栈中弹出 Activity。
- 最近任务列表(Recent Tasks): ATMS 负责维护最近任务列表,用户可以快速切换任务。
ATMS 的实现
ATMS是通过AIDL实现的
ApplicationThread
- ApplicationThread 是 ActivityThread 的内部类,扮演着应用进程与系统服务(如 ActivityManagerService 和 ActivityTaskManagerService)之间的桥梁角色。
- ApplicationThread 是一个 Binder 对象,负责接收系统服务的指令并转发给应用进程的主线程(即 ActivityThread),从而实现对应用生命周期、Activity 生命周期等的管理。
ApplicationThread 的作用
- 接收系统服务的指令: 接收来自 ActivityManagerService(AMS)和 ActivityTaskManagerService(ATMS)的指令,例如启动 Activity、启动 Service、绑定 Service、处理广播等。
- 转发指令到主线程: 将系统服务的指令转发到应用的主线程(即 ActivityThread),确保这些操作在主线程中执行。
- 与应用组件交互: 与应用的 Activity、Service、BroadcastReceiver 等组件交互,触发它们的生命周期方法(如 onCreate()、onStart()、onResume() 等)。
ApplicationThread 的核心方法
这些方法都是由系统服务(如 AMS 或 ATMS)调用,然后通过 Binder 机制传递到应用进程的 ApplicationThread,最终由 ActivityThread 在主线程中执行。
- 启动 Activity: scheduleLaunchActivity()
- 启动 Service: scheduleCreateService()
- 绑定 Service: scheduleBindService()
- 处理广播: scheduleReceiver()
- 暂停 Activity: schedulePauseActivity()
- 销毁 Activity: scheduleDestroyActivity()
ApplicationThread 的实现
ApplicationThread是基于AIDL实现
ActivityTaskManagerService和ApplicationThread调用关系
Launcher 界面中启动Activity的流程
流程
源码分析
- 点击桌面图标会触发ItemClickHandler.java的onClick()。
/*
* @param v 被点击的视图对象(如应用图标、文件夹图标等)
**/
//packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java
private static void onClick(View v) {...if (v.getWindowToken() == null) return;//Launcher 是 Launcher 应用的主 Activity,负责管理主屏幕、应用图标、小部件等。Launcher launcher = Launcher.getLauncher(v.getContext());if (!launcher.getWorkspace().isFinishedSwitchingState()) return;//Launcher 中的每个视图(如应用图标、文件夹图标等)都关联了一个 ItemInfo 对象,用于存储该视图的元数据(如应用包名、组件名、位置信息等)。Object tag = v.getTag();//点击的是应用图标if (tag instanceof WorkspaceItemInfo) {onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);} else if (tag instanceof FolderInfo) {//点击文件夹图标if (v instanceof FolderIcon) {onClickFolderIcon(v);}} else if (tag instanceof AppInfo) {//快捷方式startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);} else if (tag instanceof LauncherAppWidgetInfo) {//点击的是小部件if (v instanceof PendingAppWidgetHostView) {onClickPendingWidget((PendingAppWidgetHostView) v, launcher);}} else if (tag instanceof ItemClickProxy) {((ItemClickProxy) tag).onItemClicked(v);}}
点击应用图标执行下面方法
/*** Event handler for an app shortcut click.** @param v The view that was clicked. Must be a tagged with a {@link WorkspaceItemInfo}.*/public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {...// Start activities 启动activitystartAppShortcutOrInfoActivity(v, shortcut, launcher);}
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {...Intent intent;...//从 WorkspaceItemInfo 中获取 Intent,用于启动应用或显示应用信息。if (item instanceof WorkspaceItemInfo) {WorkspaceItemInfo si = (WorkspaceItemInfo) item;if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)&& Intent.ACTION_VIEW.equals(intent.getAction())) {// make a copy of the intent that has the package set to null// we do this because the platform sometimes disables instant// apps temporarily (triggered by the user) and fallbacks to the// web ui. This only works though if the package isn't setintent = new Intent(intent);intent.setPackage(null);}if ((si.options & WorkspaceItemInfo.FLAG_START_FOR_RESULT) != 0) {launcher.startActivityForResult(item.getIntent(), 0);InstanceId instanceId = new InstanceIdSequence().newInstanceId();launcher.logAppLaunch(launcher.getStatsLogManager(), item, instanceId);return;}}...// 启动普通应用launcher.startActivitySafely(v, intent, item);}
- 触发Launcher.java的startActivitySafely
//packages/apps/Launcher3/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java@Overridepublic boolean startActivitySafely(View v, Intent intent, ItemInfo item) {// Only pause is taskbar controller is not presentmHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);//调用父类即Launcher.javaboolean started = super.startActivitySafely(v, intent, item);if (getTaskbarUIController() == null && !started) {mHotseatPredictionController.setPauseUIUpdate(false);}return started;}
//packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@Overridepublic boolean startActivitySafely(View v, Intent intent, ItemInfo item) {//检查 Launcher 是否已经处于 resumed 状态(即完全恢复并可见)。//如果 Launcher 未完全恢复,直接启动 Activity 可能会导致窗口管理器(WM)的启动动画被破坏。if (!hasBeenResumed()) {//如果 Launcher 未完全恢复,则延迟启动 Activity,直到 Launcher 下次恢复。//使用 addOnResumeCallback 方法注册一个回调,在 Launcher 恢复时执行 startActivitySafely。addOnResumeCallback(() -> startActivitySafely(v, intent, item));if (mOnDeferredActivityLaunchCallback != null) {mOnDeferredActivityLaunchCallback.run();mOnDeferredActivityLaunchCallback = null;}return true;}//调用父类ActivityContext的 startActivitySafely 方法boolean success = super.startActivitySafely(v, intent, item);//BubbleTextView 是 Launcher 中用于显示应用图标和文件夹图标的视图。//如果成功启动 Activity,并且触发视图是 BubbleTextView,则设置其按压状态为 true。if (success && v instanceof BubbleTextView) { BubbleTextView btv = (BubbleTextView) v;btv.setStayPressed(true);//使用 addOnResumeCallback 方法注册一个回调,在 Launcher 恢复时将按压状态重置为 false。addOnResumeCallback(() -> btv.setStayPressed(false));}return success;}
- 触发ActivityContext.java的startActivitySafely
主要包含以下几个步骤
- 主线程检查:确保方法在主线程中调用。
- 安全模式检查:在安全模式下阻止非系统应用的启动。
- 快捷方式启动:支持深度快捷方式的启动。
- 启动选项:根据视图和 ItemInfo 准备启动选项。
- 用户句柄:支持跨用户启动 Activity。
- 日志记录:记录应用启动日志。
- 异常处理:捕获并处理启动过程中的异常。
//packages/apps/Launcher3/src/com/android/launcher3/views/ActivityContext.java/*** 安全地启动一个 Activity,并处理一些特殊情况(如安全模式、快捷方式启动、跨用户启动等)* @param v 触发启动操作的视图(如应用图标)。* @param intent 要启动的 Activity 的 Intent。* @param item 与视图关联的 ItemInfo 对象(如 WorkspaceItemInfo),可以为 null。* @return RunnableList 用于监听动画结束的回调列表。如果启动失败,则返回 null。*/default RunnableList startActivitySafely(View v, Intent intent, @Nullable ItemInfo item) {//确保该方法在主线程(UI 线程)中调用,避免在后台线程中启动 Activity。Preconditions.assertUIThread();Context context = (Context) this;//检查安全模式//如果设备处于安全模式,并且目标应用不是系统应用,则阻止启动并显示提示信息。if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();return null;}//如果 ItemInfo 是深度快捷方式(ITEM_TYPE_DEEP_SHORTCUT),并且不是占位符(isPromise() 返回 false),则标记为快捷方式启动。boolean isShortcut = (item instanceof WorkspaceItemInfo)&& item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT&& !((WorkspaceItemInfo) item).isPromise();//GO_DISABLE_WIDGETS:如果为 true,则禁用快捷方式启动,并返回 null。if (isShortcut && GO_DISABLE_WIDGETS) {return null;}//准备启动选项//如果视图 v 为 null,则调用 makeDefaultActivityOptions 方法创建默认启动选项。ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item): makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);//设置用户句柄UserHandle user = item == null ? null : item.user;Bundle optsBundle = options.toBundle();// 准备 Intent//设置 Intent 的标志位,确保目标 Activity 在新的任务栈中启动。intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);if (v != null) {//用于动画过渡效果。intent.setSourceBounds(Utilities.getViewBounds(v));}//启动Activitytry {//快捷方式启动if (isShortcut) {String id = ((WorkspaceItemInfo) item).getDeepShortcutId();String packageName = intent.getPackage();((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, user);} else if (user == null || user.equals(Process.myUserHandle())) {// Could be launching some bookkeeping activitycontext.startActivity(intent, optsBundle);//普通启动} else {//如果用户句柄不是当前用户,跨用户启动 Activity。context.getSystemService(LauncherApps.class).startMainActivity(intent.getComponent(), user, intent.getSourceBounds(), optsBundle);}...return options.onEndCallback;} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {...}return null;}
Activity启动流程
- 执行Activity的startActivity()
//frameworks/base/core/java/android/app/Activity.java@Overridepublic void startActivity(Intent intent, @Nullable Bundle options) {getAutofillClientController().onStartActivity(intent, mIntent);if (options != null) {startActivityForResult(intent, -1, options);} else {startActivityForResult(intent, -1);}}
startActivityForResult主要包含以下几个步骤
- 启动目标 Activity:
- 通过 Instrumentation.execStartActivity 方法启动目标 Activity。
- 处理返回结果:
如果目标 Activity 立即返回结果,则通过 mMainThread.sendActivityResult 方法将结果发送给当前 Activity。 - 标记 Activity 已启动:
如果 requestCode 大于等于 0,则标记当前 Activity 已启动目标 Activity。 - 取消输入并启动退出过渡:
取消当前 Activity 的输入事件,并启动退出过渡动画。 - 支持子 Activity:
如果当前 Activity 有父 Activity,则通过父 Activity 启动目标 Activity。
/** @param intent 要启动的 Activity 的 Intent。* @param requestCode 请求代码,用于标识启动请求。当目标 Activity 返回结果时,该代码会传递给 onActivityResult 方法。* @param options 启动选项(如动画、过渡效果等),可以为 null。* @see #startActivity*/public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {// 检查是否有父 Activityif (mParent == null) {//将启动选项转换为适合当前 Activity 的格式。例如,处理与启动动画相关的选项。options = transferSpringboardActivityOptions(options);//通过 Instrumentation 执行实际的 Activity 启动操作。//参数包括当前 Activity 的上下文、应用线程、Activity 的 IBinder 令牌、目标 Intent、请求代码和启动选项。Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);//如果目标 Activity 立即返回结果(如 RESULT_CANCELED),则通过主线程将结果发送给当前 Activity。//结果会传递给 onActivityResult 方法。if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {// 如果 requestCode 大于等于 0,则标记当前 Activity 已启动目标 Activity。// 这可以避免在目标 Activity 返回结果之前显示当前 Activity,从而减少闪烁。mStartedActivity = true;}//取消输入并启动退出过渡//取消当前 Activity 的输入事件(如键盘输入)。//启动退出过渡动画(如 Activity 切换动画)。cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {//调用父 Activity 的方法if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {mParent.startActivityFromChild(this, intent, requestCode);}}}
Instrumentation阶段
Instrumentation 用于监控应用程序与系统的交互。它在应用程序的整个生命周期中扮演着重要角色,尤其是在 Activity 的启动、生命周期回调、以及测试框架中。
Instrumentation 的作用
- 监控应用程序的生命周期:如 Activity 的启动、停止、销毁等。
- 注入测试代码:在 Android 测试框架中,Instrumentation 用于注入测试代码,监控应用程序的行为。
- 提供上下文和环境:为应用程序提供测试所需的上下文和环境。
- 处理系统交互:如启动 Activity、发送广播、处理 Intent 等。
Instrumentation 的核心方法
- execStartActivity 启动一个 Activity。
- callActivityOnCreate 调用 Activity 的 onCreate 方法。
- callActivityOnResume 调用 Activity 的 onResume 方法。
- newActivity 创建一个新的 Activity 实例。
- sendKeySync 同步发送一个按键事件。
- runOnMainSync 在主线程中同步执行一个 Runnable。
execStartActivity 执行启动 Activity
execStartActivity 主要包括以下几个步骤
- IApplicationThread:用于与系统服务通信。
- Referrer:处理 Activity 的来源信息。
- ActivityMonitor:监控和拦截 Activity 启动。
- Intent 准备:确保 Intent 可以跨进程传递。
- ActivityTaskManager:与系统服务交互,启动 Activity。
- 异常处理:捕获并处理启动过程中的异常。
//frameworks/base/core/java/android/app/Instrumentation.java/** @param who 启动 Activity 的上下文(通常是当前 Activity)。* @param contextThread 应用的主线程(IApplicationThread 类型)。* @param token 当前 Activity 的 IBinder 令牌。* @param target 目标 Activity(可以为 null)。* @param intent 要启动的 Activity 的 Intent。* @param requestCode 请求代码(用于 startActivityForResult)。* @param options 启动选项(如动画、过渡效果等)。** @return 返回一个 ActivityResult 对象,包含目标 Activity 的结果(如结果代码和返回数据)。如果启动失败,则返回 null。* {@hide}*/@UnsupportedAppUsagepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {//获取 IApplicationThread,表示应用的主线程,用于与系统服务(如 ActivityTaskManager)通信。IApplicationThread whoThread = (IApplicationThread) contextThread;//处理 Referrer,将 Referrer 添加到 Intent 的 EXTRA_REFERRER 字段中。Uri referrer = target != null ? target.onProvideReferrer() : null;if (referrer != null) {intent.putExtra(Intent.EXTRA_REFERRER, referrer);}//处理 ActivityMonitor,用于监控和拦截 Activity 启动。if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();//遍历所有的 ActivityMonitor。for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);ActivityResult result = null;//如果 ActivityMonitor 忽略特定的 Intent,则调用 onStartActivity 方法处理。if (am.ignoreMatchingSpecificIntents()) {if (options == null) {options = ActivityOptions.makeBasic().toBundle();}result = am.onStartActivity(who, intent, options);}//如果 ActivityMonitor 匹配当前的启动请求,则根据其配置决定是否拦截启动。if (result != null) {am.mHits++;return result;} else if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {//将 Intent 中的 EXTRA_STREAM 数据迁移到 ClipData 中。intent.migrateExtraStreamToClipData(who);//准备 Intent,确保它可以跨进程传递。intent.prepareToLeaveProcess(who);//启动 Activity//获取 ActivityTaskManager 的系统服务。//调用 ActivityTaskManager 的 startActivity 方法,启动目标 Activity。int result = ActivityTaskManager.getService().startActivity(whoThread,who.getOpPackageName(), who.getAttributionTag(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()), token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);//通知 Activity 启动结果。notifyStartActivityResult(result, options);//检查启动结果,如果失败则抛出异常。checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;}
execStartActivity执行后启动过程就会进入到服务端 SystemServer的 ATMS Binder 服务中去了。