Android12应⽤启动流程分析
最近因为⼀些业务上的需求,需要梳理 Android 应⽤的启动链路,从中寻⼀些稳定的锚点来实现⼀些特殊的功能。本⽂即为对应⽤端启动全过程的⼀次代码分析记录。
注: 本⽂所分析的代码基于 AOSP android_12.0.0_r14
前⾔
之前的⽂章介绍过 ,从 init 进程开始,⼀直到 zygote 和 system_server,有助于我们去理解 Android 和 Linux 之间的异同。不过,⽤户和开发者最直观的感知是 UI、Framework 和四⼤组件,这些组件虽然⼤部分由 Java 代码构成,但对其分析的流程也是类似的,核⼼在于识别出跨进程的 RPC 调⽤,以及接⼝和继承引出的多态调⽤。
应⽤端
做过应⽤开发的对下⾯这句应该不会陌⽣:
context.startActivity(new Intent(context, SomeActivity.class));
这经常⽤来启动⼀个新的界⾯(Activity),可以是当前应⽤的,也可以是其他应⽤的:
Intent intent =new Intent();
intent.setComponent(new ComponentName("com.android.settings","com.android.settings.DeviceAdminSettings"));
context.startActivity(intent);
其中Context.startActivity是个虚函数,Activity 本⾝也是 Context 的⼦类,也实现了该⽅法。
Activity
在 frameworks/base/core/java/android/app/Activity.java 中调⽤路径如下:
startActivity(intent)
startActivity(intent, null)
startActivityForResult(intent, -1)
startActivityForResult(intent, -1, null)
关键代码:
public void startActivityForResult(@RequiresPermission Intent intent,int requestCode,@Nullable Bundle options){
// ...
Instrumentation.ActivityResult ar = StartActivity(this, ApplicationThread(), mToken,this, intent, requestCode, optio ns);
if(ar !=null){
mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
}
最终调⽤了 Instrumentation 的 execStartActivity。当然,启动应⽤的⽅法有很多,⽐如:
startActivity[ForResult] - 开发者所能接触到的接⼝,启动⼀个应⽤(Activity),可以选择⼀个回调接收启动的结果;
startActivityAsUser[ForResult] - 以指定⽤户的⾝份启动应⽤,这是个隐藏接⼝,只对预装的应⽤开放;
startActivityAsCaller[ForResult] - 以调⽤者(即启动本当前 Activity 的 APP)的⾝份启动应⽤,也是个隐藏接⼝,主要⽤于resolver 和 chooser Activity;
这些接⼝的实现都和上⾯代码类似,即最终都会调⽤到 Instrumentation 的接⼝。
Instrumentation
Instrumentation 类主要作⽤是实现代码追踪的⼀个收⼝,当启⽤跟踪时,该类会在 APP 代码之前被实例化,允许⽤户监控系统与应⽤之间的所有交互。代码追踪的配置见 l 的 instrumentation 参数。
execStartActivity 主要有两个作⽤:
1. 更新所有激活的 ActivityMonitor 对象,调⽤它们的 onStartActivity 回调以及更新对应的计数信息;
2. 将当前调⽤分发到 system activity manager 中;
简略的伪代码如下:
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent,int requestCode, Bundle options){
// 1. 更新 ActivityMonitor
for(int i =0; i < mActivityMonitors.size(); i++){
ActivityMonitor am = (i);
}
// 2. 调⽤ System Activity Manager
int result = Service().startActivity();
checkStartActivityResult(result, intent);
}
在代码注释中提到我们可以覆写此⽅法来观察 APP 启动新 Activity 的事件,并且可以修改启动 Activity 的⾏为和返回。许多插件化框架就是通过修改此⽅法来实现 Activity 的拦截。
ActivityTaskManager
由于我们关⼼的是实际的启动链路,因此暂时忽略监控相关的代码,直接进⼊到 ActivityTaskManager (简称 ATM)。其 getService 返回的实际上是:
final IBinder b = Service(Context.ACTIVITY_TASK_SERVICE);// activity_task
return IActivityTaskManager.Stub.asInterface(b);
是这⾥是个常见的远程调⽤模式:
// 1. 获取原始的IBinder对象
IBinder b = Service("service_name");
// 2. 转换为 Service 的 RPC 接⼝
IXXInterface in = IXXInterface.Stub.asInterface(b);
所以返回的是⼀个类型为IActivityTaskManager的对象,这其实是⼀个 Service,即 activity_task,其接⼝为:
package;
/**
* System private API for talking with the activity task manager that handles how activities are
* managed on screen.
*
* {@hide}
*/
public interface IActivityTaskManager extends IInterface
{
/** Default implementation for IActivityTaskManager. */
public static class Default implements IActivityTaskManager
{
//...
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends Binder implements IActivityTaskManager
{
//...
}
public static final String DESCRIPTOR ="android.app.IActivityTaskManager";
public int startActivity(...);
}
这个类是⾃动⽣成的,即使⽤ AIDL ⽣成的 RPC 接⼝,细节可以参考 ,HIDL 的实现和 AIDL 类似,区别在于 HIDL ⾯向
Hardware,AIDL ⾯向 Application。
其定义⽂件为: frameworks/base/core/java/android/app/IActivityTaskManager.aidl:
interface IActivityTaskManager {
int startActivity(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in Intent intent, in String resolvedType,
in IBinder resultTo, in String resultWho,int requestCode,
int flags, in ProfilerInfo profilerInfo, in Bundle options);
// ...
}
既然到了 AIDL,那在 APP 进程中也就⾛到头了,下⼀步需要转换视⾓,从 RPC 的另⼀端继续分析。
服务端
根据 AIDL 的原理,RPC 的另⼀端需要实现 IActivityTaskManager 接⼝,⼀般来说是要继承 IActivityTaskManager.Stub,搜索可以发现这个类为 ActivityTaskManagerService。
ActivityTaskManagerService
该类在 AOSP 中的路径为: frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java,看名称猜测这是⼀个系统服务。笔者在之前的⽂章() 中介绍了从 init 到 zygote 到 system_server 的⼀套流程,⽽这个 ActivityTaskManagerService 正好也是在startBootstrapServices 中启动的其中⼀个服务,代码⽚段如下:
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t){
// ...
// Activity manager runs the show.
// TODO: Might need to move after migration to WM.
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
mWindowManagerGlobalLock = GlobalLock();
// ...
}
随之启动的还有 ActivityManagerService。
在旧版本中实际上是在 ActivityManagerNative 中调⽤ ActivityManagerService,不过新版本已经将其 startActivity 标记为过时了。
回到代码,ActivityTaskManagerService 的 startActivity 调⽤经过了以下链路:
startActivity
startActivityAsUser(…, CallingUserId())
startActivityAsUser(…, validateIncomingUser=true)
后者调⽤的代码如下:
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho,int requestCode,int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions,int userId,boolean validateIncomingUser){
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId =getActivityStartController().checkTargetUser(userId, validateIncomingUser,
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent,"startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.
setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
通过⼀系列 builder 获取 starter 并设置对应参数,最终执⾏ execute。
ActivityStarter
obtainStarter 返回的类型是 ActivityStarter, 该类定义在: frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java,其execute 函数的作⽤就是根据前⾯提供的的请求参数并开始启动应⽤。
关键调⽤路径:
exexute: 处理 Activity 启动请求的接⼝;
executeRequest: 执⾏⼀系列权限检查,对于合法的请求才继续;
startActivityUnchecked: 调⽤该⽅法时表⽰⼤部分初步的权限检查已经完成,执⾏ Trace,以及异常处理;
startActivityInner: 启动 Activity,并更新全局的 task 栈帧信息;
在 Android 中系统维护了所有应⽤的状态信息,因此⽤户才可以在不同应⽤中⽆缝切换和返回。同时
制作android软件流程在处理启动应⽤请求的时候还需要进⾏额外的判断,⽐如当前栈顶是否是同样的 Activity,如果是则根据设置决定是否重复启动等等。
忽略 ActivityStack、WindowContainer 等任务窗⼝管理的代码,只关注其中真正启动应⽤相关的:
mTargetRootTask.startActivityLocked()
mTargetRootTask 是 Task 类型, Task 是 WindowContainer 的⼦类,⽤于管理和表⽰属于同⼀栈帧的所有 activity,其中每个activity 使⽤ ActivityRecord 表⽰。mRootWindowContainer 是 RootWindowContainer 类型,也是 WindowContainer 的⼦类,特别代表根窗⼝。
startActivityLocked ⽅法的主要作⽤是判断当前 activity 是否可见以及是否需要为其新建 Task,根据不同情况将 ActivityRecord 加⼊到对应的 Task 栈顶中。
resumeFocusedTasksTopActivities ⽅法正如其名字⼀样,将所有聚焦的 Task 的所有 Activity 恢复运⾏,因为有些刚加⼊的 Activity 是处于暂停状态的。
Task
Task 从宏观来说是⼀系列 Activity 界⾯的集合,根据先进后出的栈结构进⾏组织。注意 task 和 进程/线程是不同的概念,⼤多数 task 可以认为是从桌⾯点击某个应⽤开始启动,随着不断点击深⼊打开其他界⾯,使对应的 Activity ⼊栈,在点击返回时将当前 Activity 出栈并销毁,如下所⽰:
同时,整个 Task 本⾝也可以被移动当后台,⽐如当⽤户点击 HOME 键时,此时 Task 中的所有 Activity 都会停⽌。Task 中的 Activity 可以同属于⼀个 APP,也可能属于不同的 APP 和进程。在 Android R (11) 以及 Android S(12) beta 的代码中(甚⾄更早的代码之前),Task 类实际上是 ActivityStack,可以认为 Task 就是 ActivityStack,ActivityStack 就是 Task。关于 Task 的更多介绍,可以阅读官⽅的⽂档: 。
resumeFocusedTasksTopActivities 中主要是判断传⼊的 targetRootTask 是否等于当前栈顶的 Task,不管是否相等,后续都是调⽤栈顶 Task 的 resumeTopActivityUncheckedLocked ⽅法。
其中对 Task 进⾏了⼀次判断,如果是⾮叶⼦结点,则对所有⼦结点递归调⽤本⽅法,递归结束(即到达叶⼦结点)后才继续实际流程。再次执⾏了⼀系列的判断,⽐如查当前栈帧中最接近栈顶且可显⽰和可聚焦的 Activity (next),判断其暂停状态以及所属⽤户的权限等,然后进⼊到 resumeTopActivityInnerLocked。
该⽅法中主要是寻合适的 ActivityRecord、设置 resume 条件、准备启动⽬标 Activity。最后,来到了我们的关键逻辑:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论