美文网首页Android开发经验
VirtualApp 框架解析---启动篇

VirtualApp 框架解析---启动篇

作者: Kael_Huang | 来源:发表于2018-12-23 12:05 被阅读0次

    前言

    插件化一直是百舸争流,Small、Replugin、Atlas等方案也是层出不穷,在android开发呈现百花齐放的感觉。
    最近看到了一种新的插件化方案,确切的说更像一种沙盒,名为VirtualApp框架,觉得整个构思和以往的都有所不同。因此在细细品读完源码后,产生写下自己的体会和想法。

    源于启动

    我们从主进程(io.virtualapp)的application开始解析
    ps:代码块只会截取关键代码,其他用...替代

    @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(base);
            ...
            try {
                VirtualCore.get().startup(base);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    

    可以看到主要是attachBaseContext中调用了VirtualCore的startup方法

     @Override
        public void onCreate() {
            ...
            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");
                }
            });
        }
    

    以及在onCreate中调用了virtualCore的initialize方法注册了一个VirtualInitializer的callback,用来处理不同进程的初始化逻辑。

    VirtualCore.startup

    这里核心是VirtualCore.startup的方法,我们进入到startup方法来看下做了哪些事情

    public void startup(Context context) throws Throwable {
            if (!isStartUp) {
                ..
                VASettings.STUB_CP_AUTHORITY = context.getPackageName() + "." + VASettings.STUB_DEF_AUTHORITY;
                ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
                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);
                    }
                });
                detectProcessType();
                InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
                invocationStubManager.init();
                invocationStubManager.injectAll();
                ...
            }
        }
    

    其中VASettings.STUB_CP_AUTHORITY和ServiceManagerNative.SERVICE_CP_AUTH分别对应的是用来启动虚拟VAppProcess和ServerProcess进程的ContentProvider,mainThread是通过反射获取的ActivityThread的实例,然后是IPCBus进行初始化以及判断现在进程的类型(detectProcessType),最后是通过InvocationStubManager来完成对这个进程的系统服务的BinderProxy的hook。
    这里最主要的是IPCBus和InvocationStubManager,我们先来说下IPCBus,这是虚拟app进程和ServerProcess进程通信的核心。

    IPCBus

    public class IPCBus {
    
        private static IServerCache sCache;
    
        public static void initialize(IServerCache cache) {
            sCache = cache;
        }
        ...
        public static void register(Class<?> interfaceClass, Object server) {
            checkInitialized();
            ServerInterface serverInterface = new ServerInterface(interfaceClass);
            TransformBinder binder = new TransformBinder(serverInterface, server);
            sCache.join(serverInterface.getInterfaceName(), binder);
        }
    
        public static <T> T get(Class<?> interfaceClass) {
            checkInitialized();
            ServerInterface serverInterface = new ServerInterface(interfaceClass);
            IBinder binder = sCache.query(serverInterface.getInterfaceName());
            if (binder == null) {
                return null;
            }
            //noinspection unchecked
            return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new IPCInvocationBridge(serverInterface, binder));
        }
    }
    

    IPCBus主要有两个方法register和get,register方法根据传入的class对象构造ServerInterface对象。

    ServerInterface

    public ServerInterface(Class<?> interfaceClass) {
            this.interfaceClass = interfaceClass;
            Method[] methods = interfaceClass.getMethods();
            codeToInterfaceMethod = new SparseArray<>(methods.length);
            methodToIPCMethodMap = new HashMap<>(methods.length);
            for (int i = 0; i < methods.length; i++) {
                int code = Binder.FIRST_CALL_TRANSACTION + i;
                IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClass.getName());
                codeToInterfaceMethod.put(code, ipcMethod);
                methodToIPCMethodMap.put(methods[i], ipcMethod);
            }
        }
    

    ServerInterface构造函数里面通过反射获取methods然后再根据Binder.FIRST_CALL_TRANSACTION的自增去构造IPCMethod实例(这个类后面会讲到通过反射进行方法调用并将结果通过Parcel进行回传),
    接着通过键值code,method将IPCMethod存储在两个Map中。

    TransformBinder

    ServerInterface实例构造完成后,再和传入的server实例对象构造TransformBinder。

    public class TransformBinder extends Binder {
    
        private ServerInterface serverInterface;
        private Object server;
    
        public TransformBinder(ServerInterface serverInterface, Object server) {
            this.serverInterface = serverInterface;
            this.server = server;
        }
    
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            if (code == INTERFACE_TRANSACTION) {
                reply.writeString(serverInterface.getInterfaceName());
                return true;
            }
            IPCMethod method = serverInterface.getIPCMethod(code);
            if (method != null) {
                try {
                    method.handleTransact(server, data, reply);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
    

    从代码可以看到TransformBinder主要的方法是重载了Binder的onTransact方法,我们知道这个方法通常是在IPC通信中接收消息然后进行回传处理的地方。在这里我们又看到了IPCMethod,是通过code从ServerInterface中获取,跟前面的serverInterface构造就对应起来了,然后调用handleTransact方法。

    public void handleTransact(Object server, Parcel data, Parcel reply) {
            data.enforceInterface(interfaceName);
            Object[] parameters = data.readArray(getClass().getClassLoader());
            if (parameters != null && parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {
                    if (converters[i] != null) {
                        parameters[i] = converters[i].convert(parameters[i]);
                    }
                }
            }
            try {
                Object res = method.invoke(server, parameters);
                reply.writeNoException();
                reply.writeValue(res);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                reply.writeException(e);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                reply.writeException(e);
            }
        }
    

    我们跟踪这个方法进去看到,果然就是反射调用在IPCMethod的method,并且将结果通过reply写会请求进程完成IPC通信。
    这样我们再回到IPCBus中的register方法中,在构造完这个TransformBinder后调用ServiceCache.addService方法进行存储。
    我们再回到IPCBus中的get(Class<?> interfaceClass)方法,那其实就是调用ServiceManagerNative.getService()的方法获取IBinder对象,并且返回interfaceClass的proxy类。
    我们再跟踪进去看下IPCInvocationBridge这个类干了什么

    public class IPCInvocationBridge implements InvocationHandler {
        ...
        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
            IPCMethod ipcMethod = serverInterface.getIPCMethod(method);
            if (ipcMethod == null) {
                throw new IllegalStateException("Can not found the ipc method : " + method.getDeclaringClass().getName() + "@" +  method.getName());
            }
            return ipcMethod.callRemote(binder, args);
        }
    }
    

    在重载InvocationHandler的invoke方法中我们又看到了熟悉的serverInterface和IPCMethod,然后调用IPCMethod的callRmote方法。

    public Object callRemote(IBinder server, Object[] args) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            Object result;
            try {
                data.writeInterfaceToken(interfaceName);
                data.writeArray(args);
                server.transact(code, data, reply, 0);
                reply.readException();
                result = readValue(reply);
                if (resultConverter != null) {
                    result = resultConverter.convert(result);
                }
            } finally {
                data.recycle();
                reply.recycle();
            }
            return result;
        }
    

    这个方法主要就是发起一次IPC请求,传入需要调用的类名称(interfaceName),参数(args),对应的方法(code),然后通过IBinder的transact进行IPC调用。
    到这里我们其实可以发现这和前面提到的handleTransact方法对应起来,一个是请求,一个是应答处理。
    我们再次回到IPCBus的get(Class<?> interfaceClass)方法,那其实这里的IBinder应该就是TransformBinder在调用进程的BinderProxy,其他进程通过get方法获取BinderProxy来向TransformBinder所在的进程发送IPC调用。
    到了这里大家可能会一头雾水,别急我们去看下sCache.query也就是ServiceManagerNative.getService(serverName)看看是不是返回的是BinderProxy。

    ServiceManagerNative

    public static IBinder getService(String name) {
            if (VirtualCore.get().isServerProcess()) {
                return ServiceCache.getService(name);
            }
            IServiceFetcher fetcher = getServiceFetcher();
            if (fetcher != null) {
                try {
                    return fetcher.getService(name);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            VLog.e(TAG, "GetService(%s) return null.", name);
            return null;
        }
    

    在这里可以看到如果是ServerProcess进程直接返回保存在ServiceCache的TransformBinder,如果其他进程调用getServiceFetcher,再通过其getService进行返回。

    private static IServiceFetcher getServiceFetcher() {
            if (sFetcher == null || !sFetcher.asBinder().isBinderAlive()) {
                synchronized (ServiceManagerNative.class) {
                    Context context = VirtualCore.get().getContext();
                    Bundle response = new ProviderCall.Builder(context, SERVICE_CP_AUTH).methodName("@").call();
                    if (response != null) {
                        IBinder binder = BundleCompat.getBinder(response, "_VA_|_binder_");
                        linkBinderDied(binder);
                        sFetcher = IServiceFetcher.Stub.asInterface(binder);
                    }
                }
            }
            return sFetcher;
        }
    

    getServiceFetcher方法主要是启动一个virtual.service.BinderProvider的ContentProvider并且调用"@"方法。

     <provider
                android:name="com.lody.virtual.server.BinderProvider"
                android:authorities="${applicationId}.virtual.service.BinderProvider"
                android:exported="false"
                android:process="@string/engine_process_name" />
    

    BinderProvider

    我们再来看看BinderProvider这个类主要作用。

    public final class BinderProvider extends ContentProvider {
    
        private final ServiceFetcher mServiceFetcher = new ServiceFetcher();
    
        @Override
        public boolean onCreate() {
            Context context = getContext();
            DaemonService.startup(context);
            if (!VirtualCore.get().isStartup()) {
                return true;
            }
            VPackageManagerService.systemReady();
            IPCBus.register(IPackageManager.class, VPackageManagerService.get());
            VActivityManagerService.systemReady(context);
            IPCBus.register(IActivityManager.class, VActivityManagerService.get());
            IPCBus.register(IUserManager.class, VUserManagerService.get());
            VAppManagerService.systemReady();
            IPCBus.register(IAppManager.class, VAppManagerService.get());
            BroadcastSystem.attach(VActivityManagerService.get(), VAppManagerService.get());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                IPCBus.register(IJobService.class, VJobSchedulerService.get());
            }
            VNotificationManagerService.systemReady(context);
            IPCBus.register(INotificationManager.class, VNotificationManagerService.get());
            VAppManagerService.get().scanApps();
            VAccountManagerService.systemReady();
            IPCBus.register(IAccountManager.class, VAccountManagerService.get());
            IPCBus.register(IVirtualStorageService.class, VirtualStorageService.get());
            IPCBus.register(IDeviceInfoManager.class, VDeviceManagerService.get());
            IPCBus.register(IVirtualLocationManager.class, VirtualLocationService.get());
            return true;
        }
    
        @Override
        public Bundle call(String method, String arg, Bundle extras) {
            if ("@".equals(method)) {
                Bundle bundle = new Bundle();
                BundleCompat.putBinder(bundle, "_VA_|_binder_", mServiceFetcher);
                return bundle;
            }
            if ("register".equals(method)) {
    
            }
            return null;
        }
        ...
        private class ServiceFetcher extends IServiceFetcher.Stub {
            @Override
            public IBinder getService(String name) throws RemoteException {
                if (name != null) {
                    return ServiceCache.getService(name);
                }
                return null;
            }
    
            @Override
            public void addService(String name, IBinder service) throws RemoteException {
                if (name != null && service != null) {
                    ServiceCache.addService(name, service);
                }
            }
    
            @Override
            public void removeService(String name) throws RemoteException {
                if (name != null) {
                    ServiceCache.removeService(name);
                }
            }
        }
    }
    

    BinderProvider就启动了ServerProcess进程,在这个进程里面我们看到通过BinderProvider的onCreate方法调用了大量的IPCBus.register方法把一系列的VPackageManagerService等对应的TransformBinder保存了在这个ServerProcess进程的ServiceCache中。
    我们再来看call方法,返回了一个ServiceFetcher通过键值"VA|binder"进行存储的Bundle。
    我们再回到ServiceManagerNative的getService中,这个时候我们就明白了,如果是其他进程则先通过getServiceFetcher获取ServiceFetcher的BinderProxy,然后再调用getService方法获取对应的TransformBinder在这个进程的BinderProxy,然后通过Proxy去调用ServerProcess进程的对应VxxService服务。这个时候其他VAppProcess进程跟ServerProcess进程的交互就通过这一系列IPCBus,IPCMethod,BinderTransformer等来完成。
    整个流程图如下:

    进程启动流程图

    InvocationStubManager

    public final class InvocationStubManager {
        ...
        void injectAll() throws Throwable {
            for (IInjector injector : mInjectors.values()) {
                injector.inject();
            }
            // XXX: Lazy inject the Instrumentation,
            addInjector(AppInstrumentation.getDefault());
        }
        ...
        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());
                }
            }
        }
    
        ...
    
        public <T extends IInjector, H extends MethodInvocationStub> H getInvocationStub(Class<T> injectorClass) {
            T injector = findInjector(injectorClass);
            if (injector != null && injector instanceof MethodInvocationProxy) {
                // noinspection unchecked
                return (H) ((MethodInvocationProxy) injector).getInvocationStub();
            }
            return null;
        }
    }
    

    里面最主要的方法就是injectInternal,从这里看到主进程(io.virtualapp)没有进行hook,ServerProcess(io.virtualapp:x)对AMS以及PMS的BinderProxy进行了hook,而VAppProcess则对大量的系统服务进行了hook。
    具体的hook是通过MethodInvocationStub,MethodInvocationProxy,MethodProxy这个基础框架来完成的,具体的原理也是生成需要hook类的proxy对象通过反射进行注入,这里就不在细说了。整个封装的Hook框架是在包名com.lody.virtual.hook下,有兴趣的可以自行研读。
    到这里整个启动流程就差不多完成了,这个时候会启动两个进程一个是va的主进程(io.virtualapp)通过ui处理安装和多开app等功能,一个ServerProcess进程虚拟了VxxService10个服务,来替代android的systemservice进程里的服务来完成和VAppProcess进程的交互。

    后面会再解析app的安装和运行原理,分两篇来写。

    相关文章

      网友评论

        本文标题:VirtualApp 框架解析---启动篇

        本文链接:https://www.haomeiwen.com/subject/plxikqtx.html