Activity启动流程分析

开始

在面试中,经常会被问到四大组件相关的问题,而在四大组件中问到最多的就是 Activity,如生命周期,启动流程等等。由此我们可以看出 Activity 在 Android 系统中扮演者很重要的角色,对于用户来说操作的基本上都是 Activity,而对于我们开发者来说,在平时的开发中基本上都是在 Activity 的基础之上进行的(应用开发)。下面我们就来分析一下 Activity 的启动流程。

分析之前

在开始分析之前,我们回顾一下 Activity 的一般用法,Activity 的使用方法虽然简单,那其实因为 Andrid 帮我们实现了大部分的逻辑,但是这不代表一般用法没用,在整个阅读源码的过程中,用法往往是放在第一个位的,从用法中我们可以分析出一个大概的轮廓,比如:

平时我们都是这么使用 Activity 的

1
2
3
4
5
6
7
8
9
10

//1. 首先我们要在 Manifest 中声明 Activity
<activity name = ".MainActivity"/>

//2. 我们新建一个类并且继承 Activity
public class MainActivity extends Activity { ... }

//3. 如果我们想启动这个 Activity
Intent intent = new Intent(this,MainActivity.class);
startActivity(Intent)

可以看到,我们首先要在 Manifest 中声明 Activity,然后要继承系统的 Activity,最后通过 Intent 加 startActivity 方法启动。那么就有如下几个问题:

  1. 为什么要在 Manifest 中声明 Activity,是不是必须的?
  2. 可不可在不继承 Activity 的情况下实现一个 Activity?
  3. 启动一个 Activity 有没有别的方法?

下面我们就在源码中找到上面问题的答案。

下面源码都是基于 Android 26。

startActivity()

我们先看看 startActivity() 这个方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
//一般情况下 mParent 都是等于 null 的
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}

cancelInputsAndStartExitTransition(options);
} else {
//省略部分代码
}
}

不知道大家有没有发现 startActivity() 这个方法是重写的父类的方法,而 startActivityForResult() 却不是重写的,原因很简单,因为 Activity 的父类其实就 Context,因为 Context 压根就没有 startActivityForResult() 这个方法,所以无法重写,那为什么 Context 没有呢?因为 startActivityForResult() 是 Activity 特有的,换言之 startActivity 并不是非要在 Activity 中调用,只要有 Context 对象就能调用,所以我们就能在 Service 等组件中启动 Activity。

我们只看最重要的一部分,那就是调用 mInstrumentation 的 execStartActivity() 方法,这个方法的第二参数是一个 IBinder 对象,这个参数非常重要,具体如何重要,我们继续往下看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
// 省略部分代码
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), 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;
}

在上面的方法中,最终调用了 ActivityManager 的 getService() 这个方法,这个方法最终会返回一个 ActivityManagerService(下面简称 AMS),并调用它的 startActivity() 方法,在分析 AMS 的 startActivity() 方法之前,我们先看看后面那个 checkStartActivityResult() 这个方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//Instrumentation.java
public static void checkStartActivityResult(int res, Object intent) {
// 判断 startActivity 的返回结果是否有异常
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");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start voice activity on a hidden session");
case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
throw new IllegalStateException(
"Session calling startAssistantActivity does not match active session");
case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
throw new IllegalStateException(
"Cannot start assistant activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for "
+ intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}

在上面代码中的过 switch 中,有一个 case 的值是 START_CLASS_NOT_FOUND,这个 case 对应的异常我想大家在日常开发中一定没少遇到,原因就是我们没有在 Manifest 中注册这个 Acitivty,所以就会导致这个异常。

ActivityThread

回到 AMS 的 startActivity() 方法,在 AMS 的 startActivity() 方法中又会经过一长窜的调用(这里的调用很长,我们没必要去纠结它是怎么调用的,只需要最终会调用哪个方法即可),最终来到 ApplicationThread 的 scheduleLaunchActivity(),源码如下:

1
2
3
4
5
6
7
8
9
10
11
12

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

//省略部分代码
sendMessage(H.LAUNCH_ACTIVITY, r);
}

在上面的代码中,最终调用 sendMessage() 方法,这个方法会向一个名为 mH 的 Handler 发送一个 Message,这个名为 mH 的 Hander 声明在 ActivityThread 类中,而 ApplicationThread 是 ActivityThread 的内部类。

