virtualapp启动流程源码分析

virtualapp启动流程分析

1. 首先是启动本身,执行Vpp 的attachBaseContext

    @Override
    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);

    public void startup(Context context) throws Throwable {
        if (!isStartUp) {
......
            detectProcessType();
            InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
            invocationStubManager.init();
            invocationStubManager.injectAll();
            ContextFixer.fixContext(context);
            isStartUp = true;
......
        }
    }

这里最主要的是实例化了invocationStubManager ,并开启注入(injectAll),

public void init() throws Throwable {
		if (isInit()) {
			throw new IllegalStateException("InvocationStubManager Has been initialized.");
		}
		injectInternal();
		sInit = true;

	}

	private void injectInternal() throws Throwable {
		if (VirtualCore.get().isMainProcess()) {
			return;
		}
		......
	}

由于当前我们是主进程,所以这里注入是啥也没干

2. 然后进入APP 的主Activity(SplashActivity)

    protected void onCreate(Bundle savedInstanceState) {
        @SuppressWarnings("unused")
        boolean enterGuide = !Once.beenDone(Once.THIS_APP_INSTALL, VCommends.TAG_NEW_VERSION);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        VUiKit.defer().when(() -> {
            if (!Once.beenDone("collect_flurry")) {
                FlurryROMCollector.startCollect();
                Once.markDone("collect_flurry");
            }
            long time = System.currentTimeMillis();
            doActionInThread();
            time = System.currentTimeMillis() - time;
            long delta = 3000L - time;
            if (delta > 0) {
                VUiKit.sleep(delta);
            }
        }).done((res) -> {
            HomeActivity.goHome(this);
            finish();
        });
    }
	
    private void doActionInThread() {
        if (!VirtualCore.get().isEngineLaunched()) {
            VirtualCore.get().waitForEngine();
        }
    }

在这里异步执行了doActionInThread,也就是执行了waitForEngine,这一步很重要,在这里会开启另一个进程

    public void waitForEngine() {
        ServiceManagerNative.ensureServerStarted();
    }

ServiceManagerNative.java

    public static String SERVICE_CP_AUTH = "virtual.service.BinderProvider";
......
    public static void ensureServerStarted() {
        new ProviderCall.Builder(VirtualCore.get().getContext(), SERVICE_CP_AUTH).methodName("ensure_created").call();
    }

ProviderCall.java

	public static Bundle call(String authority, Context context, String method, String arg, Bundle bundle) {
		Uri uri = Uri.parse("content://" + authority);
		return ContentProviderCompat.call(context, uri, method, arg, bundle);
	}

最终会构造出一个uri: virtual.service.BinderProvider, 并启动这个Provider

ContentProviderCompat.java

    public static Bundle call(Context context, Uri uri, String method, String arg, Bundle extras) {
        if (VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return context.getContentResolver().call(uri, method, arg, extras);
        }
        ContentProviderClient client = crazyAcquireContentProvider(context, uri);
        Bundle res = null;
        try {
            res = client.call(method, arg, extras);
        } catch (RemoteException e) {
            e.printStackTrace();
        } finally {
            releaseQuietly(client);
        }
        return res;
    }
	......

    private static ContentProviderClient acquireContentProviderClient(Context context, Uri uri) {
        if (VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return context.getContentResolver().acquireUnstableContentProviderClient(uri);
        }
        return context.getContentResolver().acquireContentProviderClient(uri);
    }

也就是最终使用context.getContentResolver().acquireContentProviderClient 获得一个client引用,并执行他的client.call(method, arg, extras);,经上面分析method的值为ensure_created,
这里的目的就是为了唤醒这个BinderProvider
查看它在AndroidManifest.xml中的配置

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

<string name="engine_process_name">:x</string>
那么它是存在另一个进程中的,那么根据命名规则,该进程名会是io.virtualapp:x

也就是说现在有两个进程了
主进程
io.virtualapp

服务进程
io.virtualapp:x

2. 服务进程启动流程

由于provider的启动,那么流程又会走到VApp中,在这个进程中走attachBaseContextVirtualCore.get().startup(base);

然后同样的走

            InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
            invocationStubManager.init();
            invocationStubManager.injectAll();

