• 最近在看安卓的应用级虚拟化的架构 这一章我们先来说一下大致架构 大致框架是这样的 host 主进程,va server 进程 和各个 client进程。这里host主进程就可以看作vritual app本身 ,然后vaserverkey看作虚拟机内部的一个framwork 架构 。后门就是各个client 进程 而因为我们的虚拟机内部没有 service manager进程来要负责 Binder 服务的注册、查询和管理。所以我们还需要自己实现一个类似的结构

构建一个类似service manager的服务

首先我们先抛开binder的底层机制,我们需要明白,如果一个进程要通过binder调用另一个进程,那么这个进程就要获取到他的ibinder 我们一层一层往下看

binderprovider

继承自组件contentprovider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package com.lody.virtual.server;

import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;

import com.lody.virtual.client.core.VirtualCore;
import com.lody.virtual.client.ipc.ServiceManagerNative;
import com.lody.virtual.client.stub.KeepAliveService;
import com.lody.virtual.helper.compat.BundleCompat;
import com.lody.virtual.helper.compat.NotificationChannelCompat;
import com.lody.virtual.server.accounts.VAccountManagerService;
import com.lody.virtual.server.am.VActivityManagerService;
import com.lody.virtual.server.content.VContentService;
import com.lody.virtual.server.device.VDeviceManagerService;
import com.lody.virtual.server.interfaces.IServiceFetcher;
import com.lody.virtual.server.job.VJobSchedulerService;
import com.lody.virtual.server.location.VirtualLocationService;
import com.lody.virtual.server.notification.VNotificationManagerService;
import com.lody.virtual.server.pm.VAppManagerService;
import com.lody.virtual.server.pm.VPackageManagerService;
import com.lody.virtual.server.pm.VUserManagerService;
import com.lody.virtual.server.vs.VirtualStorageService;

/**
* @author Lody
*/
public final class BinderProvider extends ContentProvider {

private final ServiceFetcher mServiceFetcher = new ServiceFetcher();
private static boolean sInitialized = false;

@Override
public boolean onCreate() {
return init();
}

public static boolean isInitialized() {
return sInitialized;
}

private boolean init() {
if (sInitialized) {
return false;
}
Context context = getContext();
if (context != null) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannelCompat.checkOrCreateChannel(context, NotificationChannelCompat.DAEMON_ID, "daemon");
NotificationChannelCompat.checkOrCreateChannel(context, NotificationChannelCompat.DEFAULT_ID, "default");
}
try {
context.startService(new Intent(context, KeepAliveService.class));
} catch (Exception e) {
e.printStackTrace();
}
}

if (!VirtualCore.get().isStartup()) {
return false;
}
VPackageManagerService.systemReady();
addService(ServiceManagerNative.PACKAGE, VPackageManagerService.get());
addService(ServiceManagerNative.ACTIVITY, VActivityManagerService.get());
addService(ServiceManagerNative.USER, VUserManagerService.get());
VAppManagerService.systemReady();
addService(ServiceManagerNative.APP, VAppManagerService.get());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
addService(ServiceManagerNative.JOB, VJobSchedulerService.get());
}
VNotificationManagerService.systemReady(context);
addService(ServiceManagerNative.NOTIFICATION, VNotificationManagerService.get());
VAppManagerService.get().scanApps();
VAccountManagerService.systemReady();
VContentService.systemReady();
addService(ServiceManagerNative.ACCOUNT, VAccountManagerService.get());
addService(ServiceManagerNative.CONTENT, VContentService.get());
addService(ServiceManagerNative.VS, VirtualStorageService.get());
addService(ServiceManagerNative.DEVICE, VDeviceManagerService.get());
addService(ServiceManagerNative.VIRTUAL_LOC, VirtualLocationService.get());
sInitialized = true;
return true;
}

private void addService(String name, IBinder service) {
ServiceCache.addService(name, service);
}

