VirtualApp源码分析——(一)VA启动

VirtualApp(以下简称VA)是一个开源的Android app虚拟化引擎,它提供了一个虚拟空间,允许其他应用运行在这个虚拟空间中,实现应用多开(可重复安装)。

在VA中,host应用(VA自身)和client应用(通过VA安装的应用)具有相同的uid
在运行时,一般会包含三个进程:

  • io.virtualapp,主进程,负责VA的用户界面及应用管理;
  • io.virtualapp:x,服务进程,负责系统服务的代理;
  • io.virtual:pXXX,用于运行client应用的进程,应用启动后,进程名更新为应用包名。

用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对象,具体为:

  • MainProcess:直接返回;
  • ServerProcess:添加ActivityManagerStub和PackageManagerStub对象;
  • VAppProcess:添加LibCoreStub、ActivityManagerStub、PackageManagerStub等;

说明:这里注入其实就是完成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()初始化四种进程类型的情况:

  1. 主进程
    先执行Once.initialise(VApp.this)进行初始化操作;
    然后后面一句初始化Flurry SDK,启用日志并调用build方法,两个参数分别为应用和API_Key,用于统计应用使用情况(可忽略)。
  2. 客户端进程
    主要是调用了virtualCore的setComponentDelegate、setPhoneInfoDelegate和setTaskDescriptionDelegate方法,主要是为了设置自己的代理,如在组建的生命周期前后添加一些自己的操作、伪造设备信息等。
  3. 服务进程
    首先是调用了virtualCore的setAppRequestListener方法,伪造了自己的应用请求监听器;
    然后调用了virtualCore的addVisibleOutsidePackage方法,设置包对外部可见。

至此,VA的Application启动过程就分析完成。

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