在 ActivityThread 中,最终会调用 handleLaunchActivity() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;

if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}

// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);

// Initialize before creating the activity
WindowManagerGlobal.initialize();

//调用 performLaunchActivity
Activity a = performLaunchActivity(r, customIntent);

//省略部分代码
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}

ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}

if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}

ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
//从这里可以看错 Activity 的实例是通过反射创建的
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}

//省略部分代码
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//省略部分代码

return activity;
}

上面的代码很长,不过流程很清晰,首先我们可以看到,系统通过 Instrumentation 的 newActivity() 方法创建 Activity 对象的实例,其内部其实就是是用了 Java 的反射机制,然后会调用 LoadApk 的 makeApplication() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//判断 mApplication
if (mApplication != null) {
return mApplication;
}

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

Application app = null;

String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}

try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;

if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
//省略部分代码...
return app;
}

在上面的代码中,首先会判断 mApplication 对象是否为空,所以我们可以推断出 mApplication 只会有一个实例,接着如果 mApplication 为空会调用 Instrumentation 的 createAppContext() 方法,这个方法会创建出 ContextImpl 对象,紧接着会调用 Instrumentation 的 createApplication() 方法,源码如下:

1
2
3
4
5
6
7
8
//Instrumentation.java
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}

可以看到,和 Activity 一样会使用反射创建对象,然后调用 attach() 方法,注意那个 context 参数,其实就是我们上面创建的 ContextImpl 对象。

回到上面的 makeApplication(),当 Application 对象的实例创建完成之后,会将它赋值个 mApplication,最后通过 Instrumentation 的 callApplicationOnCreate() 调用 Application 的 onCreate()。

到这里 Application 对象创建了,并且它的 onCreate() 也被调用,重新回调用 ActivityThread 类的 performLaunchActivity() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//省略部分代码
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
//activity 对象已经在上面创建了
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);

if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
return activity;
}

可以看到在 performLaunchActivity() 方法中,创建完 Activity 对象之后,会调用它的 attach() 方法,这个方法主要是用来初始化 Activity 的一些属性的,其中包括 Window,ApplicationContext 等等。之后会调用 Intrumentation 的 callActivityOnCreate() 方法,在这个方法会调用 Activity 的 onCreate()。

分析到这里,Activity 对象就被成功创建出来了,我们回到开始的几个问题,看看有没有找到答案。

  1. Activity 在一般情况下必须在 Manifest 中注册,为什么说是一般情况下,因为我们可以通过一些特殊手段来欺瞒系统,从而让系统不抛出 ActivityNotFoundException 这个异常。
  2. 必须要继承系统的 Activity,因为在 Instrumentation 中的 newActivity 的方法中会对反射创建出来的对象进行强转,如果类型不对,会直接抛出类型转换异常。
  3. 开启 Activity 的方式有很多种如 startActivity(),startActivityForResult()等等,但是通过上面的分析,启动一个 Activity 其实和 Instrumentation 这个类有这密切的关系,所以如果我们把上面的流程通过会先方式实现一遍,一样是可以唤醒 Actiivty,不过这样做是没有意义的,但是我们可以通过反射来替换系统的 Instrumentation 对象并使用我们自定义的 Instrumentation 对象。插件化就是一个典型的例子。

插件化

上面分析了 startActivity() 的整个流程,但是感觉对我们的开发没有什么用,其实不然,Activity 的启动流程能帮助我们更容易的理解插件化的原理,下面我们就通过分析 VirtualAPKVirtualAPK

VirtualAPK 这个开源库中是怎么实现将 Activity 插件化的。

什么是插件化?

最近几年在国内 Android 界中,插件化成为了一个比较热门的话题,几乎热门的 APP 都有自己的插件化方案,因为国内市场竞争激烈,每家 APP 都想将扩大自己的业务范围,所以就会在 APP 集成很多模块,这些模块对于用户来说是完全透明的,但是对于开发者来说却是噩梦,在传统 APP 开发环境中,实现几个小的模块并处理好里面的逻辑已经是很麻烦的事情了,而如果需要处理几个大模块,每个大模块中又有一堆小模块,这个时候开发就会变得很困难,但是老板不管这些,于是插件化就诞生了。