InvocationStubManager.java

	private void injectInternal() throws Throwable {
	....
		if (VirtualCore.get().isServerProcess()) {
		addInjector(new ActivityManagerStub());
		addInjector(new PackageManagerStub());
		return;
		....
	}

	void injectAll() throws Throwable {
		for (IInjector injector : mInjectors.values()) {
			injector.inject();
		}
		// XXX: Lazy inject the Instrumentation,
		addInjector(AppInstrumentation.getDefault());
	}

在这里会hook掉ActivityManager 和PackageManager

先查看PackageManager 的hooker PackageManagerStub
@Inject(MethodProxies.class)
public final class PackageManagerStub extends MethodInvocationProxy<MethodInvocationStub<IInterface>> {

    public PackageManagerStub() {
        super(new MethodInvocationStub<>(ActivityThread.sPackageManager.get()));
    }

    @Override
    protected void onBindMethods() {
        super.onBindMethods();
        addMethodProxy(new ResultStaticMethodProxy("addPermissionAsync", true));
        addMethodProxy(new ResultStaticMethodProxy("addPermission", true));
        addMethodProxy(new ResultStaticMethodProxy("performDexOpt", true));
        addMethodProxy(new ResultStaticMethodProxy("performDexOptIfNeeded", false));
        addMethodProxy(new ResultStaticMethodProxy("performDexOptSecondary", true));
        addMethodProxy(new ResultStaticMethodProxy("addOnPermissionsChangeListener", 0));
        addMethodProxy(new ResultStaticMethodProxy("removeOnPermissionsChangeListener", 0));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            addMethodProxy(new ResultStaticMethodProxy("checkPackageStartable", 0));
        }
        if (BuildCompat.isOreo()) {
            addMethodProxy(new ResultStaticMethodProxy("notifyDexLoad", 0));
            addMethodProxy(new ResultStaticMethodProxy("notifyPackageUse", 0));
            addMethodProxy(new ResultStaticMethodProxy("setInstantAppCookie", false));
            addMethodProxy(new ResultStaticMethodProxy("isInstantApp", false));
        }

    }

    @Override
    public void inject() throws Throwable {
        final IInterface hookedPM = getInvocationStub().getProxyInterface();
        ActivityThread.sPackageManager.set(hookedPM);
        BinderInvocationStub pmHookBinder = new BinderInvocationStub(getInvocationStub().getBaseInterface());
        pmHookBinder.copyMethodProxies(getInvocationStub());
        pmHookBinder.replaceService("package");
    }

    @Override
    public boolean isEnvBad() {
        return getInvocationStub().getProxyInterface() != ActivityThread.sPackageManager.get();
    }
}

这里就是创建了一个PackageManager 的一个代理, 通过Java动态代理的方式,并通过反射写回到ActivityThread.sPackageManager中,实现这个对象的代理,走到我们自己对象中

然后走到BinderProvider的onCreate中
    @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;
    }

BinderProvideronCreate方法,在其中启动后台的DaemonService,保持:x进程不被系统杀死。然后初始化各个模拟的系统服务,如VPackageManagerService、VUserManagerService、VActivityManagerService、VAppManagerService、VNotificationManagerService、VAccountManagerService等,并注册到ServiceCache中
最终通过 IServiceFetcher.aidl 实现rpc通信,实现客户端进程来服务端访问数据

IServiceFetcher.Stub 的实现在BinderProvider.java 中

    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);
            }
        }
    }
从这里可以看出, 当调用getService 时,实际时从ServiceCache中访问之前注册的service
那么客户端如何获得Fetcher呢

BinderProvider.java

    @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;
    }
当客户段通过BinderProvider 并调用方法名为"@"时,会返回mServiceFetcher,并通过

sFetcher = IServiceFetcher.Stub.asInterface(binder); 创建客户端的interface,具体可以参考
ServiceManagerNative.java 的以下方法

    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;
    }

客户段通过这个Fetcher来访问服务端的各个服务,而各个服务都是封装成了TransformBinder 对象,TransformBinder 继承于Binder, 可通过RPC进行通信

至此virtual app 启动完毕

posted @ 2023-04-25 18:56  明月照江江  阅读(315)  评论(0编辑  收藏  举报