VirtualApp大致原理
- VirtualApp是一款运行于Android系统的沙盒产品,可以理解为轻量级的“Android虚拟机”。
进程
- VA当中设计了三种进程
- VA主进程,即本身的进程,可以认为类似Android中的Launcher进程
- VA的服务进程,可以任务类似Android中的System Server进程
- VA双开的子进程,双开应用所在的进程。可以同时有很多个
环境
- 一个App能运行起来,需要System Server进程中的各种核心服务提供的能力。比如AMS,WMS,PMS等。应用进程通过SystemManager进程中通过查找表获取到核心服务的Binder引用。从而实现IPC的调用。
- VA实现了一个类似System Server进程,其中有必须的一些核心服务。比如VAMS和VPMS,就是AMS和PMS的复刻。其逻辑与系统原生的类似。
- 这些VAMS和VPMS的Binder引用都被存放在VA的服务进程中的一个静态的Map<String, IBinder>里。这个Map就类似SystemManager中的查找表。

- VA主进程通过ContentProvider的call()获取传递的Bundle其中的Binder引用。这个Binder引用可以和VA服务进程通信,提供了getService(String)的接口,从而获取对应的复刻核心服务的Binder引用。就能调用这些复刻核心服务提供的能力。
- 在复刻的核心服务中,有些也需要去调用真正核心服务的能力。因此VA中还实现了Framework层一些类的镜像类。只是这些镜像类只是保存了通过反射去获取对于类的方法和变量。这样VA可以主动去调用。RefXXX是包装类,比如RefObject封装了Field,RefMethod封装了Method。到时可以直接用于反射调用。下图的ActivityThread就是系统的ActivityThread的镜像

- 除了VA需要使用Framework层不暴露出来的方法和变量,同时VA也需要对于Framework层的一些不暴露出来的方法实现AOP。其中AMS的Hook是通过反射获取接口,再使用动态代理从而实现的AOP。而ActivityThread的mH是通过反射设置Callback,从而实现对Message在被调用handleMessage()之前的拦截。
StartActivity
- Android 9开始对Activity的启动流程有所调整需要适配
- VAMS.startActivity()会借助ContentProviderClient.call()实现IPC。通过给ContentProviderClient设置了URI指定通信的进程(就是某个双开的子进程)。如果进程未创建,系统就会自动创建对应的进程。
- VAMS.startActivity()同时还会设置打开StubActivity的Intent。而这个Intent当中保存了真正要打开双开应用Activity的Intent。而StubActivity是VA的占坑Activity,它会在Manifest.xml中注册。
- VAMS.startActivity()最终会调用Context.startActivity()。此时传入的Intent还是StubActivity的。
- 而之前给mH设置的Callback会收到启动Activity的消息,在拦截到这条消息后,通过反射获取打开StubActivity的Intent,再把这个Intent中保存的真正Intent通过反射进行替换。这样就能顺利打开双开应用的Activity了。
- VA会获得双开应用Activity的ActivityInfo信息,所以创建的LoadAPK对象为双开应用的apk内存实例对象,获取的classLoader对象也是指定了双开应用的代码路径与so路径等,所以使用这个classLoader就可以创建目标Activity了。而不需要像插件化一样去修改BaseDexClassLoader中的Dex数组。