其实插件化只是一种思想,就是一个复杂的东西,拆分成一个一个的简单的东西。至于每种插件化方案的差别,仅仅是技术实现手段不同而已,思想上是一样的,都是为了能更快速的迭代产品。

VirtualAPK

VirtualAPK 是滴滴开源的插件化方案,算是我看过最通俗易懂的插件化方案之一,是通过 Hook 系统的 Instrumenation 对象,来实现启动插件中的 Activity,本篇博客只分析 Activity 是如何实现插件化的。

通过上面的分析,Activity 的启动流程最先是走到 Instrumentation 的 execStartActivity() 方法的,所以 VirtualAPK 使用反射技术将自定义的 VAInstrumentation 对象注入到系统的 ActivityThread 类中,从而实现接替系统的 execStartActivity() 方法,具体源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//PluginManager.java
private void prepare() {
Systems.sHostContext = getHostContext();
this.hookInstrumentationAndHandler();
if (Build.VERSION.SDK_INT >= 26) {
this.hookAMSForO();
} else {
this.hookSystemServices();
}
}

private void hookInstrumentationAndHandler() {
try {
Instrumentation baseInstrumentation = ReflectUtil.getInstrumentation(this.mContext);
if (baseInstrumentation.getClass().getName().contains("lbe")) {
// reject executing in paralell space, for example, lbe.
System.exit(0);
}
//创建自己的 VAInstrumentation 对象
final VAInstrumentation instrumentation = new VAInstrumentation(this, baseInstrumentation);
Object activityThread = ReflectUtil.getActivityThread(this.mContext);
//通过反射替换系统的 Instrumentation 对象
ReflectUtil.setInstrumentation(activityThread, instrumentation);
ReflectUtil.setHandlerCallback(this.mContext, instrumentation);
this.mInstrumentation = instrumentation;
} catch (Exception e) {
e.printStackTrace();
}
}

下面我们来看看在 VAInstrumentation 对象中,究竟做了一些什么事情,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//VAInstrumentaion.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
mPluginManager.getComponentsHandler().transformIntentToExplicitAsNeeded(intent);
// null component is an implicitly intent
if (intent.getComponent() != null) {
Log.i(TAG, String.format("execStartActivity[%s : %s]", intent.getComponent().getPackageName(),
intent.getComponent().getClassName()));
// resolve intent with Stub Activity if needed
this.mPluginManager.getComponentsHandler().markIntentIfNeeded(intent);
}

ActivityResult result = realExecStartActivity(who, contextThread, token, target,
intent, requestCode, options);

return result;

}

//执行系统的 execStartAcitivty 方法
private ActivityResult realExecStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
ActivityResult result = null;
try {
Class[] parameterTypes = {Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class,
int.class, Bundle.class};
result = (ActivityResult)ReflectUtil.invoke(Instrumentation.class, mBase,
"execStartActivity", parameterTypes,
who, contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
if (e.getCause() instanceof ActivityNotFoundException) {
throw (ActivityNotFoundException) e.getCause();
}
e.printStackTrace();
}

return result;
}

阅读源码可以看到,VAInstrumentation 类其实使用了静态代理设计模式来实现接替系统的 Instrumentation,但是由于系统的 execStartActivity() 方法标记为 hide,所以在 realExecStartActivity() 方法中不得不使用反射去调用真正的 execStartActivity() 方法。

回到 execStartActivity() 方法,平时我们调用 startAcitivty() 的时候,getComponent() 肯定是不会为 null 的,所以它会执行 ComponentsHandler 中的 markIntentIfNeeded() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//ComponentsHandler.java
public void markIntentIfNeeded(Intent intent) {
if (intent.getComponent() == null) {
return;
}

String targetPackageName = intent.getComponent().getPackageName();
String targetClassName = intent.getComponent().getClassName();
// search map and return specific launchmode stub activity
if (!targetPackageName.equals(mContext.getPackageName()) && mPluginManager.getLoadedPlugin(targetPackageName) != null) {
intent.putExtra(Constants.KEY_IS_PLUGIN, true);
intent.putExtra(Constants.KEY_TARGET_PACKAGE, targetPackageName);
intent.putExtra(Constants.KEY_TARGET_ACTIVITY, targetClassName);
dispatchStubActivity(intent);
}
}

