首页 > 编程语言 >android Activity的启动流程源码分析

android Activity的启动流程源码分析

时间:2022-10-21 14:59:51浏览次数:66  
标签:cl activity mClassLoader 源码 intent Activity android 加载

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()尝试获取LoadApk的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);
        }
    }

}

总结

因为最后是通过获取到LoadApk中的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

标签:cl,activity,mClassLoader,源码,intent,Activity,android,加载
From: https://www.cnblogs.com/revercc/p/16813435.html

相关文章