VirtualAPK学习

Activity加载

参考了鸿洋的博客:
https://blog.csdn.net/lmj623565791/article/details/75000580

 Activity:
 首先通过反射拿到了原本的Instrumentation对象,拿的过程是首先拿到ActivityThread,由于ActivityThread可以通过静态变量sCurrentActivityThread或者静态方法currentActivityThread()获取,所以拿到其对象相当轻松。拿到ActivityThread对象后,调用其getInstrumentation()方法,即可获取当前的Instrumentation对象。然后自己创建了一个VAInstrumentation对象,接下来就直接反射将VAInstrumentation对象设置给ActivityThread对象即可。

 hook Instrumentation的dispatchStubActivity方法,判断是否是启动插件类,是的话就选择一个坑位将真正的activity放在intent的响应变量中,启动activity的方法为:
 AMS在处理完启动Activity后,会调用:app.thread.scheduleLaunchActivity,这里的thread对应的server端未我们ActivityThread中的ApplicationThread对象(binder可以理解有一个client端和一个server端),所以会调用ApplicationThread.scheduleLaunchActivity方法,在其内部会调用mH类的sendMessage方法,传递的标识为H.LAUNCH_ACTIVITY,进入调用到ActivityThread的handleLaunchActivity方法->ActivityThread#handleLaunchActivity->mInstrumentation.newActivity()。

   还原Activity:
   在newActivity中替换要真正加载的activity,
   在callActivityOnCreate中设置了修改了mResources、mBase(Context)、mApplication对象。以及设置一些可动态设置的属性。



service:

创建一个代理service,hook住IActivityManager对象,里面是service的所有方法,当判断是插件service的时候,启动代理service,在代理service中的start。


BroadcastReceiver的支持:

    将静态代理转换为动态代理


ContentProvider:通过一个代理Provider进行分发。

资源加载

我们知道android资源加载是与AssetManager和Resources两个类有关的,AssetManager根据文件名加载资源,Resources先根据资源id获取资源名称,然后再根据AssetManager加载资源。先创建AssetManager,这个是一个native的方法,将系统资源和所对应的apk路径addAssetPath一个verctor集合中,在Resources创建的时候mResources指向的是一个ResTable对象,如果它的值不等于NULL,那么就说明当前应用程序已经解析过它使用的资源包里面的resources.arsc文件,因此,这时候AssetManager类的成员函数getResources就可以直接将该ResTable对象返回给调用者。如果还没有初始化 mResources 则按照一定步骤遍历当前应用所使用的每个资源包进而生成 mResources 。ResTable对象就是对应资源id 的一个列表。

VirtualAPk资源加载

virtual有两种模式:1.插件有一个独立的Resources,2.插件可以访问宿主的资源。
如果将宿主和插件隔离,我们只需要生成一个独立的Resources对象给插件使用,如果要调用宿主资源则需要将宿主的APK和插件的APK一起添加到同一个AssetManager里。

由于资源做过分区,则在Android L后直接将插件包的apk地址addAssetPath`之后就可以,但是在Android L之前,addAssetPath只是把补丁包加入到资源路径列表里,但是资源的解析其实是在很早的时候就已经执行完了,问题出现在这部分代码:

const ResTable* AssetManager::getResTable(bool required) const
{
    ResTable* rt = mResources;
    if (rt) {
        return rt;
    }
    //....

}

由于有系统资源的存在,mResources 的初始化在很早就初始化了,所以我们就算通过addAssetPath方法将 apk 添加到mAssetPaths里,在查找资源的时候也不会找到这部分的资源,因为在旧的 mResources 里没有这部分的 id。

所以在 Android L 之前是需要想办法构造一个新的AssetManager里的 mResources 才行,这里有两种方案,VirtualAPK 用的是类似 InstantRun 的那种方案,构造一个新的 AssetManager,将宿主和加载过的插件的所有 apk 全都添加一遍,然后再调用hookResources方法将新的 Resources 替换回原来的,这样会引起两个问题,一个是每次加载新的插件都会重新构造一个 AssetManger 和 Resources,然后重新添加所有资源,这样涉及到很多机型的兼容(因为部分厂商自己修改了 Resources 的类名),一个是需要有一个替换原来Resources的过程,这样就需要涉及到很多地方,从hookResources的实现里看,替换了四处地方,在尽量少的 hook 原则下这样的情况还是尽量避免的。

Activity 启动过程中对资源的处理

在newActivity中将新创建的Resources添加到要启动的activity中。

你可能感兴趣的:(学习)