VirtualAPK分析

VirtualAPK初始化流程

在使用VirtualAPK之前,我们需要多VirtualAPK进行初始化,如下所示:

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    long start = System.currentTimeMillis();
    PluginManager.getInstance(base).init();
}

getInstance()

双重校验锁实现单例

private static volatile PluginManager sInstance = null;
public static PluginManager getInstance(Context base) {
    if (sInstance == null) {
        synchronized (PluginManager.class) {
            if (sInstance == null) {
                //调用createInstance创建PluginManager
                sInstance = createInstance(base);
            }
        }
    }
    return sInstance;
}

createInstance()

构造函数

hookCurrentProcess()

hookInstrumentationAndHandler()

hookSystemServices

VirtualAPK的的加载流程

VirtualAPK对于加载的APK文件没有额外的约束,只需要添加VirtualAPK的插件进行编译,如下所示:

然后就可以调用PluginManager直接加载编译完成的APK,被加载的APK在PluginManager里是一个LoadedPlugin对象,VirtualAPK通过这些LoadedPlugin对象来管理APK,这些APK也可以 想在手机里直接安装的App一样运行。

APK的加载流程如下图所示:

这里调用了LoadedPlugin的create()方法去构建一个LoadedPlugin对象,所以的初始化操作都是在LoadedPlugin的构造方法里完成的,如下所示:

整个LoadedPlugin对象构建的过程就是去解析APK里的组件信息,并缓存起来,具体说来:

  1. 调用PackageParser解析APK,获取PackageParser.Package对象。

  2. 构建PackageInfo对象。

  3. 构建PluginPackageManager对象。

  4. 构建Resouces对象。

  5. 构建ClassLoader对象。

  6. 拷贝so库。

  7. 缓存Instrumentation对象。

  8. 缓存APK里的Activity信息。

  9. 缓存APK里的Service信息。

  10. 缓存APK里的Content Provider信息。

  11. 将静态的广播转为动态的。

我们接着来看没有在宿主App的Manifest里注册的四大组件时如何被启动起来的。

VirtualAPK启动组件的流程

Activity

前面我们说过在初始化VirtualAPK的过程中使用自定义的VAInstrumentation在ActivityThread中替换掉了原生的Instrumentation对象,来达到hook到Activity启动流程的目的,绕开Instrumentation 启动Activity的校验流程。

那么VirtualAPK是如何绕过系统校验的呢?

Virtual是采用占坑的方式来绕过校验的,它在库里的Manifest文件里定义了占坑的文件,如下所示:

A、B、C、D分别代表standard、singleTop、singleTask和singleInstance四种启动模式。

VirtualAPK制造一些假的Activity替身在Manifest文件提前进行注册占坑,在启动真正的Activity时候,再将Activity填到坑里,以完成启动Activity。我们来看看具体的是实现流程:

  1. execStartActivity()

  2. realExecStartActivity()

  3. newActivity()

  4. callActivityOnCreate()

以上四个方法都是启动Activity的过程中必经的四个方法。

  1. 将隐式Intent转换为显式Intent,Virtual是通过intent.setClassName(this, "com.guoxiaoxing.plugin.MainActivity");这种 //方式来启动Activity的,这里将包名封装成真正的ComponentName对象。

参考

最后更新于