上一章:Android 双开沙箱 VirtualApp 源码分析(五)BroadcastReceiver
Provider 注册
回顾前面,Activity 启动的时候会检查 Application 是否初始化,会调用 bindApplication,里面执行了安装 Provider 的方法:
private void installContentProviders(Context app, List<ProviderInfo> providers) {
long origId = Binder.clearCallingIdentity();
Object mainThread = VirtualCore.mainThread();
try {
for (ProviderInfo cpi : providers) {
if (cpi.enabled) {
ActivityThread.installProvider(mainThread, app, cpi, null);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
这里很简单,调用 ActivityThread.installProvider() 注册就这么完成了。
但是,仔细一想事情没那么简单,按照这个逻辑 ContentProvider 是在 Application 启动的时候注册的,那么如果 Application 没有启动,那么自然就没有注册了,这样的话其他 App 怎么找到 Provider 呢?
Activity 是因为有在 VA 的 Menifest 里注册的 StubActivity,这样启动 StubActivity 自然就启动了在“:p(n)”进程。那么对应的,VA 用了 StubContentProvider 么?确实是有的。
但是请不要误会了,这个注册在 “p(n)”进程的 StubContentProvider(继承自 StubContentProvider 的 C1,C2,Cn……) 并不是 StubActivity 那样的为了给插件 Provider 占坑的 Stub 组件。
StubContentProvider 的真正目的是为了让 AMS 通过 system_process 带起 “p(n)”进程,然后 VAMS 用过远程调用 StubProvider.call() 回插件 IClient 的 IBinder 句柄给 VAMS 持有。这样 VAMS 就可以远程调用插件进程 “p(n)”中的方法了。
事实上在前面第二张 App 启动时就有说过相关内容,但是为了避免大家误解还是有必要重复一下。
public class StubContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
}
@Override
public Bundle call(String method, String arg, Bundle extras) {
if ("_VA_|_init_process_".equals(method)) {
return initProcess(extras);
}
return null;
}
private Bundle initProcess(Bundle extras) {
ConditionVariable lock = VirtualCore.get().getInitLock();
if (lock != null) {
lock.block();
}
IBinder token = BundleCompat.getBinder(extras,"_VA_|_binder_");
int vuid = extras.getInt("_VA_|_vuid_");
VClientImpl client = VClientImpl.get();
client.initProcess(token, vuid);
Bundle res = new Bundle();
BundleCompat.putBinder(res, "_VA_|_client_", client.asBinder());
res.putInt("_VA_|_pid_", Process.myPid());
return res;
}
getContentProvider
这里依然 Hook 了 getContentProvider 方法:
static class GetContentProvider extends MethodProxy {
@Override
public String getMethodName() {
return "getContentProvider";
}
@Override
public Object call(Object who, Method method, Object... args) throws Throwable {
int nameIdx = getProviderNameIndex();
String name = (String) args[nameIdx];
int userId = VUserHandle.myUserId();
// 远程调用 VPMS 从 VPackage 拿到 ProviderInfo
ProviderInfo info = VPackageManager.get().resolveContentProvider(name, 0, userId);
// 拿不到说明目标 App 未启动
if (info != null && info.enabled && isAppPkg(info.packageName)) {
// 远程调用 VAMS,然后 VAMS 再通过 AMS 远程调用注册在插件进程的 StubContentProvider.call 初始化插件进程
int targetVPid = VActivityManager.get().initProcess(info.packageName, info.processName, userId);
if (targetVPid == -1) {
return null;
}
args[nameIdx] = VASettings.getStubAuthority(targetVPid);
Object holder = method.invoke(who, args);
if (holder == null) {
return null;
}
// ContentProviderHolder 有两个成员变量provider、connection,provider 是目标 Provider 的 IBinder 句柄。
// connection 则是 callback
if (BuildCompat.isOreo()) {
IInterface provider = ContentProviderHolderOreo.provider.get(holder);
if (provider != null) {
// 这里是重点,远程调用了 VAMS 的 acquireProviderClient
provider = VActivityManager.get().acquireProviderClient(userId, info);
}
ContentProviderHolderOreo.provider.set(holder, provider);
ContentProviderHolderOreo.info.set(holder, info);
} else {
IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);
if (provider != null) {
provider = VActivityManager.get().acquireProviderClient(userId, info);
}
IActivityManager.ContentProviderHolder.provider.set(holder, provider);
IActivityManager.ContentProviderHolder.info.set(holder, info);
}
return holder;
}
Object holder = method.invoke(who, args);
if (holder != null) {
if (BuildCompat.isOreo()) {
IInterface provider = ContentProviderHolderOreo.provider.get(holder);
info = ContentProviderHolderOreo.info.get(holder);
if (provider != null) {
provider = ProviderHook.createProxy(true, info.authority, provider);
}
ContentProviderHolderOreo.provider.set(holder, provider);
} else {
IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);
info = IActivityManager.ContentProviderHolder.info.get(holder);
if (provider != null) {
provider = ProviderHook.createProxy(true, info.authority, provider);
}
IActivityManager.ContentProviderHolder.provider.set(holder, provider);
}
return holder;
}
return null;
}
public int getProviderNameIndex() {
return 1;
}
@Override
public boolean isEnable() {
return isAppProcess();
}
}
这里主要做了几件事情:
- 通过 VPMS 拿到解析好的目标 ProviderInfo,启动目标 Provider 所在的进程,怎么启动?远程调用 VAMS,然后 VAMS 再通过 AMS 远程调用注册在插件进程的 StubContentProvider.call 初始化插件进程。这时候 VAMS 就会持有目标插件进程的 IClient 句柄,以备后续调用。
- 准备 ContentProviderHolder 相关的事情,ContentProviderHolder 有两个成员变量provider、connection,provider 是目标 Provider 的 IBinder 句柄。
- 远程调用了 VAMS 的 acquireProviderClient(), 将任务抛给了远端的 VAMS。
下面就来看一下 VAMS.acquireProviderClient()
@Override
public IBinder acquireProviderClient(int userId, ProviderInfo info) {
ProcessRecord callerApp;
synchronized (mPidsSelfLocked) {
callerApp = findProcessLocked(VBinder.getCallingPid());
}
if (callerApp == null) {
throw new SecurityException("Who are you?");
}
String processName = info.processName;
ProcessRecord r;
synchronized (this) {
r = startProcessIfNeedLocked(processName, userId, info.packageName);
}
if (r != null && r.client.asBinder().isBinderAlive()) {
try {
return r.client.acquireProviderClient(info);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return null;
}
可以看到调用了 r.client.acquireProviderClient(info);
r.client 就是前面 initProcess 的时候保存下来的插件进程的 IClient 句柄,那么等于远程调用到了插件的 VClientImpl.acquireProviderClient():
注意现在开始流程是在目标 Provider 的 Client App 进程中
@Override
public IBinder acquireProviderClient(ProviderInfo info) {
if (mTempLock != null) {
mTempLock.block();
}
// 这里检查 Application 是否启动,注意注册 Provider 的逻辑也在里面
if (!isBound()) {
VClientImpl.get().bindApplication(info.packageName, info.processName);
}
// 准备 ContentProviderClient
IInterface provider = null;
String[] authorities = info.authority.split(";");
String authority = authorities.length == 0 ? info.authority : authorities[0];
ContentResolver resolver = VirtualCore.get().getContext().getContentResolver();
ContentProviderClient client = null;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
client = resolver.acquireUnstableContentProviderClient(authority);
} else {
client = resolver.acquireContentProviderClient(authority);
}
} catch (Throwable e) {
e.printStackTrace();
}
if (client != null) {
// 反射获取 provider
provider = mirror.android.content.ContentProviderClient.mContentProvider.get(client);
client.release();
}
return provider != null ? provider.asBinder() : null;
}
这里终于看到了调用 bindApplication 的地方,如果 provider 尚未注册,那么这里将会注册 provider。
最终通过反射 android.content.ContentProviderClient.mContentProvider 获取到了目标 provider 的句柄,然后 provider 沿着目标 Client App 进程——> VAMS 进程 ———-> 回到了调用 Client App 进程中,整个获取 provider 的过程正式完成。
到此,四大组件的代理全部完成,本次分析也基本结束,下一章会写一些总结和补充内容。