activity的启动流程
加载一个Activity肯定不会像加载一般的类那样,因为activity作为系统的组件有自己的生命周期,有系统的很多回调控制,所以自定义一个DexClassLoader类加载器来加载插件中的Activity肯定是不可以的。
首先不得不了解一下activity的启动流程,当然只是简单的看一下,太详细的话很难研究清楚。
通过startActivity启动后,最终通过AMS进行跨进程回调到ApplicationThread的scheduleLaunchActivity,这时会创建一个ActivityClientRecord对象,这个对象表示一个Acticity以及他的相关信息,比如activityInfo字段包括了启动模式等,还有loadedApk,顾名思义指的是加载过了的APK,他会被放在一个Map中,应用包名到LoadedApk的键值对,包含了一个应用的相关信息。然后通过Handler切换到主线程执performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
// 1.创建ActivityClientRecord对象时没有对他的packageInfo赋值,所以它是null
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);
}
// ...
Activity activity = null;
try {
// 2.非常重要!!这个ClassLoader保存于LoadedApk对象中,它是用来加载我们写的activity的加载器
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
// 3.用加载器来加载activity类,这个会根据不同的intent加载匹配的activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
// 4.这里的异常也是非常非常重要的!!!后面就根据这个提示找到突破口。。。
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
// 从这里就会执行到我们通常看到的activity的生命周期的onCreate里面
mInstrumentation.callActivityOnCreate(activity, r.state);
// 省略的是根据不同的状态执行生命周期
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
// ...
}
return activity;
}
1.getPackageInfo方法最终返回一个LoadedApk对象,它会从一个HashMap的数据结构中取,mPackages维护了包名和LoadedApk的对应关系,即每一个应用有一个键值对对应。如果为null,就新创建一个LoadedApk对象,并将其添加到Map中,重点是这个对象的ClassLoader字段为null!
public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
int flags) {
// 为true
boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
boolean securityViolation = includeCode && ai.uid != 0
&& ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
: true);
// ...
// includeCode为true
// classloader为null!!!
return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode);
}
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
synchronized (mPackages) {
WeakReference<LoadedApk> ref;
if (includeCode) {
// includeCode为true
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null && !packageInfo.mResources.getAssets().isUpToDate())) {
if (localLOGV) // ...
// packageInfo为null,创建一个LoadedApk,并且添加到mPackages里面
packageInfo = new LoadedApk(this, aInfo, compatInfo, this, baseLoader, securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo. ) != 0);
if (includeCode) {
mPackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
2.获取这个activity对应的类加载器,由于上面说过,mClassLoa