前言
在Android开发中,我们经常会用到startActivity(Intent)方法,但是你知道startActivity(Intent)后Activity的启动流程吗?今天就专门讲一下最基础的startActivity(Intent)看一下Activity的启动流程,同时由于Launcher的启动后续和这里基本类似,就记录在一起。注意本章都是基于Android-10来讲解的。
客户端startActivity启动流程
startActivity启动流程本质上就是:向ActivityManagerService发送启动请求。由于发送端基本是在当前用户App进程或者Launcher进程(从桌面启动新的App)。除了SystemServer启动Launcher外,都需要借助AIDL发送请求。
1:客户端启动流程
startActivity方法在Activity,startActivity有两个重载方法,最终都会调用startActivityForResult(Intent,int, Bundle)方法,代码如下:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
//...
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
//...
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
其中mParent是当前Activity的父Activity,目前我只能想到TabActivity场景下才会存在一个Activity中包含Activity的情况,虽然它已经被Fragment替代了。所以基本上代码都是走mParent == null的流程,调用Instrumentation的execStartActivity方法。当然,在startActivityFromChild 方法里也是如此(不难发现,该方法已经被废弃了),源码如下,俩个重载的方法均已经废弃:
/** @deprecated */
@Deprecated
public void startActivityFromChild(@NonNull Activity child, Intent intent, int requestCode) {
throw new RuntimeException("Stub!");
}
/** @deprecated */
@Deprecated
public void startActivityFromChild(@NonNull Activity child, Intent intent, int requestCode, @Nullable Bundle options) {
throw new RuntimeException("Stub!");
}
我们继续看execStartActivity方法的关键代码:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//...
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
//备注一
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), 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;
}
其中,备注一处就是获取ActivityTaskManager服务并向其发送请求。备注二处会根据备注一处的返回结果检查Activity的启动状态,源码如下:
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
//如果没法发生启动错误,直接返回
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
//...
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
可以看到checkStartActivityResult在Activity里会根据启动失败的原因并抛出异常:注意里面的case ActivityManager.START_CLASS_NOT_FOUND,你一定知道如果没有在AndroidManifest.xml文件里声明Activity,就会抛出异常。没错,就是根据AMS返回的错误码,在这里抛出的异常。
当然,检查并不是在这里。checkStartActivityResult不负责任何启动Activity以及检查配置文件的工作,它之负责根据AMS的返回结果抛出异常。接下来回到备注一,看一下重点工作 ActivityTaskManager的getService方法。
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
代码比较简单,一个匿名内部类IActivityTaskManagerSingleton,里面的create 方法返回了一个IActivityTaskManager对象,根据方法里的内容就能猜出它个AIDL,该AIDL文件可在IActivityTaskManager源码里查看。
接着看一个ActivityTaskManagerSingleton.get()方法,get方法在它的父类Singleton中定义:
public abstract class Singleton<T> {
@UnsupportedAppUsage
public Singleton() {
}
@UnsupportedAppUsage
private T mInstance;
protected abstract T create();
@UnsupportedAppUsage
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
很简单的代码,一个懒汉式单例。如果实例为空,就调用create()方法,也就是上文中匿名内部类中复写的方法。到这里,一切就明了了:这里就准备开始跨进程通讯了ActivityTaskManager.getService方法就是客户端(发起创建Activity的当前App进程)向服务端(AMS)获取获取Binder对象用于跨进程通讯。而关键代码就是IActivityTaskManager.Stub.asInterface(b)。(注意IActivityTaskManager只是个AIDL文件,是为了自动生成代码的工具,更多关于AIDL的知识请看Android里的多进程和跨进程通讯方式)
接下来看final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);,看它是如何获得Binder实例的:
private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
// 有缓存,直接从缓存获取
return service;
} else {
// 没有缓存重新通过ServiceManager获取
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
上面是ServiceManager.getService方法的代码。ServiceManager是Android用来关系系统服务的,Android系统给我们提供了很多服务,每一个服务都有一个对应的类(AMS,WMS等),开发过程中我们就是通过这些类来获得我们所需要的服务。而ServiceManager则通过一个ArrayMap来缓存这些服务。这里也是如此:getService(Context.ACTIVITY_TASK_SERVICE)不难看出是要获得ActivityTaskManagerService的。看一下ActivityTaskManagerService:
它继承了IActivityTaskManager.Stub!!!就和上文中我们的AIDL文件对应上了。可以肯定ActivityTaskManagerService就是这次AIDL跨进程通讯的服务端了。
为了以防万一,我们还是要追踪一下ActivityTaskManagerService是如何添加到ServiceManager中的。这时,我们就要了解一下Android系统的启动流程了:ActivityTaskManagerService作为系统服务,是在SystemServer中被启动的:
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
其中SystemServiceManager.startService是通过反射创建Service的:
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
//..
final T service;
try {
//通过反射创建实例
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
}
//...
//启动服务
startService(service);