可以发现,通过判断包名来判断,启动的 Activity 是否是插件中的,如果是插件中的,会在 Intent 中保存几个值,然后调用 dispatchStubActivity() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

private void dispatchStubActivity(Intent intent) {
ComponentName component = intent.getComponent();
String targetClassName = intent.getComponent().getClassName();
LoadedPlugin loadedPlugin = mPluginManager.getLoadedPlugin(intent);
ActivityInfo info = loadedPlugin.getActivityInfo(component);
if (info == null) {
throw new RuntimeException("can not find " + component);
}
int launchMode = info.launchMode;
Resources.Theme themeObj = loadedPlugin.getResources().newTheme();
themeObj.applyStyle(info.theme, true);
String stubActivity = mStubActivityInfo.getStubActivity(targetClassName, launchMode, themeObj);
Log.i(TAG, String.format("dispatchStubActivity,[%s -> %s]", targetClassName, stubActivity));
intent.setClassName(mContext, stubActivity);
}

可以看到,最关键的一行代码就是最后一行,调用了 intent 的 setClassName() 方法,因为我们启动的是插件中的 Activity,默认情况下一定会抛出 ActivityNotFound 的异常,所以 VirtualAPK 在 Manifest 中预先声明了几个占位子的 Activity,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<!-- Stub Activities -->
<activity android:name=".A$1" android:launchMode="standard"/>
<activity android:name=".A$2" android:launchMode="standard"
android:theme="@android:style/Theme.Translucent" />

<!-- Stub Activities -->
<activity android:name=".B$1" android:launchMode="singleTop"/>
<!-- 省略部分代码 -->

<!-- Stub Activities -->
<activity android:name=".C$1" android:launchMode="singleTask"/>
<!-- 省略部分代码 -->

<!-- Stub Activities -->
<activity android:name=".D$1" android:launchMode="singleInstance"/>
<!-- 省略部分代码 -->

到这里,就成功的欺骗了系统,让系统以为我们已经在 Manifest 中注册了插件中的 Activity,但是新的问题又出现了,上面的.A$1这个类肯定是不存在的,通过我们对 Activity 启动流程的分析,系统会通过调用 Instrumentation 的 newActivity() 方法来创建 Activity 对象的实例,创建的方法是使用反射,所以我们就可以通过重写这个方法来实现创建我们插件中 Activity 类的实例从而达到启动的目的。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//VAInstrumentation.java
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
try {
//如果是启动插件中的 Activity,这里一定会报错!
cl.loadClass(className);
} catch (ClassNotFoundException e) {
LoadedPlugin plugin = this.mPluginManager.getLoadedPlugin(intent);
String targetClassName = PluginUtil.getTargetActivity(intent);

Log.i(TAG, String.format("newActivity[%s : %s]", className, targetClassName));

if (targetClassName != null) {
Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);
activity.setIntent(intent);

try {
// for 4.1+
ReflectUtil.setField(ContextThemeWrapper.class, activity, "mResources", plugin.getResources());
} catch (Exception ignored) {
// ignored.
}

return activity;
}
}

return mBase.newActivity(cl, className, intent);
}

分析上面的代码,可以看到 在 newActivity() 方法中判断如果报错了,就说明启动的是插件中的 Activity 所以就通过插件中 ClassLoader 去创建插件中的 Activity 的实例,然后在设置一相应的属性比返回,这样就成功的打开了插件里面里面的 Activity。

总结

Activity 的启动流程大致可以看为 APP 进程像系统服务 ActivityManagerService 发送”请求”,通过返回信息加反射创建 Activity 类的实例。这里的”请求”其实就是一次 IPC

系统实现的像 ActivityManagerService 这样的系统服务,这些服务都是向 APP 提供服务的,这样做的好处就是可以将很多复杂的功能都封装起来,只提供对外的接口,如果后面服务有修改,只要接口不变,APP 这块不需要任何修改。

关于 VirtualAPK 实现的插件化 Activity,可以说是很简洁的一种方案,但是这里仅仅只分析了打开插件里面的 Activity,还有其他需要处理的地方,可以看出插件化这项技术对学习系统服务的原理有这很大的帮助。