前言
Activity 启动过程文章系列中,首先会先对启动流程从头到尾进行简要梳理,后续文章会对其中重要细节进行详细展开。
启动流程梳理:
- Activity 启动流程(一)—— Launcher 阶段
- Activity 启动流程(二)—— AMS 处理阶段
- Activity 启动流程(三)—— 应用程序进程启动阶段
- Activity 启动流程(四)—— ActivityThread 初始化阶段
- Activity 启动流程(五)—— Activity 启动阶段
下面开始对 Activity 启动的整个过程进行源码解析,代码基于 android-14.0.0_r9。
Activity 启动过程分为两种:
- 普通 Activity 的启动过程。
- 根 Activity 的启动过程,即第一个 Activity 的启动过程,包含普通 Activity 的启动流程。
这里讲解根 Activity 的启动过程,整个启动流程是从点击 Launcher 图标开始的。
1. Launcher 阶段
1.1 点击 Launcher icon,调用 startActivity 方法
Launcher 是一个 Activity,点击 Launcher 图标,最终调用的也是我们熟悉的 startActivity 方法。
Launcher 中应用程序的 icon 就是根 Activity 启动的入口。当点击快捷图标 icon,调用 ItemClickHandler 的 onClick 方法:
// src/com/android/launcher3/touch/ItemClickHandler.java
public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
private static void onClick(View v) {
...
Launcher launcher = Launcher.getLauncher(v.getContext());
Object tag = v.getTag();
if (tag instanceof WorkspaceItemInfo) {
...
} else if (tag instanceof FolderInfo) {
...
} else if (tag instanceof AppInfo) {
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
} else if
...
}
:: 是Java 8引入的方法引用语法,等价于v -> ItemClickHandler.onClick(v)。
BaseDraggingActivity 的 getItemOnClickListener 方法是最核心的入口点,所有继承自 BaseDraggingActivity 的 Activity(包括Launcher)都会返回 ItemClickHandler.INSTANCE 作为图标的点击监听器:
@Override
public View.OnClickListener getItemOnClickListener() {
return ItemClickHandler.INSTANCE;
}
Launcher 在创建 BubbleTextView 时调用 setOnClickListener(getItemOnClickListener()),将 ItemClickHandler.INSTANCE 设置为 BubbleTextView 的点击监听器:
public View createShortcut(@Nullable ViewGroup parent, WorkspaceItemInfo info) {
BubbleTextView favorite =
(BubbleTextView) LayoutInflater.from(parent != null ? parent.getContext() : this)
.inflate(R.layout.app_icon, parent, false);
favorite.applyFromWorkspaceItem(info);
favorite.setOnClickListener(getItemOnClickListener());
favorite.setOnFocusChangeListener(mFocusHandler);
return favorite;
}
ItemClickHandler 的点击监听器最初是在 BaseDraggingActivity 中设置的 ,通过 getItemOnClickListener 方法返回,然后在各个创建 BubbleTextView 的地方(如 Launcher.createShortcut、FolderPagedView.createNewView 等)被具体应用到图标上。
点击 icon 时,view 对应的 Tag 是 AppInfo 类型,所以会调用 startAppShortcutOrInfoActivity:
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
...
Intent intent;
if (item instanceof ItemInfoWithIcon
&& (((ItemInfoWithIcon) item).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {// app 正在安装
ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
intent = new PackageManagerHelper(launcher)
.getMarketIntent(appInfo.getTargetComponent().getPackageName());// 跳转至应用市场
} else {
// 否则直接获取 item 的 Intent(通常是启动应用的 Intent)
intent = item.getIntent();
}
...
// 最终调用 Launcher 的安全启动方法
// v: BubbleTextView 图标视图
// intent: 启动 Intent(通常是启动应用的 Intent)
// item: 项目信息(ItemInfo、AppInfo 等)
launcher.startActivitySafely(v, intent, item);
}
创建 Intent,如果应用正在安装,Intent 则指向应用市场。否则直接使用 item.getIntent(),通常是类似 Intent(ACTION_MAIN, Category.CATEGORY_LAUNCHER) 的应用主入口。
点击 icon 时,就会调用 Launcher 的 startActivitySafely 方法,三个参数分别指的是 icon、启动应用的Intent、ItemInfo:
// Launcher3/src/com/android/launcher3/Launcher.java
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
...
RunnableList result = super.startActivitySafely(v, intent, item);
...
}
接着会调用 ActivityContext 接口中的 startActivitySafely 方法,Launcher 的基类 BaseActivity 实现了 ActivityContext:
// src/com/android/launcher3/views/ActivityContext.java
default RunnableList startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
...
// 添加 NEW_TASK 标志:确保应用在新的任务栈中启动,这是 Launcher 启动应用的标准做法
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
try {
...
// 当前用户应用启动:直接使用 Context.startActivity 启动
// 适用于普通应用启动和一些内部管理 Activity
context.startActivity(intent, optsBundle);
...
}
...
}
接着调用 startActivity 方法,该方法在 Activity 中实现:
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
...
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
Activity 的 startActivity 中的 options != null,直接调用到 Launcher 的 startActivityForResult 方法:
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (requestCode != -1) {
mPendingActivityRequestCode = requestCode;
}
super.startActivityForResult(intent, requestCode, options);
}
接着调用到 Activity 的 startActivityForResult 方法:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
// 一般走这个分支
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
...
}
一般走第一个分支,大家可以研究一下什么时候 mParent 不为 null,接着会调用 Instrumentation 的 execStartActivity 方法,Instrumentation 主要用来监控应用程序与系统的交互。Activity 持有 Instrumentation 对象,该对象在 Activity 的 attach 方法中赋值。
到此,Activity 启动过程中的 Launcher 部分就已经结束了。总结一下:点击 Launcher icon,准备 Acitivity 启动所需参数,如新建启动应用的 Intent,Flag 为 Intent.FLAG_ACTIVITY_NEW_TASK,并调用了 Activity 的 startActivity 方法启动新应用进程的 Activity。
1.2 Launcher App -> ATMS
应用程序通过 Instrumentation 的 execStartActivity 方法执行启动 Activity 的流程:
@UnsupportedAppUsage
// core/java/android/app/Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String resultWho,
Intent intent, int requestCode, Bundle options, UserHandle user) {
...
try {
...
int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
requestCode, 0, null, options, user.getIdentifier());
notifyStartActivityResult(result, options);
// 检查 Activity 启动结果
checkStartActivityResult(result, intent);
}
...
}
调用 ActivityTaskManager 的 getService 方法来获取 ActivityTaskManagerService 的代理对象,接着调用它的 startActivity 方法:
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
// ACTIVITY_TASK_SERVICE = "activity_task"
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
public static final String ACTIVITY_TASK_SERVICE = "activity_task";
得到名为 activity_task 的 Service 引用,也就是 IBinder 类型的 ActivityTaskManagerService 的引用。接着将它转换为 IActivityTaskManager 类型的对象,这段代码采用的是 AIDL,IActivityTaskManager.aidl 文件路径为 core/java/android/app/IActivityTaskManager.aidl。
要实现进程间通信,服务器端(ActivityTaskManagerService)只需要继承 IActivityTaskManager.Stub 类并实现相应方法就可以了。
execStartActivity 最终调用的是 ActivityTaskManagerService 的 startActivity 方法。
ActivityTaskManagerService 继承自 IActivityTaskManager.Stub,是用于管理 Activity 及其容器(task, stacks, displays,...)的系统服务,运行在 SystemServer 进程中。