android Activity的启动流程源码分析
ActivityThread在handlebindapplication中执行完Application的初始化之后会继续进入到消息循环中接收AMS(activity manager service)启动activity的消息。AMS首先会发送启动入口Activity的消息,然后ActivityThread会去调用handleLaunchActivity函数。
Activity启动过程
handleLaunchActivity
handleLaunchActivity会先去创建应用进程的页面然后初始化窗口,之后会调用performLaunchActivity函数。
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
// 创建页面 , 窗口初始化
WindowManagerGlobal.initialize();
// 启动 Activity 核心方法
final Activity a = performLaunchActivity(r, customIntent);
return a;
}
performLaunchActivity
performLaunchActivity函数会调用appContext.getClassLoader()尝试获取LoadedApk的mClassLoader。然后作为参数调用mInstrumentation.newActivity函数
/** Activity 启动的核心实现。 */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// 正式创建 Activity 对象
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) {
}
return activity;
}
Instrumentation.newActivity
newActivity函数会调用getFactory(pkg).instantiateActivity创建Activity,实际调用的是 AppComponentFactory 的 Activity instantiateActivityCompat
public class Instrumentation {
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
}
AppComponentFactory.instantiateActivityCompat
instantiateActivityCompat会通过前面获取的mClassLoader 调用loadClass加载Activity类对象,并调用newInstance实例化Activity对象。
public class AppComponentFactory extends android.app.AppComponentFactory {
public @NonNull Activity instantiateActivityCompat(@NonNull ClassLoader cl,
@NonNull String className, @Nullable Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
try {
// 通过mClassLoader 调用loadClass加载的。
return (Activity) cl.loadClass(className).getDeclaredConstructor().newInstance();
} catch (InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException("Couldn't call constructor", e);
}
}
}
总结
因为最后是通过获取到LoadedApk中的mClassLoader作为加载器来加载Activity类的,根据类加载流程,首先会遍历mClassLoader类加载器加载的所有dex文件,然后寻找每一个dex文件中的ClassDef并与待加载的class对比,如果找不到就会返回失败。因此在apk的加固应用中,因为我们使用的自定义的类加载器加载的apk文件/dex文件,所以mClassLoader根本找不到我们原apk的Activity类。所以使用自定义的类加载器加载apk时需要将mClassLoader替换为自定义的类加载器,否则在启动apk的activity时会出现找不到对应的Activity类。
也可以利用双亲委派原则,将当前mClassLoader类加载器与mClassLoader的父类加载器中插入自定义的类加载器,这样在使用mClassLoader加载Activity类时会根据双亲委派原则先让父加载器加载,因为mClassLoader的父加载器已经替换为了我们自定义的类加载器,所以可以找到对应的Activity类
参考:https://blog.csdn.net/shulianghan/article/details/120263706