@Override
public Bundle call(String method, String arg, Bundle extras) {
if (!sInitialized) {
init();
}
if ("@".equals(method)) {
Bundle bundle = new Bundle();
BundleCompat.putBinder(bundle, "_VA_|_binder_", mServiceFetcher);
return bundle;
}
return null;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}

@Override
public String getType(Uri uri) {
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}

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

我们稍后会讲解几个结构首先这个ServiceFetcher,是作为调用的接口,通过控制ServiceCache 控制和调用服务。至于什么服务,其实就是server 提供的一些类似于 安卓系统级的binder服务。 因为contentprovider 的call 是通过ams管理并能够被外部通过contentresover调用的. 所以我们还需要在 app 的mainfest专门写注册代码以便ams发现并管理

1
2
3
4
5
6
7
8
    <!-- lib/src/main/AndroidManifest.xml:381-386 -->
<provider
android:name="com.lody.virtual.server.BinderProvider" ← 类
android:authorities="${AUTHORITY_PREFIX}.virtual.service.BinderProvider" ← 唯一标识
android:exported="true" ← 允许跨 uid
android:permission="${PERMISSION_PREFIX}.permission.SAFE_ACCESS" ← 签名级准入
android:process="@string/engine_process_name" /> ← 承载进程 :x

根据前面的代码private class ServiceFetcher extends IServiceFetcher.Stub 他继承的IServiceFetcher.Stub 本身就是一个ibinder对象,所以我们就只需要在call函数返回bundle

1
2
3
Bundle bundle = new Bundle();
BundleCompat.putBinder(bundle, "_VA_|_binder_", mServiceFetcher);
return bundle;

里面存放ibinder就是mServiceFetcher

ServiceFetcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
}
}
}

这个类主要来自于IServiceFetcher接口结合stub静态类.stub是作为binder 的server 的服务端的接口.在这里是

