前言
在之前的启动流程分析的文章中,初步分析了AMS和PKMS,探索了一下应用启动从Zygote进程孵化到执行ActivityThread类中的main()方法,在main()方法中会去创建Application对象,并调用了其内部的onCreate()方法,也看到了后续流程去实例化首个Activity并调用执行到Activity的onCreate()方法,提到了在启动Activity的时候是需要从PKMS服务中取获取对应应用解析的Activity的信息,在PKMS的文章里面也分析了开机的时候操作系统会去扫描/data/app目录下的base.apk文件,解析我们在应用开发中对于一个app应用配置的AndroidManifest.xml文件
整个流程涉及的类和对象比较多,Activity对于Android开发来说又是非常重要的一个组件,自打我开发Android以来,就知道需要对Activity的生命周期的认知,页面栈的管理,视图的显示和销毁跟生命周期的关系,Activity跟window的关系有个非常明确的认知,结合前面的文章,接下来就继续从源码的角度去深入剖析一下我们能看到的Activity对象
startActivity
通过前面的文章分析,当执行startActivity方法后,会通过一连串的对象方法调用,执行到ActivityStarter这个关键类里面的execute()方法,先附上这段流程的调用时序图
这里可以看到,startActivity方法的执行调用会执行到ATMS服务,所以即使是我们平时开发的应用进程内部,要跳转我们自己开发的Activity也是一个跨进程通信的行为,ATMS服务是在system_server进程中,跨进程通信在Android中使用的就是binder通信
接下来进入源码阶段
从PKMS获取Activity信息
//ActivityStarter.java
class ActivityStarter {
//mRequest是Starter对象的内部属性
Request mRequest = new Request();
int excute(){
//启动Activity首先会进入这个判断,mRequest里面是没有赋值activityInfo的
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
}
//Request是Starter类里面声明的内部类
static class Request {
ActivityInfo activityInfo;
Request() {
reset();
}
void reset() {
activityInfo = null;
}
void set(Request request) {
activityInfo = request.activityInfo;
}
}
}
//ActivityStartController.java
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
//DefaultFactory.java
public ActivityStarter obtain() {
ActivityStarter starter = mStarterPool.acquire();
if (starter == null) {
starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
}
return starter;
}
//ActivityStarter对象回收的时候会情况之前的request内容
public void recycle(ActivityStarter starter) {
starter.reset(true /* clearRequest*/);
mStarterPool.release(starter);
}
ActivityStarter对象内部实例化了一个Request对象,ActivityStarter是由ActivityStartController去进行管理,里面维护了一个ActivityStarter的对象池,对象池复用对象在回收的时候会复位内部的成员属性,每次调用startActivity都会从对象池里面取出一个ActivityStarter,并且里面的mRequest对象是初始默认空状态
对象池的使用在源码里面经常能看到,在对象频繁创建使用的场景下,要学会用源码的设计方式去使用对象池管理这些短生命周期又需要频繁创建的对象,频繁的去创建回收对象会引发内存抖动,类似Handler里面的Message对象,startActivity也是一个调用次数会很高的方法
由于ActivityStarter内部的Request是没有内容的,所以会继续去解析出对应的activityInfo
//Request.java
void resolveActivity(ActivityStackSupervisor supervisor) {
resolveInfo = supervisor.resolveIntent();
// Collect information about the target of the Intent.
activityInfo = supervisor.resolveActivity();
}
可以看到,解析工作是通过ActivityStackSupervisor进行的,ActivityStackSupervisor这个对象的作用就是用来管理相关的配置信息
//ActivityStackSupervisor.java
final ActivityTaskManagerService mService;
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,int filterCallingUid) {
//getPackageManagerInternalLocked就是通过ATMS去获取PKMS
return mService.getPackageManagerInternalLocked().resolveIntent();
}
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,ProfilerInfo profilerInfo) {
final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
return aInfo;
}
ActivityStackSupervisor对象解析Activity信息是通过ATMS去调用到PKMS中的方法,看到PKMS的调用,就能联想到之前开机的时候分析了PKMS会去解析相关应用的四大组件信息,感觉离目标更近了
//PackageMangerService.java
public ResolveInfo resolveIntent(Intent intent, String resolvedType,int flags, int userId) {
return resolveIntentInternal();
}
private ResolveInfo resolveIntentInternal() {
try {
//继续调用去查询相关的Activity信息
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
flags, privateResolveFlags, filterCallingUid, userId, resolveForStart,
true /*allowDynamicSplits*/);
final boolean queryMayBeFiltered =
UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID
&& !resolveForStart;
//对列表进行进一步查询过滤
final ResolveInfo bestChoice =
chooseBestActivity(
intent, resolvedType, flags, privateResolveFlags, query, userId,
queryMayBeFiltered);
//最终返回的是一个ResolveInfo对象
return bestChoice;
}
}
//返回了List<ResolveInfo>一个列表对象
private List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,...) {
final String pkgName = intent.getPackage();
//ComponentName就是包含了目标目标Activity的全类名
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<>(1);
//会调用内部private的getActivityInfoInternal()方法
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
List<ResolveInfo> result = applyPostResolutionFilter(
list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent);
return result;
}
private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId) {
synchronized (mLock) {
//会从mComponentResolver里面去获取缓存的内容信息
ParsedActivity a = mComponentResolver.getActivity(component);
AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
//会从Settings对象里面去匹配是否已经解析了对应的Activity信息,然后返回
if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
return PackageInfoUtils.generateActivityInfo(pkg,
a, flags, ps.readUserState(userId), userId, ps);
}
if (mResolveComponentName.equals(component)) {
return PackageParser.generateActivityInfo(
mResolveActivity, flags, new PackageUserState(), userId);
}
}
return null;
}
从前面的PMKS解析开机过程中对APK的分析可以看出,当解析了manifest文件里面的activity标签后,会生成一个ParsedActivity数据结构的对象去存储Activity相关的配置信息,而在这里从PKMS取Activity信息的时候,通过一级一级的缓存去取出一个ParsedActivity类型的对象出来,也就是之前解析的activity信息
小结
到这里就分析到了,当startActivity方法执行的时候,会从PKMS中获取对应的Activity信息,这里面涉及到一些列的数据结构对象,在PKMS解析的最原始的Activity是用ParsedActivity对象是存储信息,然后当Intent解析后,会将里面的内容传递封装成ActivityInfo对象,这两个对象里面的内容基本一致,再往上传递就会将ActivityInfo对象封装到ResolveInfo对象中,这个对象是为了兼容四大组件,里面有不同组件的成员属性,具体的内容如下
//ParsedActivity.java
public class ParsedActivity extends ParsedMainComponent {
private String targetActivity;
String taskAffinity;
private String permission;
int launchMode;
int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
//ActivityInfo.java
public class ActivityInfo extends ComponentInfo implements Parcelable {
public int theme;
public int launchMode;
public String permission;
public String taskAffinity;
public String targetActivity;
public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
}
//ResolveInfo.java
public class ResolveInfo implements Parcelable {
public ActivityInfo activityInfo;
public ServiceInfo serviceInfo;
public ProviderInfo providerInfo;
public IntentFilter filter;
}
到这里就把Activity信息的获取过程告一段落,Request对象里面就持有了ActivityInfo对目标Activity的数据封装,接下来就继续回到ActivityStarter对象里面的execute()方法,去看后续的执行动作
executeRequest
当request对象里面解析了对象的数据,就进入继续的处理过程
//ActivityStarter.java
int execute() {
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
int res;
synchronized (mService.mGlobalLock) {
res = executeRequest(mRequest);
}
}
private int executeRequest(Request request) {
//一堆参数的处理
final IApplicationThread caller = request.caller;
Intent intent = request.intent;
ActivityInfo aInfo = request.activityInfo;
ResolveInfo rInfo = request.resolveInfo;
final int launchFlags = intent.getFlags();
//创建出目标ActivityRecord对象
final ActivityRecord r = new ActivityRecord();
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
//下一步执行的关键方法
mLastStartActivityResult = startActivityUnchecked(r,...);
return mLastStartActivityResult;
}
这个executeRequest方法里面有很多我们熟悉的对象,比如IApplicationThread在前面的文章中提过是应用ActivityThread的binder对象,处理了launchFlag启动模式等,将我们上面解析的ActivityInfo通过构造函数赋值到了一个ActivityRecord对象中,通过类名可以知道这个对象跟Activity有很密切的关系,那么又跟上面的ActivityInfo有什么不同
ActivityRecord
/**
* An entry in the history stack, representing an activity.
* 通过注释可以看出这个类就是历史栈中一条记录,也就是我们页面Activity的一个代表
*/
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
final ActivityTaskManagerService mAtmService;//关联了ATMS
// activity info provided by developer in AndroidManifest
final ActivityInfo info; //从AndroidManifest解析后封装的数据
final ActivityRecord.Token appToken;//WMS用到的token
final String taskAffinity; // 设置Task名字
// the task this is in.
private Task task; //ActivityRecord记录所在的Task任务栈
//省略一大堆成员变量
//ActivityRecord对象的构造方法里面传递了大量的数据,包括我们前面解析的ActivityInfo
ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
@Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
String _resultWho, int _reqCode, boolean _componentSpecified,
boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor,
ActivityOptions options, ActivityRecord sourceRecord) {}
}
通过这个数据结构的成员变量分析,可以得知在应用进程服务之间传递的Activity页面的属性和状态相关的数据包装类就是ActivityRecord,记录了前面通过manifest解析出来的我们配置的标签属性ActivityInfo和一堆跟Activity状态相关的成员变量
总结
到这里我们就基本上把跟Activity相关的数据类梳理了一遍,从应用开发的角度,我们会写一个继承自Activity的java类,并且在Androidmanifest.xml文件中进行配置,配置后首先会通过PKMS解析成ParsedActivity对象,然后通过包名缓存在内存中,当调用startActivity方法的时候,通过方法调用从PKMS取出解析好的ParsedActivity对象并且将内部属性赋值给一个ActivityInfo类型的对象,为了兼容四大组件,ActivityInfo类型的对象又会作为成员属性封装在一个ResolveInfo类型对象中,当准备好了ActivityInfo数据会赋值在一个Request对象中,在后续的startActiviy流程中,会取出对应的ActivityInfo数据实例化一个ActivityRecord类型的对象,这个对象就是我们所写的Activity在系统服务中进行传递和管理的真正代表,内部包含了当前页面的状态,页面所属的任务栈等各种跟Activity运行状态相关的属性
接下来的文章继续去分析跟ActivityRecord相关管理的任务栈Task对象和启动模式相关的内容,对涉及的数据结构有个整体的认知,在后续的源码分析中不容易迷路