VirtualApp(以下简称VA)是一个开源的Android app虚拟化引擎,它提供了一个虚拟空间,允许其他应用运行在这个虚拟空间中,实现应用多开(可重复安装)。
在VA中,host应用(VA自身)和client应用(通过VA安装的应用)具有相同的uid。
在运行时,一般会包含三个进程:
用ps命令看一下:
u0_a123 16545 256 1056344 84524 ffffffff 00000000 S io.virtualapp
u0_a123 16607 256 909252 36140 ffffffff 00000000 S io.virtualapp:x
u0_a123 16674 256 914872 40004 ffffffff 00000000 S com.example.test
下面从源码分析一下VA启动与运行的整个过程:
VA的Application为VApp,包路径为io.virtualapp,是一个继承自MultiDexApplication的Application。这个类重写了attachBaseContext()
方法,程序启动后首先运行该方法,再调用oncreate()
方法。先看一下这个attachBaseContext方法做了什么:
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
mPreferences = base.getSharedPreferences("va", Context.MODE_MULTI_PROCESS);
VASettings.ENABLE_IO_REDIRECT = true;
VASettings.ENABLE_INNER_SHORTCUT = false;
try {
VirtualCore.get().startup(base);
} catch (Throwable e) {
e.printStackTrace();
}
}
除了设置一些属性,主要有这么一句:VirtualCore.get().startup(base);
VirtualCore是定义在包com.lody.virtual.client.core中的一个类,get()
首先返回一个重点内容静态的VirtualCore对象,然后调用该对象的startup()
方法进行一些初始化操作,看下这个方法的代码:
public void startup(Context context) throws Throwable {
if (!isStartUp) {
// step 1
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
}
VASettings.STUB_CP_AUTHORITY = context.getPackageName() + "." + VASettings.STUB_DEF_AUTHORITY;
ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
// step 2
this.context = context;
mainThread = ActivityThread.currentActivityThread.call();
unHookPackageManager = context.getPackageManager();
hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);
IPCBus.initialize(new IServerCache() {
@Override
public void join(String serverName, IBinder binder) {
ServiceCache.addService(serverName, binder);
}
@Override
public IBinder query(String serverName) {
return ServiceManagerNative.getService(serverName);
}
});
// step 3
detectProcessType();
// step 4
InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
invocationStubManager.init();
invocationStubManager.injectAll();
// step 5
ContextFixer.fixContext(context);
isStartUp = true;
if (initLock != null) {
initLock.open();
initLock = null;
}
}
}
step 1. 首先判断当前进程是否为主进程,因为VApp作为应用程序的入口,多进程情况下会被调用多次;
step 2. 依次获取当前线程mainThread、调用context的getPackageManager方法获得包管理器unHookPackageManager(后面会对该对象做hook),以及包管理器的getPackageInfo方法获得包信息PackageInfo对象hostPkgInfo;
step 3. 接下来调用detectProcessType()
,主要是获取包名、主进程名和当前进程名,通过对比判断进程类型,主要是四种:主进程、服务进程(以:x结尾)、客户端进程(VActivityManager的isAppProcess()
方法)和子进程;
step 4. 创建了InvocationStubManager类对象invocationStubManager,然后分别调用了该对象的init()
和injectAll()
方法,依次完成InvocationStubManager的初始化和执行系统的注入;
step 5. 完成一些上下文的恢复与检查。
然后我们先详细看下第四步中的注入过程,首先是invocationStubManager.init()
:
public void init() throws Throwable {
if (isInit()) {
throw new IllegalStateException("InvocationStubManager Has been initialized.");
}
injectInternal();
sInit = true;
}
代码很简单,主要是调用了injectInternal()
这个方法,继续看代码:
private void injectInternal() throws Throwable {
if (VirtualCore.get().isMainProcess()) {
return;
}
if (VirtualCore.get().isServerProcess()) {
addInjector(new ActivityManagerStub());
addInjector(new PackageManagerStub());
return;
}
if (VirtualCore.get().isVAppProcess()) {
addInjector(new LibCoreStub());
addInjector(new ActivityManagerStub());
addInjector(new PackageManagerStub());
addInjector(HCallbackStub.getDefault());
addInjector(new ISmsStub());
addInjector(new ISubStub());
addInjector(new DropBoxManagerStub());
addInjector(new NotificationManagerStub());
addInjector(new LocationManagerStub());
addInjector(new WindowManagerStub());
addInjector(new ClipBoardStub());
addInjector(new MountServiceStub());
addInjector(new BackupManagerStub());
addInjector(new TelephonyStub());
addInjector(new TelephonyRegistryStub());
addInjector(new PhoneSubInfoStub());
addInjector(new PowerManagerStub());
addInjector(new AppWidgetManagerStub());
addInjector(new AccountManagerStub());
addInjector(new AudioManagerStub());
addInjector(new SearchManagerStub());
addInjector(new ContentServiceStub());
addInjector(new ConnectivityStub());
if (Build.VERSION.SDK_INT >= JELLY_BEAN_MR2) {
addInjector(new VibratorStub());
addInjector(new WifiManagerStub());
addInjector(new BluetoothStub());
addInjector(new ContextHubServiceStub());
}
if (Build.VERSION.SDK_INT >= JELLY_BEAN_MR1) {
addInjector(new UserManagerStub());
}
if (Build.VERSION.SDK_INT >= JELLY_BEAN_MR1) {
addInjector(new DisplayStub());
}
if (Build.VERSION.SDK_INT >= LOLLIPOP) {
addInjector(new PersistentDataBlockServiceStub());
addInjector(new InputMethodManagerStub());
addInjector(new MmsStub());
addInjector(new SessionManagerStub());
addInjector(new JobServiceStub());
addInjector(new RestrictionStub());
}
if (Build.VERSION.SDK_INT >= KITKAT) {
addInjector(new AlarmManagerStub());
addInjector(new AppOpsManagerStub());
addInjector(new MediaRouterServiceStub());
}
if (Build.VERSION.SDK_INT >= LOLLIPOP_MR1) {
addInjector(new GraphicsStatsStub());
addInjector(new UsageStatsManagerStub());
}
if (Build.VERSION.SDK_INT >= M) {
addInjector(new FingerprintManagerStub());
addInjector(new NetworkManagementStub());
}
if (Build.VERSION.SDK_INT >= N) {
addInjector(new WifiScannerStub());
addInjector(new ShortcutServiceStub());
addInjector(new DevicePolicyManagerStub());
}
if (Build.VERSION.SDK_INT >= 26) {
addInjector(new AutoFillManagerStub());
}
}
}
简单的看就是判断当前进程类型,然后通过addInjector方法添加XXXStub对象,具体为:
说明:这里注入其实就是完成Java层的hook操作,自身app当然不需要hook,服务进程需要管理应用因此需要hook AMS和PMS,而对于应用进程,则需要hook整个framework框架,保证所有调用重定向到VA的框架里。
这里的添加操作:
private void addInjector(IInjector IInjector) {
mInjectors.put(IInjector.getClass(), IInjector);
}
就是将新建的Stub对象添加到Map
public ActivityManagerStub() {
super(new MethodInvocationStub<>(ActivityManagerNative.getDefault.call()));
}
可以看到,这个构造函数中,首先新建了一个MethodInvocationStub对象,参数是通过反射调用ActivityManagerNative的getDefault()
获取的接口对象。再看MethodInvocationStub的构造函数,最终都会调到这个函数:
public MethodInvocationStub(T baseInterface, Class>... proxyInterfaces) {
this.mBaseInterface = baseInterface;
if (baseInterface != null) {
if (proxyInterfaces == null) {
proxyInterfaces = MethodParameterUtils.getAllInterface(baseInterface.getClass());
}
mProxyInterface = (T) Proxy.newProxyInstance(baseInterface.getClass().getClassLoader(), proxyInterfaces, new HookInvocationHandler());
} else {
VLog.d(TAG, "Unable to build HookDelegate: %s.", getIdentityName());
}
}
首先保存第一个参数,也即前面传入的ActivityManagerNative实例对象,然后获取这个实例对象对应Class对象的所有接口proxyInterfaces,通过Proxy.newProxyInstance()来构建ActivityManager的动态接口代理对象mProxyInterface,其中HookInvocationHandler对象处理代理后的执行逻辑。
初始化的工作到这里就做完了,接下来是invocationStubManager.injectAll()
:
void injectAll() throws Throwable {
for (IInjector injector : mInjectors.values()) {
injector.inject();
}
// XXX: Lazy inject the Instrumentation,
addInjector(AppInstrumentation.getDefault());
}
其实就是一个遍历,对每个添加的Injectors执行对应的inject()
,注意最后,对于Instrumentation这个类执行的是一个懒注入,因为这个类设计application和activity生命周期的跟踪测试。那么继续来看ActivityManagerStub的inject()
方法:
public void inject() throws Throwable {
if (BuildCompat.isOreo()) {
//Android Oreo(8.X)
Object singleton = ActivityManagerOreo.IActivityManagerSingleton.get();
Singleton.mInstance.set(singleton, getInvocationStub().getProxyInterface());
} else {
if (ActivityManagerNative.gDefault.type() == IActivityManager.TYPE) {
ActivityManagerNative.gDefault.set(getInvocationStub().getProxyInterface());
} else if (ActivityManagerNative.gDefault.type() == Singleton.TYPE) {
Object gDefault = ActivityManagerNative.gDefault.get();
Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());
}
}
BinderInvocationStub hookAMBinder = new BinderInvocationStub(getInvocationStub().getBaseInterface());
hookAMBinder.copyMethodProxies(getInvocationStub());
ServiceManager.sCache.get().put(Context.ACTIVITY_SERVICE, hookAMBinder);
}
首先是ActivityManagerNative.gDefault获取AMN的实例对象,然后getInvocationStub().getProxyInterface()获取代理对象的接口对象,进行设置;
接下来getInvocationStub().getBaseInterface()获取的原始接口对象,作为参数传入,新建一个BinderInvocationStub对象,这里面就完成了method代理的添加,最后调用BinderInvocationStub对象hookAMBinder的的copyMethodProxies()
方法,将所有的方法代理添加到MethodInvocationStub的Map表中。
至此,InvocationStubManager的工作就全部结束了(to-do:hook的具体实现),VA的初始化工作也全部完成了,接下来我们继续看oncreate()
方法:
public void onCreate() {
gApp = this;
super.onCreate();
VirtualCore virtualCore = VirtualCore.get();
virtualCore.initialize(new VirtualCore.VirtualInitializer() {
@Override
public void onMainProcess() {
Once.initialise(VApp.this);
new FlurryAgent.Builder()
.withLogEnabled(true)
.withListener(() -> {
// nothing
})
.build(VApp.this, "48RJJP7ZCZZBB6KMMWW5");
}
@Override
public void onVirtualProcess() {
//listener components
virtualCore.setComponentDelegate(new MyComponentDelegate());
//fake phone imei,macAddress,BluetoothAddress
virtualCore.setPhoneInfoDelegate(new MyPhoneInfoDelegate());
//fake task description's icon and title
virtualCore.setTaskDescriptionDelegate(new MyTaskDescriptionDelegate());
}
@Override
public void onServerProcess() {
virtualCore.setAppRequestListener(new MyAppRequestListener(VApp.this));
virtualCore.addVisibleOutsidePackage("com.tencent.mobileqq");
virtualCore.addVisibleOutsidePackage("com.tencent.mobileqqi");
virtualCore.addVisibleOutsidePackage("com.tencent.minihd.qq");
virtualCore.addVisibleOutsidePackage("com.tencent.qqlite");
virtualCore.addVisibleOutsidePackage("com.facebook.katana");
virtualCore.addVisibleOutsidePackage("com.whatsapp");
virtualCore.addVisibleOutsidePackage("com.tencent.mm");
virtualCore.addVisibleOutsidePackage("com.immomo.momo");
}
});
}
首先还是通过VirtualCore.get()
获取VirtualCore静态对象virtualCore,然后调用VirtualCore.VirtualInitializer()
初始化四种进程类型的情况:
Once.initialise(VApp.this)
进行初始化操作; 至此,VA的Application启动过程就分析完成。