1
2
3
4
5
6
7
8
9
10
public static abstract class Stub extends android.os.Binder implements com.lody.virtual.server.interfaces.IServiceFetcher  
{
/** Construct the stub at attach it to the interface. */
@SuppressWarnings("this-escape")
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.lody.virtual.server.interfaces.IServiceFetcher interface, * generating a proxy if needed. */ public static

这几个操作就是在操作serviceCache这个hashmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ServiceCache {

private static final Map<String, IBinder> sCache =
new ArrayMap<>(5);

public static void addService(String name, IBinder service) {
sCache.put(name, service);
}

public static IBinder removeService(String name) {
return sCache.remove(name);
}

public static IBinder getService(String name) {
return sCache.get(name);
}
}

实现如下,这个service cache的存储的就是ibinder而这个ibinder就是client app真正要从server获取的服务.还有一点怎么把我们的这些服务编程ibinder呢? 原开源版本中使用的是一个ipcbus类,但是他要使用反射调用函数.获取每个类的函数对应的code(按顺序编码),因为ibinder本身是通过这些code调用的 这些方法,所以我们要用code。bug挖个坑,后门我们详细讲一讲安卓的binder 但是其实这么没有直接用 aidl来的方便,所以还是直接通过 类似与前面直接用继承一个

1
public class VAccountManagerService extends IAccountManager.Stub

这个类本身就是一个ibinder的形式.

host

host进程就是宿主app这个进程本身,启动的时候为后续server的执行做准备,执行的时候运行ui和 监听安装广播

server

前面我们讲到,ServiceCache 里注册了 11 个服务,而注册这个动作发生在 BinderProvider.init() 里。那问题就来了:这 11 个服务是干什么的?除了服务,server 还提供了别的东西吗?

lib/src/main/java/com/lody/virtual/server/ 这个目录,一共 22,502 行、13 个子包。我们把它拆成三块来看:服务、组件,以及它们怎么配合。

server 提供了哪些服务

先看表格,这 11 个就是 ServiceCache 里存着的东西:

服务名 实现类 模拟的系统服务 主要职责
package VPackageManagerService PackageManager 虚拟包表查询、组件解析、权限/签名
activity VActivityManagerService ActivityManager 进程池、Activity 栈、Service 绑定
user VUserManagerService UserManager 虚拟用户管理(多开的基础)
app VAppManagerService —— 安装、卸载、扫描
account VAccountManagerService AccountManager 账户、认证器、token
content VContentService ContentService ContentObserver、Sync
job VJobSchedulerService JobScheduler Job 调度隔离
notification VNotificationManagerService NotificationManager 通知 id/tag 改写
vs VirtualStorageService —— 虚拟 SD 卡映射
device VDeviceManagerService —— 设备指纹
virtual-loc VirtualLocationService LocationManager 虚拟定位

里面最重的是 activity,54 个 AIDL 方法,1,271 行——因为我们没有真的 AMS,进程怎么起、Activity 栈怎么管、Service 怎么绑,全得自己写。其次是 package(34 个方法)和 account(35 个方法)。

这里有个细节值得单独说一句:这些服务类本身都是 Binder。比如:

java

1
2
public class VActivityManagerService extends IActivityManager.Stub { ... }
public class VPackageManagerService extends IPackageManager.Stub { ... }

IXxx.Stub 继承自 android.os.Binder,所以服务实例天生就是 IBinder,直接 addService(name, service) 扔进 ServiceCache 就行。这也是为什么前面说"换回 AIDL 比 ipcbus 省事"——AIDL 编译出来的 Stub 天然满足"可跨进程 + 可当接口用"两个条件,不需要运行时反射再包一层。

server提供组件

光有服务还不够。

服务是给"我们自己人"用的——客户端的 VActivityManager 通过 Binder 找到它。但系统不会调用服务,系统只认 virtualapp本身在manifest 里声明的组件。虚拟应用的组件在系统里根本不存在,所以凡是"系统要回调 VA"的场景,都必须有一个真实存在的组件顶上去。

于是就有了这些组件。lib 模块的 :x 进程里一共 16 个,按 Android 四大组件分类:

Activity(8 个)

组件 干什么
ShadowPendingActivity 接住虚拟应用的 PendingIntent.getActivity()
ShortcutHandleActivity 桌面快捷方式点进来的跳板
ChooserActivity 顶替 Intent.createChooser() 的分享面板
ResolverActivity 顶替隐式 Intent 的"用哪个应用打开"
ChooseAccountTypeActivity 账户类型选择
ChooseTypeAndAccountActivity 账户选择
WindowPreviewActivity 启动前显示窗口背景预览(防止白屏)
RequestPermissionsActivity 替虚拟应用弹运行时权限

Service(5 个)

组件 干什么
KeepAliveService 保活,START_STICKY
HiddenForeNotification 显示一个隐藏的前台通知,提高 :x 优先级
ShadowPendingService 接住 PendingIntent.getService()
ShadowJobService 虚拟应用 JobService 的系统侧入口
ShadowJobWorkService Job 真正执行的地方

Provider(2 个)

组件 干什么
BinderProvider 服务注册表入口,call("@") 返回 IServiceFetcher
ContentProviderProxy 虚拟应用 Provider 的请求转发

Receiver(1 个)

组件 干什么
ShadowPendingReceiver 接住 PendingIntent.getBroadcast()

这些组件按用途其实分三类:

  1. 虚拟应用的代理——就是 :p0..:p99 里那 399 个槽位组件(ShadowActivity$Pn 之类)。系统只认组件名,所以每个虚拟应用进程都得有一个合法名字顶着。
  2. 系统 API 的回调接收器——比如 PendingIntent、JobScheduler、选择器这些 API,系统要求目标组件必须真实存在,那就用 ShadowPending*、ShadowJob* 去接。
  3. VA 自己用的——BinderProvider(注册表入口)、KeepAliveService、ShortcutHandleActivity(快捷方式)这些。

把它们都放在 :x (server进程)里,是因为这些组件必须比虚拟应用活得久——虚拟应用进程死了,Job 还得能触发,PendingIntent 还得能响,:x 不能跟着挂。

分享: 微博 QQ Telegram X
2026-11-14

⬆︎TOP