前言
插件化一直是百舸爭流,Small、Replugin、Atlas等方案也是層出不窮,在android開發(fā)呈現(xiàn)百花齊放的感覺。
最近看到了一種新的插件化方案,確切的說更像一種沙盒,名為VirtualApp框架,覺得整個(gè)構(gòu)思和以往的都有所不同。因此在細(xì)細(xì)品讀完源碼后,產(chǎn)生寫下自己的體會(huì)和想法。
源于啟動(dòng)
我們從主進(jìn)程(io.virtualapp)的application開始解析
ps:代碼塊只會(huì)截取關(guān)鍵代碼,其他用...替代
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
...
try {
VirtualCore.get().startup(base);
} catch (Throwable e) {
e.printStackTrace();
}
}
可以看到主要是attachBaseContext中調(diào)用了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中調(diào)用了virtualCore的initialize方法注冊了一個(gè)VirtualInitializer的callback,用來處理不同進(jìn)程的初始化邏輯。
VirtualCore.startup
這里核心是VirtualCore.startup的方法,我們進(jìn)入到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分別對應(yīng)的是用來啟動(dòng)虛擬VAppProcess和ServerProcess進(jìn)程的ContentProvider,mainThread是通過反射獲取的ActivityThread的實(shí)例,然后是IPCBus進(jìn)行初始化以及判斷現(xiàn)在進(jìn)程的類型(detectProcessType),最后是通過InvocationStubManager來完成對這個(gè)進(jìn)程的系統(tǒng)服務(wù)的BinderProxy的hook。
這里最主要的是IPCBus和InvocationStubManager,我們先來說下IPCBus,這是虛擬app進(jìn)程和ServerProcess進(jìn)程通信的核心。
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主要有兩個(gè)方法register和get,register方法根據(jù)傳入的class對象構(gòu)造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構(gòu)造函數(shù)里面通過反射獲取methods然后再根據(jù)Binder.FIRST_CALL_TRANSACTION的自增去構(gòu)造IPCMethod實(shí)例(這個(gè)類后面會(huì)講到通過反射進(jìn)行方法調(diào)用并將結(jié)果通過Parcel進(jìn)行回傳),
接著通過鍵值code,method將IPCMethod存儲(chǔ)在兩個(gè)Map中。
TransformBinder
ServerInterface實(shí)例構(gòu)造完成后,再和傳入的server實(shí)例對象構(gòu)造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方法,我們知道這個(gè)方法通常是在IPC通信中接收消息然后進(jìn)行回傳處理的地方。在這里我們又看到了IPCMethod,是通過code從ServerInterface中獲取,跟前面的serverInterface構(gòu)造就對應(yīng)起來了,然后調(diào)用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);
}
}
我們跟蹤這個(gè)方法進(jìn)去看到,果然就是反射調(diào)用在IPCMethod的method,并且將結(jié)果通過reply寫會(huì)請求進(jìn)程完成IPC通信。
這樣我們再回到IPCBus中的register方法中,在構(gòu)造完這個(gè)TransformBinder后調(diào)用ServiceCache.addService方法進(jìn)行存儲(chǔ)。
我們再回到IPCBus中的get(Class<?> interfaceClass)方法,那其實(shí)就是調(diào)用ServiceManagerNative.getService()的方法獲取IBinder對象,并且返回interfaceClass的proxy類。
我們再跟蹤進(jìn)去看下IPCInvocationBridge這個(gè)類干了什么
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,然后調(diào)用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;
}
這個(gè)方法主要就是發(fā)起一次IPC請求,傳入需要調(diào)用的類名稱(interfaceName),參數(shù)(args),對應(yīng)的方法(code),然后通過IBinder的transact進(jìn)行IPC調(diào)用。
到這里我們其實(shí)可以發(fā)現(xiàn)這和前面提到的handleTransact方法對應(yīng)起來,一個(gè)是請求,一個(gè)是應(yīng)答處理。
我們再次回到IPCBus的get(Class<?> interfaceClass)方法,那其實(shí)這里的IBinder應(yīng)該就是TransformBinder在調(diào)用進(jìn)程的BinderProxy,其他進(jìn)程通過get方法獲取BinderProxy來向TransformBinder所在的進(jìn)程發(fā)送IPC調(diào)用。
到了這里大家可能會(huì)一頭霧水,別急我們?nèi)タ聪聅Cache.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進(jìn)程直接返回保存在ServiceCache的TransformBinder,如果其他進(jìn)程調(diào)用getServiceFetcher,再通過其getService進(jìn)行返回。
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方法主要是啟動(dòng)一個(gè)virtual.service.BinderProvider的ContentProvider并且調(diào)用"@"方法。
<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這個(gè)類主要作用。
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就啟動(dòng)了ServerProcess進(jìn)程,在這個(gè)進(jìn)程里面我們看到通過BinderProvider的onCreate方法調(diào)用了大量的IPCBus.register方法把一系列的VPackageManagerService等對應(yīng)的TransformBinder保存了在這個(gè)ServerProcess進(jìn)程的ServiceCache中。
我們再來看call方法,返回了一個(gè)ServiceFetcher通過鍵值"VA|binder"進(jìn)行存儲(chǔ)的Bundle。
我們再回到ServiceManagerNative的getService中,這個(gè)時(shí)候我們就明白了,如果是其他進(jìn)程則先通過getServiceFetcher獲取ServiceFetcher的BinderProxy,然后再調(diào)用getService方法獲取對應(yīng)的TransformBinder在這個(gè)進(jìn)程的BinderProxy,然后通過Proxy去調(diào)用ServerProcess進(jìn)程的對應(yīng)VxxService服務(wù)。這個(gè)時(shí)候其他VAppProcess進(jìn)程跟ServerProcess進(jìn)程的交互就通過這一系列IPCBus,IPCMethod,BinderTransformer等來完成。
整個(gè)流程圖如下:

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,從這里看到主進(jìn)程(io.virtualapp)沒有進(jìn)行hook,ServerProcess(io.virtualapp:x)對AMS以及PMS的BinderProxy進(jìn)行了hook,而VAppProcess則對大量的系統(tǒng)服務(wù)進(jìn)行了hook。
具體的hook是通過MethodInvocationStub,MethodInvocationProxy,MethodProxy這個(gè)基礎(chǔ)框架來完成的,具體的原理也是生成需要hook類的proxy對象通過反射進(jìn)行注入,這里就不在細(xì)說了。整個(gè)封裝的Hook框架是在包名com.lody.virtual.hook下,有興趣的可以自行研讀。
到這里整個(gè)啟動(dòng)流程就差不多完成了,這個(gè)時(shí)候會(huì)啟動(dòng)兩個(gè)進(jìn)程一個(gè)是va的主進(jìn)程(io.virtualapp)通過ui處理安裝和多開app等功能,一個(gè)ServerProcess進(jìn)程虛擬了VxxService10個(gè)服務(wù),來替代android的systemservice進(jìn)程里的服務(wù)來完成和VAppProcess進(jìn)程的交互。
后面會(huì)再解析app的安裝和運(yùn)行原理,分兩篇來寫。