Vapp.Java
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();
}
}
attachBaseContext的时候进行startup()加载hook等
public void startup(Context context) throws Throwable {
if (!isStartUp) {
//判断是否为主线程
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
}
VASettings.STUB_CP_AUTHORITY = context.getPackageName() + "." + VASettings.STUB_DEF_AUTHORITY;
ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
this.context = context;
//获取ActivityThread实例
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();
//hook系统类
InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
invocationStubManager.init();
invocationStubManager.injectAll();
//修复权限管理
ContextFixer.fixContext(context);
isStartUp = true;
if (initLock != null) {
initLock.open();
initLock = null;
}
}
}
invocationStubManager.init();
public void init() throws Throwable {
if (isInit()) {
throw new IllegalStateException("InvocationStubManager Has been initialized.");
}
injectInternal();
sInit = true;
}
对 Java 层 framework 的 Hook,将其定位到 VA 伪造 VA framework 上去
private void injectInternal() throws Throwable {
//VA自身的app的进程不需要Hook
if (VirtualCore.get().isMainProcess()) {
return;
}
//VAService 需要 Hook AMS 和 PMS
if (VirtualCore.get().isServerProcess()) {
addInjector(new ActivityManagerStub());
addInjector(new PackageManagerStub());
return;
}
//Client APP 需要 Hook 整个 framework,来使其调用到 VA framework
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());
}
}
}
Vapp.java
public void onCreate() {
gApp = this;
super.onCreate();
VirtualCore virtualCore = VirtualCore.get();
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");
}
});
}
在onCrete方法中加载了安装app的方法在onServerProcess()内的 virtualCore.setAppRequestListener(new MyAppRequestListener(VApp.this));
public void setAppRequestListener(final AppRequestListener listener) {
IAppRequestListener inner = new IAppRequestListener.Stub() {
@Override
public void onRequestInstall(final String path) {
VirtualRuntime.getUIHandler().post(new Runnable() {
@Override
public void run() {
listener.onRequestInstall(path);
}
});
}
@Override
public void onRequestUninstall(final String pkg) {
VirtualRuntime.getUIHandler().post(new Runnable() {
@Override
public void run() {
listener.onRequestUninstall(pkg);
}
});
}
};
try {
getService().setAppRequestListener(inner);
} catch (RemoteException e) {
e.printStackTrace();
}
}
其中listener.onRequestInstall(path);执行的是MyAppRequestListener.onRequestInstall
public void onRequestInstall(String path) {
Toast.makeText(context, "Installing: " + path, Toast.LENGTH_SHORT).show();
InstallResult res = VirtualCore.get().installPackage(path, InstallStrategy.UPDATE_IF_EXIST);
if (res.isSuccess) {
try {
VirtualCore.get().preOpt(res.packageName);
} catch (IOException e) {
e.printStackTrace();
}
if (res.isUpdate) {
Toast.makeText(context, "Update: " + res.packageName + " success!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Install: " + res.packageName + " success!", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "Install failed: " + res.error, Toast.LENGTH_SHORT).show();
}
}
InstallResult res = VirtualCore.get().installPackage(path, InstallStrategy.UPDATE_IF_EXIST);调用到了VirtualCore.installPackage就开始执行安装
VirtualCore.java
public InstallResult installPackage(String apkPath, int flags) {
try {
// 调用远程 VAService
return getService().installPackage(apkPath, flags);
} catch (RemoteException e) {
return VirtualRuntime.crash(e);
}
}
getService()返回的是IAppManager下边是调用过程
private IAppManager getService() {
return singleton.get();
}
private IPCSingleton<IAppManager> singleton = new IPCSingleton<>(IAppManager.class);
public class IPCSingleton<T>
private Class<?> ipcClass;
private T instance;
public IPCSingleton(Class<?> ipcClass) {
this.ipcClass = ipcClass;
}
public T get() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = IPCBus.get(ipcClass);
}
}
}
return instance;
}
}
IAppManager.java
InstallResult installPackage(String path, int flags) throws RemoteException;
在VAppManagerService类中实现
//先于installPackageAsUser安装apk,生成VPackage结构
public synchronized InstallResult installPackage(String path, int flags, boolean notify) {
long installTime = System.currentTimeMillis();
if (path == null) {
return InstallResult.makeFailure("path = NULL");
}
//apk path
File packageFile = new File(path);
if (!packageFile.exists() || !packageFile.isFile()) {
return InstallResult.makeFailure("Package File is not exist.");
}
VPackage pkg = null;
try {
// 进入解析包结构,该结构是可序列化的,为了持久化在磁盘上
pkg = PackageParserEx.parsePackage(packageFile);
} catch (Throwable e) {
e.printStackTrace();
}
if (pkg == null || pkg.packageName == null) {
return InstallResult.makeFailure("Unable to parse the package.");
}
InstallResult res = new InstallResult();
res.packageName = pkg.packageName;
// PackageCache保存了所有的包,试着检查我们是否需要更新。
VPackage existOne = PackageCacheManager.get(pkg.packageName);
PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null;
if (existOne != null) {
if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) {
res.isUpdate = true;
return res;
}
if (!canUpdate(existOne, pkg, flags)) {
return InstallResult.makeFailure("Not allowed to update the package.");
}
res.isUpdate = true;
}
//获得apk安装文件夹
File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName);
//so文件夹
File libDir = new File(appDir, "lib");
if (res.isUpdate) {
FileUtils.deleteDir(libDir);
VEnvironment.getOdexFile(pkg.packageName).delete();
VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL);
}
if (!libDir.exists() && !libDir.mkdirs()) {
return InstallResult.makeFailure("Unable to create lib dir.");
}
// 是否基于系统的 apk 加载,前提是安装过的 apk 并且 dependSystem 开关打开
boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0
&& VirtualCore.get().isOutsideInstalled(pkg.packageName);
if (existSetting != null && existSetting.dependSystem) {
dependSystem = false;
}
//复制so 到 sandbox lib
NativeLibraryHelperCompat.copyNativeBinaries(new File(path), libDir);
//如果不基于系统,一些必要的拷贝工作
if (!dependSystem) {
File privatePackageFile = new File(appDir, "base.apk");
File parentFolder = privatePackageFile.getParentFile();
if (!parentFolder.exists() && !parentFolder.mkdirs()) {
VLog.w(TAG, "Warning: unable to create folder : " + privatePackageFile.getPath());
} else if (privatePackageFile.exists() && !privatePackageFile.delete()) {
VLog.w(TAG, "Warning: unable to delete file : " + privatePackageFile.getPath());
}
try {
FileUtils.copyFile(packageFile, privatePackageFile);
} catch (IOException e) {
privatePackageFile.delete();
return InstallResult.makeFailure("Unable to copy the package file.");
}
packageFile = privatePackageFile;
}
if (existOne != null) {
PackageCacheManager.remove(pkg.packageName);
}
// 给上可执行权限,5.0 之后在 SD 卡上执行 bin 需要可执行权限
chmodPackageDictionary(packageFile);
// PackageSetting 的一些配置,后面会序列化在磁盘上
PackageSetting ps;
if (existSetting != null) {
ps = existSetting;
} else {
ps = new PackageSetting();
}
ps.dependSystem = dependSystem;
ps.apkPath = packageFile.getPath();
ps.libPath = libDir.getPath();
ps.packageName = pkg.packageName;
ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg));
if (res.isUpdate) {
ps.lastUpdateTime = installTime;
} else {
ps.firstInstallTime = installTime;
ps.lastUpdateTime = installTime;
for (int userId : VUserManagerService.get().getUserIds()) {
boolean installed = userId == 0;
ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed);
}
}
//保存 VPackage Cache 到 Disk
PackageParserEx.savePackageCache(pkg);
//保存到 RamCache
PackageCacheManager.put(pkg, ps);
mPersistenceLayer.save();
if (!dependSystem) {
boolean runDexOpt = false;
if (VirtualRuntime.isArt()) {
try {
ArtDexOptimizer.interpretDex2Oat(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath());
} catch (IOException e) {
e.printStackTrace();
runDexOpt = true;
}
} else {
runDexOpt = true;
}
if (runDexOpt) {
try {
DexFile.loadDex(ps.apkPath, VEnvironment.getOdexFile(ps.packageName).getPath(), 0).close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BroadcastSystem.get().startApp(pkg);
//发送通知 安装完成
if (notify) {
notifyAppInstalled(ps, -1);
}
res.isSuccess = true;
return res;
}
APk 的安装主要完成以下几件事情:
解析manifest PackageParserEx.parsePackage()
//解析包结构
public static VPackage parsePackage(File packageFile) throws Throwable {
PackageParser parser = PackageParserCompat.createParser(packageFile);
//调用系统版本的 parsePackage 方法
PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0);
if (p.requestedPermissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")
&& p.mAppMetaData != null
&& p.mAppMetaData.containsKey("fake-signature")) {
String sig = p.mAppMetaData.getString("fake-signature");
p.mSignatures = new Signature[]{new Signature(sig)};
VLog.d(TAG, "Using fake-signature feature on : " + p.packageName);
} else {
//验证签名
PackageParserCompat.collectCertificates(parser, p, PackageParser.PARSE_IS_SYSTEM);
}
//转换成可以序列化在磁盘上的Cache
return buildPackageCache(p);
}
这里解析 Menifest 的方法其实是调用了 framework 隐藏方法 android.content.pm.PackageParser.parsePackage 来实现的,这个方法返回 android.content.pm.Package 结构,这个类型也是隐藏的,怎么办?可以从 sdk 中复制这个类到自己的项目中欺骗编译器。
以 RefObject 为例
类型 RefObject 代表映射 framework 层同名的泛型类型成员变量
// Field 映射
public class RefObject<T> {
// framework 层对应的 Field
private Field field;
public RefObject(Class<?> cls, Field field) throws NoSuchFieldException {
// 获取 framework 中同名字段的 field
this.field = cls.getDeclaredField(field.getName());
this.field.setAccessible(true);
}
//获取变量值
public T get(Object object) {
try {
return (T) this.field.get(object);
} catch (Exception e) {
return null;
}
}
//赋值
public void set(Object obj, T value) {
try {
this.field.set(obj, value);
} catch (Exception e) {
//Ignore
}
}
}
以 framework 层中隐藏类 LoadedApk 来说:
public class LoadedApk {
public static Class Class = RefClass.load(LoadedApk.class, "android.app.LoadedApk");
public static RefObject<ApplicationInfo> mApplicationInfo;
@MethodParams({boolean.class, Instrumentation.class})
public static RefMethod<Application> makeApplication;
mApplicationInfo 就是 LoadedApk 中私有 ApplicationInfo 类型字段的同名映射。
当你引用 LoadedApk Mirror 类时,类加载器加载该类,执行静态成员的初始化表达式 RefClass.load(LoadedApk.class, “android.app.LoadedApk”); Mirror 类中的同名字段将被反射赋值。
RefClass.load()
public static Class load(Class mappingClass, Class> realClass) {
// 获取 Mirror 类的所有字段
Field[] fields = mappingClass.getDeclaredFields();
for (Field field : fields) {
try {
// 必须是 static 变量
if (Modifier.isStatic(field.getModifiers())) {
// 从预设的 Map 中找到 RefXXXX 的构造器
Constructor> constructor = REF_TYPES.get(field.getType());
if (constructor != null) {
// 赋值
field.set(null, constructor.newInstance(realClass, field));
}
}
}
catch (Exception e) {
// Ignore
}
}
return realClass;
}
最后调用的话 MirrorClass.mirrorField.get(instance),MirrorClass.mirrorField.set(instance),就相当于直接调用 framework 层的隐藏字段了。
Package 类是不可序列化的,换句话说就是不能直接保存在磁盘上,我们需要将其转换成可以序列化的 VPackage 类型,这就是 buildPackageCache() 的作用。
public class VPackage implements Parcelable {
public static final Creator<VPackage> CREATOR = new Creator<VPackage>() {
@Override
public VPackage createFromParcel(Parcel source) {
return new VPackage(source);
}
@Override
public VPackage[] newArray(int size) {
return new VPackage[size];
}
};
public ArrayList<ActivityComponent> activities;
public ArrayList<ActivityComponent> receivers;
public ArrayList<ProviderComponent> providers;
public ArrayList<ServiceComponent> services;
public ArrayList<InstrumentationComponent> instrumentation;
public ArrayList<PermissionComponent> permissions;
public ArrayList<PermissionGroupComponent> permissionGroups;
public ArrayList<String> requestedPermissions;
public ArrayList<String> protectedBroadcasts;
public ApplicationInfo applicationInfo;
public Signature[] mSignatures;
public Bundle mAppMetaData;
public String packageName;
public int mPreferredOrder;
public String mVersionName;
public String mSharedUserId;
public ArrayList<String> usesLibraries;
public int mVersionCode;
public int mSharedUserLabel;
// Applications hardware preferences
public ArrayList<ConfigurationInfo> configPreferences = null;
// Applications requested features
public ArrayList<FeatureInfo> reqFeatures = null;
public Object mExtras;
......
VPackage几乎保存的apk中所有的关键信息,尤其是组件的数据结构会在app在VA中运行的时候给VAMS,VPMS这些VAService提供apk的组件信息。
关于是否 dependSystem 和 isInstallOutside,这个有关 apk 的动态加载,如果 dependSysytem 并且 apk 已经在外部环境安装了,那么 VA 会调用系统提供的 API 就可以动态加载 APK。反之 VA 需要做一些必要的复制工作然后再费劲的去加载 APK。
VirtualApp\lib\src\main\java\com\lody\virtual\server\am\*
首先,VAService 是指 VA 仿造 Android 原生 framework 层 Service 实现的一套副本,举例有 VActivityManagerService,它和系统 AMS 一样,只不过他管理的是 VA 内部 Client App 的组件会话。
首先所有 VAService 直接继承与 XXX.Stub,也就是 Binder,并且直接使用了一个 Map 储存在 VAService 进程空间中,并没有注册到系统 AMS 中,事实上在 VAService 进程中,每个 Service 都被当作一个普通对象 new 和 初始化。
最终,他们被添加到了 ServiceCache 中:
一个简单的map
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);
}
}
而被添加的时机则在 BinderProvider 的 onCreate() 回掉中:
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;
}
这里使用了IPC通信
IPCBus.register()
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);
}
checkInitialized()检验IServerCache是否为空
private static void checkInitialized() {
if (sCache == null) {
throw new IllegalStateException("please call initialize() at first.");
}
}
IServerCache.java
public interface IServerCache {
void join(String serverName, IBinder binder);
IBinder query(String serverName);
}
join方法在
VirtualCore.startup()中
public void startup(Context context) throws Throwable {
if (!isStartUp) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
}
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();
ContextFixer.fixContext(context);
isStartUp = true;
if (initLock != null) {
initLock.open();
initLock = null;
}
}
}
回调了ServiceCache.addService(serverName, binder)方法,在BinderProvider 的 onCreate()中已经调用了
DaemonService.startup(context)
需要注意的是 DeamonService 是一个空前台服务,目的是为了保活 VAService 进程,即 :x 进程,因为现在后台服务很容易被杀,在 Android 8.0 以后后台服务只能在后台存活5S,而前台服务则不受影响。
VA 设计了一个单独的 ServiceFetcher 服务用于向外部暴露 VAService 中的所有服务的 IBinder 句柄,而 ServiceFetcher 本身也是 Binder 服务,也就是说,ServiceFetcher 的 Ibinder 句柄是拿到其他 VAServic IBinder 的钥匙。
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);
}
}
}
ServicecFetcher 自身的 IBnder 则通过 BinderProvicer 这个ContentProvider 暴露给其他进程:
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;
}
那么,在 Client App 中 VA Client 就可以通过 IServiceFetcher 这个 IBinder 拿到其他服务的 IBinder 了:
com.lody.virtual.client.ipc.ServiceManagerNative
private static IServiceFetcher sFetcher;
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;
}
//返回服务的IBinder句柄
public static IBinder getService(String name) {
//如果是本地服务,直接本地返回
if (VirtualCore.get().isServerProcess()) {
return ServiceCache.getService(name);
}
//如果是ServiceFetcher的句柄找到远程Service 的句柄
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;
}
首先要了解的是 Android App 是组件化的,Apk 其实是 N 多个组件的集合,以及一些资源文件和 Assert,App 的启动有多种情况,只要在一个新的进程中调起了 apk 中任何一个组件,App 将被初始化,Application 将被初始化。
首先在 Client App 中,startActivity 方法必须被 Hook 掉,不然 Client App 调用 startActivity 就直指外部 Activity 去了。
这部分的原理其实与 DroidPlugin 大同小异,由于插件(Client App)中的 Activity 是没有在 AMS 中注册的,AMS 自然无法找到我们的插件 Activity。
Hook 的目的是我们拿到用户的 Intent,把他替换成指向 VA 在 Menifest 中站好坑的 StubActivity 的 Intent,然后将原 Intent 当作 data 打包进新 Intent 以便日后流程再次进入 VA 时恢复。
Hook 的方法就是用我们动态代理生成的代理类对象替换系统原来的 ActiityManagerNative.geDefault 对象。
com.lody.virtual.client.hook.proxies.am.ActivityManagerStub
public void inject() throws Throwable {
if (BuildCompat.isOreo()) {
//Android Oreo(8.X)
Object singleton = ActivityManagerOreo.IActivityManagerSingleton.get();
Singleton.mInstance.set(singleton, getInvocationStub().getProxyInterface());
} else {
if (ActivityManagerNative.gDefault.type() == IActivityManager.TYPE) {
ActivityManagerNative.gDefault.set(getInvocationStub().getProxyInterface());
} else if (ActivityManagerNative.gDefault.type() == Singleton.TYPE) {
Object gDefault = ActivityManagerNative.gDefault.get();
Singleton.mInstance.set(gDefault, getInvocationStub().getProxyInterface());
}
}
BinderInvocationStub hookAMBinder = new BinderInvocationStub(getInvocationStub().getBaseInterface());
hookAMBinder.copyMethodProxies(getInvocationStub());
ServiceManager.sCache.get().put(Context.ACTIVITY_SERVICE, hookAMBinder);
}
好了,下面只要调用到 startActivity 就会被 Hook 到 call。
这个函数需要注意以下几点:
static class StartActivity extends MethodProxy {
private static final String SCHEME_FILE = "file";
private static final String SCHEME_PACKAGE = "package";
private static final String SCHEME_CONTENT = "content";
@Override
public String getMethodName() {
return "startActivity";
}
@Override
public Object call(Object who, Method method, Object... args) throws Throwable {
Log.d("Q_M", "---->StartActivity 类");
int intentIndex = ArrayUtils.indexOfObject(args, Intent.class, 1);
if (intentIndex < 0) {
return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;
}
int resultToIndex = ArrayUtils.indexOfObject(args, IBinder.class, 2);
String resolvedType = (String) args[intentIndex + 1];
Intent intent = (Intent) args[intentIndex];
intent.setDataAndType(intent.getData(), resolvedType);
IBinder resultTo = resultToIndex >= 0 ? (IBinder) args[resultToIndex] : null;
int userId = VUserHandle.myUserId();
if (ComponentUtils.isStubComponent(intent)) {
return method.invoke(who, args);
}
// 请求安装和卸载界面
if (Intent.ACTION_INSTALL_PACKAGE.equals(intent.getAction())
|| (Intent.ACTION_VIEW.equals(intent.getAction())
&& "application/vnd.android.package-archive".equals(intent.getType()))) {
if (handleInstallRequest(intent)) {
return 0;
}
} else if ((Intent.ACTION_UNINSTALL_PACKAGE.equals(intent.getAction())
|| Intent.ACTION_DELETE.equals(intent.getAction()))
&& "package".equals(intent.getScheme())) {
if (handleUninstallRequest(intent)) {
return 0;
}
}
String resultWho = null;
int requestCode = 0;
Bundle options = ArrayUtils.getFirst(args, Bundle.class);
if (resultTo != null) {
resultWho = (String) args[resultToIndex + 1];
requestCode = (int) args[resultToIndex + 2];
}
// chooser 调用选择界面
if (ChooserActivity.check(intent)) {
intent.setComponent(new ComponentName(getHostContext(), ChooserActivity.class));
intent.putExtra(Constants.EXTRA_USER_HANDLE, userId);
intent.putExtra(ChooserActivity.EXTRA_DATA, options);
intent.putExtra(ChooserActivity.EXTRA_WHO, resultWho);
intent.putExtra(ChooserActivity.EXTRA_REQUEST_CODE, requestCode);
return method.invoke(who, args);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
args[intentIndex - 1] = getHostPkg();
}
if (intent.getScheme() != null && intent.getScheme().equals(SCHEME_PACKAGE) && intent.getData() != null) {
if (intent.getAction() != null && intent.getAction().startsWith("android.settings.")) {
intent.setData(Uri.parse("package:" + getHostPkg()));
}
}
//解析 ActivityInfo
ActivityInfo activityInfo = VirtualCore.get().resolveActivityInfo(intent, userId);
if (activityInfo == null) {
VLog.e("VActivityManager", "Unable to resolve activityInfo : " + intent);
Log.d("Q_M", "---->StartActivity who=" + who);
Log.d("Q_M", "---->StartActivity intent=" + intent);
Log.d("Q_M", "---->StartActivity resultTo=" + resultTo);
if (intent.getPackage() != null && isAppPkg(intent.getPackage())) {
return ActivityManagerCompat.START_INTENT_NOT_RESOLVED;
}
if (INTERCEPT_BACK_HOME && Intent.ACTION_MAIN.equals(intent.getAction())
&& intent.getCategories().contains("android.intent.category.HOME")
&& resultTo != null) {
VActivityManager.get().finishActivity(resultTo);
return 0;
}
return method.invoke(who, args);
}
// 调用远程 VAMS.startActivity
int res = VActivityManager.get().startActivity(intent, activityInfo, resultTo, options, resultWho, requestCode, VUserHandle.myUserId());
if (res != 0 && resultTo != null && requestCode > 0) {
VActivityManager.get().sendActivityResult(resultTo, resultWho, requestCode);
}
// 处理 Activity 切换动画,因为此时动画还是 Host 的 Stub Activity 默认动画,需要覆盖成子程序包的动画
if (resultTo != null) {
ActivityClientRecord r = VActivityManager.get().getActivityRecord(resultTo);
if (r != null && r.activity != null) {
try {
TypedValue out = new TypedValue();
Resources.Theme theme = r.activity.getResources().newTheme();
theme.applyStyle(activityInfo.getThemeResource(), true);
if (theme.resolveAttribute(android.R.attr.windowAnimationStyle, out, true)) {
TypedArray array = theme.obtainStyledAttributes(out.data,
new int[]{
android.R.attr.activityOpenEnterAnimation,
android.R.attr.activityOpenExitAnimation
});
r.activity.overridePendingTransition(array.getResourceId(0, 0), array.getResourceId(1, 0));
array.recycle();
}
} catch (Throwable e) {
// Ignore
}
}
}
return res;
}
逻辑最终走到 VAMS 后,VAMS 调用 ActivityStack.startActivityLocked
public int startActivity(Intent intent, ActivityInfo info, IBinder resultTo, Bundle options, String resultWho, int requestCode, int userId) {
synchronized (this) {
return mMainStack.startActivityLocked(userId, intent, info, resultTo, options, resultWho, requestCode);
}
}
startActivityLocked()
//和framework的实现一致
int startActivityLocked(int userId, Intent intent, ActivityInfo info, IBinder resultTo, Bundle options,
String resultWho, int requestCode) {
optimizeTasksLocked();
Intent destIntent;
ActivityRecord sourceRecord = findActivityByToken(userId, resultTo);
TaskRecord sourceTask = sourceRecord != null ? sourceRecord.task : null;
ReuseTarget reuseTarget = ReuseTarget.CURRENT;
ClearTarget clearTarget = ClearTarget.NOTHING;
boolean clearTop = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
boolean clearTask = containFlags(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
//对Flag的处理
......
String affinity = ComponentUtils.getTaskAffinity(info);
//根据Flag 寻找合适的 Task
TaskRecord reuseTask = null;
switch (reuseTarget) {
case AFFINITY:
reuseTask = findTaskByAffinityLocked(userId, affinity);
break;
case DOCUMENT:
reuseTask = findTaskByIntentLocked(userId, intent);
break;
case CURRENT:
reuseTask = sourceTask;
break;
default:
break;
}
boolean taskMarked = false;
if (reuseTask == null) {
startActivityInNewTaskLocked(userId, intent, info, options);
} else {
boolean delivered = false;
mAM.moveTaskToFront(reuseTask.taskId, 0);
boolean startTaskToFront = !clearTask && !clearTop && ComponentUtils.isSameIntent(intent, reuseTask.taskRoot);
if (clearTarget.deliverIntent || singleTop) {
taskMarked = markTaskByClearTarget(reuseTask, clearTarget, intent.getComponent());
ActivityRecord topRecord = topActivityInTask(reuseTask);
if (clearTop && !singleTop && topRecord != null && taskMarked) {
topRecord.marked = true;
}
// Target activity is on top
if (topRecord != null && !topRecord.marked && topRecord.component.equals(intent.getComponent())) {
deliverNewIntentLocked(sourceRecord, topRecord, intent);
delivered = true;
}
}
if (taskMarked) {
synchronized (mHistory) {
scheduleFinishMarkedActivityLocked();
}
}
if (!startTaskToFront) {
if (!delivered) {
destIntent = startActivityProcess(userId, sourceRecord, intent, info);
if (destIntent != null) {
startActivityFromSourceTask(reuseTask, destIntent, info, resultWho, requestCode, options);
}
}
}
}
return 0;
}
然后 call 到了 startActivityProcess ,这就是真正替换 Intent 的地方:
// 使用 Host Stub Activity 的 Intent 包装原 Intent
private Intent startActivityProcess(int userId, ActivityRecord sourceRecord, Intent intent, ActivityInfo info) {
intent = new Intent(intent);
// 获得 Activity 对应的 ProcessRecorder,如果没有则表示这是 Process 第一个打开的组件,需要初始化 Application
ProcessRecord targetApp = mService.startProcessIfNeedLocked(info.processName, userId, info.packageName);
if (targetApp == null) {
return null;
}
Intent targetIntent = new Intent();
// 根据 Client App 的 PID 获取 StubActivity
targetIntent.setClassName(VirtualCore.get().getHostPkg(), fetchStubActivity(targetApp.vpid, info));
ComponentName component = intent.getComponent();
if (component == null) {
component = ComponentUtils.toComponentName(info);
}
targetIntent.setType(component.flattenToString());
StubActivityRecord saveInstance = new StubActivityRecord(intent, info,
sourceRecord != null ? sourceRecord.component : null, userId);
saveInstance.saveToIntent(targetIntent);
return targetIntent;
}
fetchStubActivity 会根据相同的进程 id 在 VA 的 Menifest 中找到那个提前占坑的 StubActivity:
// 获取合适的 StubActivity,返回 StubActivity 全限定名
private String fetchStubActivity(int vpid, ActivityInfo targetInfo) {
boolean isFloating = false;
boolean isTranslucent = false;
boolean showWallpaper = false;
try {
int[] R_Styleable_Window = R_Hide.styleable.Window.get();
int R_Styleable_Window_windowIsTranslucent = R_Hide.styleable.Window_windowIsTranslucent.get();
int R_Styleable_Window_windowIsFloating = R_Hide.styleable.Window_windowIsFloating.get();
int R_Styleable_Window_windowShowWallpaper = R_Hide.styleable.Window_windowShowWallpaper.get();
AttributeCache.Entry ent = AttributeCache.instance().get(targetInfo.packageName, targetInfo.theme,
R_Styleable_Window);
if (ent != null && ent.array != null) {
showWallpaper = ent.array.getBoolean(R_Styleable_Window_windowShowWallpaper, false);
isTranslucent = ent.array.getBoolean(R_Styleable_Window_windowIsTranslucent, false);
isFloating = ent.array.getBoolean(R_Styleable_Window_windowIsFloating, false);
}else{
Resources resources=VirtualCore.get().getResources(targetInfo.packageName);
if(resources!=null) {
TypedArray typedArray = resources.newTheme().obtainStyledAttributes(targetInfo.theme, R_Styleable_Window);
if(typedArray!=null){
showWallpaper = typedArray.getBoolean(R_Styleable_Window_windowShowWallpaper, false);
isTranslucent = typedArray.getBoolean(R_Styleable_Window_windowIsTranslucent, false);
isFloating = typedArray.getBoolean(R_Styleable_Window_windowIsFloating, false);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
// 根据在 Menifest 中注册的 pid
boolean isDialogStyle = isFloating || isTranslucent || showWallpaper;
if (isDialogStyle) {
return VASettings.getStubDialogName(vpid);
} else {
return VASettings.getStubActivityName(vpid);
}
}
VA 没有为每个 Process 注册多个 Activity,也没有为不同的启动方式注册多个 Activity,这里确实是有改进的。
这里根本原因是因为 VA 对 VAMS 实现的更为完整,实现了原版 AMS 的基本功能,包括完整的 Recorder 管理,Task Stack 管理等,这样的话 StubActivity 的唯一作用便是携带 Client App 真正的 Intent 交给 VAMS 处理。这套机制衍生到其他的组件也是一样的。
ActivityStack, TaskRecord ,ActivityRecord
/* package */ class ActivityStack {
private final ActivityManager mAM;
private final VActivityManagerService mService;
/**
* [Key] = TaskId [Value] = TaskRecord
*/
private final SparseArray<TaskRecord> mHistory = new SparseArray<>();
class TaskRecord {
public final List<ActivityRecord> activities = Collections.synchronizedList(new ArrayList<ActivityRecord>());
public int taskId;
public int userId;
public String affinity;
public Intent taskRoot;
/* package */ class ActivityRecord {
public TaskRecord task;
public ComponentName component;
public ComponentName caller;
// Client App 中 Activity 的句柄
public IBinder token;
public int userId;
public ProcessRecord process;
public int launchMode;
public int flags;
public boolean marked;
public String affinity;
StubActivityRecorder:
public class StubActivityRecord {
public Intent intent;
public ActivityInfo info;
public ComponentName caller;
public int userId;
public StubActivityRecord(Intent intent, ActivityInfo info, ComponentName caller, int userId) {
this.intent = intent;
this.info = info;
this.caller = caller;
this.userId = userId;
}
//获得原版Intent和一些其他信息
public StubActivityRecord(Intent stub) {
this.intent = stub.getParcelableExtra("_VA_|_intent_");
this.info = stub.getParcelableExtra("_VA_|_info_");
this.caller = stub.getParcelableExtra("_VA_|_caller_");
this.userId = stub.getIntExtra("_VA_|_user_id_", 0);
}
//将原版的Intent塞到Stub Intent
public void saveToIntent(Intent stub) {
stub.putExtra("_VA_|_intent_", intent);
stub.putExtra("_VA_|_info_", info);
stub.putExtra("_VA_|_caller_", caller);
stub.putExtra("_VA_|_user_id_", userId);
}
}
VActivityManagerService.java
private ComponentName startServiceCommon(Intent service,
boolean scheduleServiceArgs, int userId) {
ServiceInfo serviceInfo = resolveServiceInfo(service, userId);
if (serviceInfo == null) {
return null;
}
ProcessRecord targetApp = startProcessIfNeedLocked(ComponentUtils.getProcessName(serviceInfo),
userId,
serviceInfo.packageName);
if (targetApp == null) {
VLog.e(TAG, "Unable to start new Process for : " + ComponentUtils.toComponentName(serviceInfo));
return null;
}
IInterface appThread = targetApp.appThread;
ServiceRecord r = findRecordLocked(userId, serviceInfo);
if (r == null) {
r = new ServiceRecord();
r.startId = 0;
r.activeSince = SystemClock.elapsedRealtime();
r.process = targetApp;
r.serviceInfo = serviceInfo;
try {
IApplicationThreadCompat.scheduleCreateService(appThread, r, r.serviceInfo, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
addRecord(r);
}
r.lastActivityTime = SystemClock.uptimeMillis();
if (scheduleServiceArgs) {
r.startId++;
boolean taskRemoved = serviceInfo.applicationInfo != null
&& serviceInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.ECLAIR;
try {
IApplicationThreadCompat.scheduleServiceArgs(appThread, r, taskRemoved, r.startId, 0, service);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return ComponentUtils.toComponentName(serviceInfo);
}
// 获得 Activity 对应的 ProcessRecorder,如果没有则表示这是 Process 第一个打开的组件,需要初始化 Application
ProcessRecord targetApp = startProcessIfNeedLocked(ComponentUtils.getProcessName(serviceInfo),
userId,
serviceInfo.packageName);
startProcessIfNeedLocked()
ProcessRecord startProcessIfNeedLocked(String processName, int userId, String packageName) {
if (VActivityManagerService.get().getFreeStubCount() < 3) {
// run GC
killAllApps();
}
PackageSetting ps = PackageCacheManager.getSetting(packageName);
ApplicationInfo info = VPackageManagerService.get().getApplicationInfo(packageName, 0, userId);
if (ps == null || info == null) {
return null;
}
if (!ps.isLaunched(userId)) {
sendFirstLaunchBroadcast(ps, userId);
ps.setLaunched(userId, true);
VAppManagerService.get().savePersistenceData();
}
int uid = VUserHandle.getUid(userId, ps.appId);
ProcessRecord app = mProcessNames.get(processName, uid);
if (app != null && app.client.asBinder().isBinderAlive()) {
return app;
}
int vpid = queryFreeStubProcessLocked();
if (vpid == -1) {
return null;
}
app = performStartProcessLocked(uid, vpid, info, processName);
if (app != null) {
app.pkgList.add(info.packageName);
}
return app;
}
performStartProcessLocked()
这里会先去找对应 Client App 进程的 ProcessRecorder,找不到代表 Application 刚启动尚未初始化:
private ProcessRecord performStartProcessLocked(int vuid, int vpid, ApplicationInfo info, String processName) {
ProcessRecord app = new ProcessRecord(info, processName, vuid, vpid);
Bundle extras = new Bundle();
BundleCompat.putBinder(extras, "_VA_|_binder_", app);
extras.putInt("_VA_|_vuid_", vuid);
extras.putString("_VA_|_process_", processName);
extras.putString("_VA_|_pkg_", info.packageName);
// 调用子程序包的 init_process 方法,并且得到子程序包 IBinder 句柄
Bundle res = ProviderCall.call(VASettings.getStubAuthority(vpid), "_VA_|_init_process_", null, extras);
if (res == null) {
return null;
}
int pid = res.getInt("_VA_|_pid_");
IBinder clientBinder = BundleCompat.getBinder(res, "_VA_|_client_");
// attach 到 Client 的 VAM , 将子程序句柄推入服务端 VAMS
attachClient(pid, clientBinder);
return app;
}
ProviderCall.call 向 Client App 的 StubContentProvider 发起远程调用:
StubContentProvider.java
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;
}
Client App 的 IBinder 句柄(VClientImpl.asBinder) 被打包在了 Bundle 中返回给 VAMS。
最终, VAMS 调用原生 AM 的 startActivity 向真正的 AMS 发送替换成 StubActivity 的伪造 Intent。
private void realStartActivitiesLocked(IBinder resultTo, Intent[] intents, String[] resolvedTypes, Bundle options) {
Class<?>[] types = IActivityManager.startActivities.paramList();
Object[] args = new Object[types.length];
if (types[0] == IApplicationThread.TYPE) {
args[0] = ActivityThread.getApplicationThread.call(VirtualCore.mainThread());
}
int pkgIndex = ArrayUtils.protoIndexOf(types, String.class);
int intentsIndex = ArrayUtils.protoIndexOf(types, Intent[].class);
int resultToIndex = ArrayUtils.protoIndexOf(types, IBinder.class, 2);
int optionsIndex = ArrayUtils.protoIndexOf(types, Bundle.class);
int resolvedTypesIndex = intentsIndex + 1;
if (pkgIndex != -1) {
args[pkgIndex] = VirtualCore.get().getHostPkg();
}
args[intentsIndex] = intents;
args[resultToIndex] = resultTo;
args[resolvedTypesIndex] = resolvedTypes;
args[optionsIndex] = options;
ClassUtils.fixArgs(types, args);
//在这里进行伪造
IActivityManager.startActivities.call(ActivityManagerNative.getDefault.call(),
(Object[]) args);
}
当 AMS 收到伪装的 Intent 后,就会找到 StubActivity,这时流程回到 VA 里的主线程中的消息队列中。
Hook 过程就是用我们自己的 Handler 替换 android.os.Handler.mCallback 因为主线程在这里分发一些操作:
HCallbackStub.java
@Override
public void inject() throws Throwable {
otherCallback = getHCallback();
mirror.android.os.Handler.mCallback.set(getH(), this);
}
handlerMessage 判断是 LAUNCH_ACTIVITY Action 后直接调用了 handlerLaunchActivity 方法,和原版其实很像。
private boolean handleLaunchActivity(Message msg) {
Object r = msg.obj;
Intent stubIntent = ActivityThread.ActivityClientRecord.intent.get(r);
//获取原版Intent信息
StubActivityRecord saveInstance = new StubActivityRecord(stubIntent);
if (saveInstance.intent == null) {
return true;
}
//原版Intent
Intent intent = saveInstance.intent;
ComponentName caller = saveInstance.caller;
IBinder token = ActivityThread.ActivityClientRecord.token.get(r);
ActivityInfo info = saveInstance.info;
//如果token还没初始化,代表App刚刚启动第一个组件
if (VClientImpl.get().getToken() == null) {
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);
if(installedAppInfo == null){
return true;
}
VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId);
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return false;
}
//如果AooBindData为空,则App信息不明
if (!VClientImpl.get().isBound()) {
VClientImpl.get().bindApplication(info.packageName, info.processName);
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));
return false;
}
//获取TaskId
int taskId = IActivityManager.getTaskForActivity.call(
ActivityManagerNative.getDefault.call(),
token,
false
);
// 1.将 ActivityRecorder 加入 mActivities 2.通知服务端 VAMS Activity 创建完成
VActivityManager.get().onActivityCreate(ComponentUtils.toComponentName(info), caller, token, info, intent, ComponentUtils.getTaskAffinity(info), taskId, info.launchMode, info.flags);
ClassLoader appClassLoader = VClientImpl.get().getClassLoader(info.applicationInfo);
intent.setExtrasClassLoader(appClassLoader);
// 将 Host Stub Activity Intent 替换为原版 Intent
ActivityThread.ActivityClientRecord.intent.set(r, intent);
// 将 Host Stub Activity Intent 替换为原版 Intent
ActivityThread.ActivityClientRecord.activityInfo.set(r, info);
return true;
}
如果这个 Activity 是这个 Apk 启动的第一个组件,则需要 bindApplication 初始化 Application 操作:
private void bindApplicationNoCheck(String packageName, String processName, ConditionVariable lock) {
VDeviceInfo deviceInfo = getDeviceInfo();
if (processName == null) {
processName = packageName;
}
mTempLock = lock;
try {
//设置未捕获异常的Callback
setupUncaughtHandler();
} catch (Throwable e) {
e.printStackTrace();
}
try {
//修复Provider信息
fixInstalledProviders();
} catch (Throwable e) {
e.printStackTrace();
}
mirror.android.os.Build.SERIAL.set(deviceInfo.serial);
mirror.android.os.Build.DEVICE.set(Build.DEVICE.replace(" ", "_"));
ActivityThread.mInitialApplication.set(
VirtualCore.mainThread(),
null
);
//从VPMS获取aps信息
AppBindData data = new AppBindData();
InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0);
if (info == null) {
new Exception("App not exist!").printStackTrace();
Process.killProcess(0);
System.exit(0);
}
data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid));
data.processName = processName;
data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA);
Log.i(TAG, "Binding application " + data.appInfo.packageName + " (" + data.processName + ")");
mBoundApplication = data;
//主要设置进程的名字
VirtualRuntime.setupRuntime(data.processName, data.appInfo);
int targetSdkVersion = data.appInfo.targetSdkVersion;
if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) {
StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build();
StrictMode.setThreadPolicy(newPolicy);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
mirror.android.os.Message.updateCheckRecycle.call(targetSdkVersion);
}
if (VASettings.ENABLE_IO_REDIRECT) {
//IO重定向
startIOUniformer();
}
//hook native函数
NativeEngine.launchEngine();
Object mainThread = VirtualCore.mainThread();
//准备dex列表
NativeEngine.startDexOverride();
//获得子pkg的Context前提是必须在系统中安装的
Context context = createPackageContext(data.appInfo.packageName);
//设置虚拟机系统环境,临时文件夹codeCacheDir
System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
//oat的cache目录
File codeCacheDir;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
codeCacheDir = context.getCodeCacheDir();
} else {
codeCacheDir = context.getCacheDir();
}
//硬件加速的cache目录
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
if (HardwareRenderer.setupDiskCache != null) {
HardwareRenderer.setupDiskCache.call(codeCacheDir);
}
} else {
if (ThreadedRenderer.setupDiskCache != null) {
ThreadedRenderer.setupDiskCache.call(codeCacheDir);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (RenderScriptCacheDir.setupDiskCache != null) {
RenderScriptCacheDir.setupDiskCache.call(codeCacheDir);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (RenderScript.setupDiskCache != null) {
RenderScript.setupDiskCache.call(codeCacheDir);
}
}
//修复子App中ActivityThread.AppBinderData的参数,因为之前用的是在host程序中注册的Stub的信息
Object boundApp = fixBoundApp(mBoundApplication);
mBoundApplication.info = ContextImpl.mPackageInfo.get(context);
mirror.android.app.ActivityThread.AppBindData.info.set(boundApp, data.info);
//同样修复targetSdkVersion原来也是和Host程序一样的
VMRuntime.setTargetSdkVersion.call(VMRuntime.getRuntime.call(), data.appInfo.targetSdkVersion);
Configuration configuration = context.getResources().getConfiguration();
Object compatInfo = CompatibilityInfo.ctor.newInstance(data.appInfo, configuration.screenLayout, configuration.smallestScreenWidthDp, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
DisplayAdjustments.setCompatibilityInfo.call(ContextImplKitkat.mDisplayAdjustments.get(context), compatInfo);
}
DisplayAdjustments.setCompatibilityInfo.call(LoadedApkKitkat.mDisplayAdjustments.get(mBoundApplication.info), compatInfo);
} else {
CompatibilityInfoHolder.set.call(LoadedApkICS.mCompatibilityInfo.get(mBoundApplication.info), compatInfo);
}
boolean conflict = SpecialComponentList.isConflictingInstrumentation(packageName);
if (!conflict) {
InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
}
//开始构建子程序包的Application对象,并且替换原来通过Host Stub生成的mInitialApplication
mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null);
mirror.android.app.ActivityThread.mInitialApplication.set(mainThread, mInitialApplication);
ContextFixer.fixContext(mInitialApplication);
if (Build.VERSION.SDK_INT >= 24 && "com.tencent.mm:recovery".equals(processName)) {
fixWeChatRecovery(mInitialApplication);
}
if (data.providers != null) {
//注册Providers
installContentProviders(mInitialApplication, data.providers);
}
// 初始化锁开,异步调用的初始化函数可以返回了
if (lock != null) {
lock.open();
mTempLock = null;
}
VirtualCore.get().getComponentDelegate().beforeApplicationCreate(mInitialApplication);
try {
// 调用 Application.onCreate
mInstrumentation.callApplicationOnCreate(mInitialApplication);
InvocationStubManager.getInstance().checkEnv(HCallbackStub.class);
if (conflict) {
InvocationStubManager.getInstance().checkEnv(AppInstrumentation.class);
}
Application createdApp = ActivityThread.mInitialApplication.get(mainThread);
if (createdApp != null) {
mInitialApplication = createdApp;
}
} catch (Exception e) {
if (!mInstrumentation.onException(mInitialApplication, e)) {
throw new RuntimeException(
"Unable to create application " + mInitialApplication.getClass().getName()
+ ": " + e.toString(), e);
}
}
VActivityManager.get().appDoneExecuting();
VirtualCore.get().getComponentDelegate().afterApplicationCreate(mInitialApplication);
}
private void setupUncaughtHandler() {
ThreadGroup root = Thread.currentThread().getThreadGroup();
while (root.getParent() != null) {
root = root.getParent();
}
ThreadGroup newRoot = new RootThreadGroup(root);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
final List<ThreadGroup> groups = mirror.java.lang.ThreadGroup.groups.get(root);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (groups) {
List<ThreadGroup> newGroups = new ArrayList<>(groups);
newGroups.remove(newRoot);
mirror.java.lang.ThreadGroup.groups.set(newRoot, newGroups);
groups.clear();
groups.add(newRoot);
mirror.java.lang.ThreadGroup.groups.set(root, groups);
for (ThreadGroup group : newGroups) {
if (group == newRoot) continue;
mirror.java.lang.ThreadGroup.parent.set(group, newRoot);
}
}
} else {
final ThreadGroup[] groups = ThreadGroupN.groups.get(root);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (groups) {
ThreadGroup[] newGroups = groups.clone();
ThreadGroupN.groups.set(newRoot, newGroups);
ThreadGroupN.groups.set(root, new ThreadGroup[]{newRoot});
for (Object group : newGroups) {
if (group == newRoot) continue;
ThreadGroupN.parent.set(group, newRoot);
}
ThreadGroupN.ngroups.set(root, 1);
}
}
}
bindApplication 主要做了以下几个事情:
最后成功从 StubActivity Intent 还原出来的原版 Intent 被继续交给原生的 AM:
ActivityThread.ActivityClientRecord.intent.set(r, intent);
// 将 Host Stub Activity Intent 替换为原版 Intent
ActivityThread.ActivityClientRecord.activityInfo.set(r, info);
最后一个 Hook 点在 Instrumentation.callActivityOnCreate:
因为 AMS 实际上启动的是 StubActivity 的关系,真正的 Activity 的一些信息还不是其真正的信息,比如主题之类的,所以需要在这个时机修复一下,选择这个时间修复的原因也是因为 Activity 已经被 new 出来了,而且资源已经准备完毕。
AppInstrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
if (icicle != null) {
BundleCompat.clearParcelledData(icicle);
}
VirtualCore.get().getComponentDelegate().beforeActivityCreate(activity);
IBinder token = mirror.android.app.Activity.mToken.get(activity);
ActivityClientRecord r = VActivityManager.get().getActivityRecord(token);
//替换Activity对象
if (r != null) {
r.activity = activity;
}
ContextFixer.fixContext(activity);
ActivityFixer.fixActivity(activity);
ActivityInfo info = null;
if (r != null) {
info = r.info;
}
//设置主题和屏幕纵横控制
if (info != null) {
if (info.theme != 0) {
activity.setTheme(info.theme);
}
if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
&& info.screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
activity.setRequestedOrientation(info.screenOrientation);
}
}
super.callActivityOnCreate(activity, icicle);
VirtualCore.get().getComponentDelegate().afterActivityCreate(activity);
}
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
mBase 是 ContextImpl,所以调用到 ContextImpl.startService():
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Client 的流程最后到 ActivityManagerNative.startService():
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
// 远程调用 AMS
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
逻辑再一次转移到远程的 AMS 中,然后我们先忽略 AMS 中的一堆逻辑,最后 AMS 调用到这:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
sendServiceArgsLocked(r, execInFg, true);
}
这里的 ProcessRecoder.thread 是 AMS 持有的 Client App 的 IBinder 句柄,通过他可以远程调用到 Client App 的 ApplicationThread 中的 scheduleCreateService 方法:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
这里大家可能发现了,Intent 在 AMS 绕了一圈又回来了,事实上 AMS 在其中好像没有发挥什么作用,其实在外部环境 AMS 还是很重要的,但是在 VA 中,AMS 在 Service 调度中其实没有发挥什么作用。原因有以下几点:
首先 VA 内部的插件 Service 没有比较暴露给外部 App 调用,所以让 AMS 知晓 Service 的意义不大。
其次和 Activity 必须有个 StubActivity 让 AMS 持有不一样,Service 生命周期和功能都极其简单,并且没有界面,没有交互,换句话说 Service 和其他 Framework Service(例如 WMS) 没有任何关系,所以其实并不需要 AMS 这一步存在。
那么综上所诉,为了启动插件 Service 我们其实可以绕过 AMS,直接调用 ApplicationThread 中的 scheduleCreateService 方法,Service 的会话储存交给 VAMS 就行。
和startActivity一样,首先是Hook
static class StartService extends MethodProxy {
@Override
public String getMethodName() {
return "startService";
}
@Override
public Object call(Object who, Method method, Object... args) throws Throwable {
IInterface appThread = (IInterface) args[0];
Intent service = (Intent) args[1];
String resolvedType = (String) args[2];
if (service.getComponent() != null
&& getHostPkg().equals(service.getComponent().getPackageName())) {
// for server process
return method.invoke(who, args);
}
int userId = VUserHandle.myUserId();
//如果是内部请求,获取原理的Service
if (service.getBooleanExtra("_VA_|_from_inner_", false)) {
userId = service.getIntExtra("_VA_|_user_id_", userId);
service = service.getParcelableExtra("_VA_|_intent_");
} else {
if (isServerProcess()) {
userId = service.getIntExtra("_VA_|_user_id_", VUserHandle.USER_NULL);
}
}
service.setDataAndType(service.getData(), resolvedType);
ServiceInfo serviceInfo = VirtualCore.get().resolveServiceInfo(service, VUserHandle.myUserId());
if (serviceInfo != null) {
//远程调用VAMS.startService
return VActivityManager.get().startService(appThread, service, resolvedType, userId);
}
return method.invoke(who, args);
}
和 startActivity 一样将真正业务交给 VAMS.startService():
public ComponentName startService(IBinder caller, Intent service, String resolvedType, int userId) {
synchronized (this) {
return startServiceCommon(service, true, userId);
}
}
private ComponentName startServiceCommon(Intent service,
boolean scheduleServiceArgs, int userId) {
ServiceInfo serviceInfo = resolveServiceInfo(service, userId);
if (serviceInfo == null) {
return null;
}
ProcessRecord targetApp = startProcessIfNeedLocked(ComponentUtils.getProcessName(serviceInfo),
userId,
serviceInfo.packageName);
if (targetApp == null) {
VLog.e(TAG, "Unable to start new Process for : " + ComponentUtils.toComponentName(serviceInfo));
return null;
}
IInterface appThread = targetApp.appThread;
ServiceRecord r = findRecordLocked(userId, serviceInfo);
if (r == null) {
r = new ServiceRecord();
r.startId = 0;
r.activeSince = SystemClock.elapsedRealtime();
r.process = targetApp;
r.serviceInfo = serviceInfo;
try {
// 调用 ApplicationThread.scheduleCreateService 直接创建 Service
IApplicationThreadCompat.scheduleCreateService(appThread, r, r.serviceInfo, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
// 将 ServiceRecorder 推入 history
addRecord(r);
}
r.lastActivityTime = SystemClock.uptimeMillis();
if (scheduleServiceArgs) {
r.startId++;
boolean taskRemoved = serviceInfo.applicationInfo != null
&& serviceInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.ECLAIR;
try {
IApplicationThreadCompat.scheduleServiceArgs(appThread, r, taskRemoved, r.startId, 0, service);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return ComponentUtils.toComponentName(serviceInfo);
}
这里主要做了以下几个工作:
VAService 的启动时机实在 BinderProvider.onCreate():
public boolean onCreate() {
...
VAppManagerService.get().scanApps();
...
return true;
}
@Override
public void scanApps() {
if (mBooting) {
return;
}
synchronized (this) {
mBooting = true;
mPersistenceLayer.read();
PrivilegeAppOptimizer.get().performOptimizeAllApps();
mBooting = false;
}
}
PersistenceLayer.read()
public void read() {
File file = mPersistenceFile;
Parcel p = Parcel.obtain();
try {
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[(int) file.length()];
int len = fis.read(bytes);
fis.close();
if (len != bytes.length) {
throw new IOException("Unable to read Persistence file.");
}
p.unmarshall(bytes, 0, bytes.length);
p.setDataPosition(0);
if (!verifyMagic(p)) {
onPersistenceFileDamage();
throw new IOException("Invalid persistence file.");
}
int fileVersion = p.readInt();
int currentVersion = getCurrentVersion();
if (fileVersion != getCurrentVersion()) {
if (!onVersionConflict(fileVersion, currentVersion)) {
throw new IOException("Unable to process the bad version persistence file.");
}
}
readPersistenceData(p);
} catch (Exception e) {
if (!(e instanceof FileNotFoundException)) {
e.printStackTrace();
}
} finally {
p.recycle();
}
}
PackagePersistenceLayer.readPersistenceData()
public void readPersistenceData(Parcel p) {
int count = p.readInt();
while (count-- > 0) {
PackageSetting setting = new PackageSetting(p);
mService.loadPackage(setting);
}
}
VAppManagerService.java
synchronized void loadPackage(PackageSetting setting) {
if (!loadPackageInnerLocked(setting)) {
cleanUpResidualFiles(setting);
}
}
private boolean loadPackageInnerLocked(PackageSetting ps) {
if (ps.dependSystem) {
if (!VirtualCore.get().isOutsideInstalled(ps.packageName)) {
return false;
}
}
File cacheFile = VEnvironment.getPackageCacheFile(ps.packageName);
VPackage pkg = null;
try {
pkg = PackageParserEx.readPackageCache(ps.packageName);
} catch (Throwable e) {
e.printStackTrace();
}
if (pkg == null || pkg.packageName == null) {
return false;
}
chmodPackageDictionary(cacheFile);
PackageCacheManager.put(pkg, ps);
BroadcastSystem.get().startApp(pkg);
return true;
}
BroadcastSystem.startApp(pkg)
//静态 Receiver的注册
public void startApp(VPackage p) {
PackageSetting setting = (PackageSetting) p.mExtras;
// 遍历 Client App的Receiver
for (VPackage.ActivityComponent receiver : p.receivers) {
ActivityInfo info = receiver.info;
//得到对应Client App在VAService中的
List<BroadcastReceiver> receivers = mReceivers.get(p.packageName);
if (receivers == null) {
receivers = new ArrayList<>();
mReceivers.put(p.packageName, receivers);
}
//注册显示意图
String componentAction = String.format("_VA_%s_%s", info.packageName, info.name);
IntentFilter componentFilter = new IntentFilter(componentAction);
BroadcastReceiver r = new StaticBroadcastReceiver(setting.appId, info, componentFilter);
mContext.registerReceiver(r, componentFilter, null, mScheduler);
//推入记录
receivers.add(r);
//遍历注册隐式意图
for (VPackage.ActivityIntentInfo ci : receiver.intents) {
IntentFilter cloneFilter = new IntentFilter(ci.filter);
SpecialComponentList.protectIntentFilter(cloneFilter);
r = new StaticBroadcastReceiver(setting.appId, info, cloneFilter);
mContext.registerReceiver(r, cloneFilter, null, mScheduler);
//推入记录
receivers.add(r);
}
}
}
这里对每个 Client App 静态 Receiver 的信息使用统一的代理 StaticBroadcastReceiver 注册。
这样我们的代理 Receiver 注册完毕了。
下面当代理 Receiver 收到广播时:
public void onReceive(Context context, Intent intent) {
if (mApp.isBooting()) {
return;
}
if ((intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) != 0 || isInitialStickyBroadcast()) {
return;
}
String privilegePkg = intent.getStringExtra("_VA_|_privilege_pkg_");
if (privilegePkg != null && !info.packageName.equals(privilegePkg)) {
return;
}
PendingResult result = goAsync();
if (!mAMS.handleStaticBroadcast(appId, info, intent, new PendingResultData(result))) {
result.finish();
}
}
boolean handleStaticBroadcast(int appId, ActivityInfo info, Intent intent,
PendingResultData result) {
// 取出真正的目标Intent
Intent realIntent = intent.getParcelableExtra("_VA_|_intent_");
//取出真正的目标 component
ComponentName component = intent.getParcelableExtra("_VA_|_component_");
//用户id
int userId = intent.getIntExtra("_VA_|_user_id_", VUserHandle.USER_NULL);
if (realIntent == null) {
return false;
}
if (userId < 0) {
VLog.w(TAG, "Sent a broadcast without userId " + realIntent);
return false;
}
int vuid = VUserHandle.getUid(userId, appId);
return handleUserBroadcast(vuid, info, component, realIntent, result);
}
这里取出了真正的 Intent,和 Activity 类似,但是和 Activity 处理不同的是现在的逻辑还在 VAService 中:
handleUserBroadcast()
private boolean handleUserBroadcast(int vuid, ActivityInfo info, ComponentName component, Intent realIntent, PendingResultData result) {
if (component != null && !ComponentUtils.toComponentName(info).equals(component)) {
// Verify the component.
return false;
}
String originAction = SpecialComponentList.unprotectAction(realIntent.getAction());
if (originAction != null) {
// restore to origin action.
realIntent.setAction(originAction);
}
handleStaticBroadcastAsUser(vuid, info, realIntent, result);
return true;
}
handleStaticBroadcastAsUser()
private void handleStaticBroadcastAsUser(int vuid, ActivityInfo info, Intent intent,
PendingResultData result) {
synchronized (this) {
ProcessRecord r = findProcessLocked(info.processName, vuid);
if (BROADCAST_NOT_STARTED_PKG && r == null) {
r = startProcessIfNeedLocked(info.processName, getUserId(vuid), info.packageName);
}
if (r != null && r.appThread != null) {
performScheduleReceiver(r.client, vuid, info, intent,
result);
}
}
}
performScheduleReceiver()
private void performScheduleReceiver(IVClient client, int vuid, ActivityInfo info, Intent intent,
PendingResultData result) {
ComponentName componentName = ComponentUtils.toComponentName(info);
BroadcastSystem.get().broadcastSent(vuid, info, result);
try {
// 远程调用 client app 的 scheduleReceiver
client.scheduleReceiver(info.processName, componentName, intent, result);
} catch (Throwable e) {
if (result != null) {
result.finish();
}
}
}
public final class VClientImpl extends IVClient.Stub
client.scheduleReceiver() 这时候远程调用了 Client App 的 scheduleReceiver。这样我们回到了 Client App 进程空间:
public void scheduleReceiver(String processName, ComponentName component, Intent intent, PendingResultData resultData) {
ReceiverData receiverData = new ReceiverData();
receiverData.resultData = resultData;
receiverData.intent = intent;
receiverData.component = component;
receiverData.processName = processName;
sendMessage(RECEIVER, receiverData);
}
跟到消息队列中
private class H extends Handler {
private H() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case NEW_INTENT: {
handleNewIntent((NewIntentData) msg.obj);
}
break;
case RECEIVER: {
handleReceiver((ReceiverData) msg.obj);
}
}
}
}
handleReceiver()
private void handleReceiver(ReceiverData data) {
BroadcastReceiver.PendingResult result = data.resultData.build();
try {
//检测Application是否初始化,没有则初始化
if (!isBound()) {
bindApplication(data.component.getPackageName(), data.processName);
}
//获取Receiver的Context,这个context是一个ReceiverRestrictedContext实例,它有两个主要函数被禁掉:registerReceiver()和 bindService()。这两个函数在BroadcastReceiver.onReceive()不允许调用。每次Receiver处理一个广播,传递进来的context都是一个新的实例。
Context context = mInitialApplication.getBaseContext();
Context receiverContext = ContextImpl.getReceiverRestrictedContext.call(context);
String className = data.component.getClassName();
// 实例化目标 Receiver
BroadcastReceiver receiver = (BroadcastReceiver) context.getClassLoader().loadClass(className).newInstance();
mirror.android.content.BroadcastReceiver.setPendingResult.call(receiver, result);
data.intent.setExtrasClassLoader(context.getClassLoader());
if (data.intent.getComponent() == null) {
data.intent.setComponent(data.component);
}
//手动调用onCreate
receiver.onReceive(receiverContext, data.intent);
//通知Pending结束
if (mirror.android.content.BroadcastReceiver.getPendingResult.call(receiver) != null) {
result.finish();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(
"Unable to start receiver " + data.component
+ ": " + e.toString(), e);
}
//远程通知Vaservice广播已经收到
VActivityManager.get().broadcastFinish(data.resultData);
}
new 了真正的 Receiver 然后调用 onCreate 而已
BroadcastSystem.broadcastFinish()
broadCast 发送有个超时机制
void broadcastFinish(PendingResultData res) {
synchronized (mBroadcastRecords) {
BroadcastRecord record = mBroadcastRecords.remove(res.mToken);
if (record == null) {
VLog.e(TAG, "Unable to find the BroadcastRecord by token: " + res.mToken);
}
}
mTimeoutHandler.removeMessages(0, res.mToken);
res.finish();
}
private final class TimeoutHandler extends Handler {
TimeoutHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
IBinder token = (IBinder) msg.obj;
BroadcastRecord r = mBroadcastRecords.remove(token);
if (r != null) {
VLog.w(TAG, "Broadcast timeout, cancel to dispatch it.");
r.pendingResult.finish();
}
}
}
这里如果广播超时则会通知 PendingResult 结束,告诉发送方广播结束了。
static class BroadcastIntent extends MethodProxy {
@Override
public String getMethodName() {
return "broadcastIntent";
}
@Override
public Object call(Object who, Method method, Object... args) throws Throwable {
Intent intent = (Intent) args[1];
String type = (String) args[2];
intent.setDataAndType(intent.getData(), type);
if (VirtualCore.get().getComponentDelegate() != null) {
VirtualCore.get().getComponentDelegate().onSendBroadcast(intent);
}
Intent newIntent = handleIntent(intent);
if (newIntent != null) {
args[1] = newIntent;
} else {
return 0;
}
if (args[7] instanceof String || args[7] instanceof String[]) {
// clear the permission
args[7] = null;
}
return method.invoke(who, args);
}
private Intent handleIntent(final Intent intent) {
final String action = intent.getAction();
if ("android.intent.action.CREATE_SHORTCUT".equals(action)
|| "com.android.launcher.action.INSTALL_SHORTCUT".equals(action)) {
return VASettings.ENABLE_INNER_SHORTCUT ? handleInstallShortcutIntent(intent) : null;
} else if ("com.android.launcher.action.UNINSTALL_SHORTCUT".equals(action)) {
handleUninstallShortcutIntent(intent);
} else if (BadgerManager.handleBadger(intent)) {
return null;
} else {
return ComponentUtils.redirectBroadcastIntent(intent, VUserHandle.myUserId());
}
return intent;
}
}
ComponentUtils.redirectBroadcastIntent()
public static Intent redirectBroadcastIntent(Intent intent, int userId) {
Intent newIntent = intent.cloneFilter();
newIntent.setComponent(null);
newIntent.setPackage(null);
ComponentName component = intent.getComponent();
String pkg = intent.getPackage();
if (component != null) {
newIntent.putExtra("_VA_|_user_id_", userId);
//显示意图被重定向成_VA_PKGNAME_CLASSNAME 的格式,与前面注册的时候对应
newIntent.setAction(String.format("_VA_%s_%s", component.getPackageName(), component.getClassName()));
newIntent.putExtra("_VA_|_component_", component);
newIntent.putExtra("_VA_|_intent_", new Intent(intent));
} else if (pkg != null) {
newIntent.putExtra("_VA_|_user_id_", userId);
newIntent.putExtra("_VA_|_creator_", pkg);
newIntent.putExtra("_VA_|_intent_", new Intent(intent));
String protectedAction = SpecialComponentList.protectAction(intent.getAction());
if (protectedAction != null) {
newIntent.setAction(protectedAction);
}
} else {
newIntent.putExtra("_VA_|_user_id_", userId);
newIntent.putExtra("_VA_|_intent_", new Intent(intent));
String protectedAction = SpecialComponentList.protectAction(intent.getAction());
if (protectedAction != null) {
newIntent.setAction(protectedAction);
}
}
return newIntent;
}
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) {
try {
ActivityThread.installProvider(mainThread, app, cpi, null);
} catch (Throwable e) {
e.printStackTrace();
}
}
} 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;
}
}
依旧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();
}
}
这里主要做了几件事情:
VActivityManagerService.acquireProviderClient()
public IBinder acquireProviderClient(int userId, ProviderInfo info) {
ProcessRecord callerApp;
synchronized (mPidsSelfLocked) {
callerApp = findProcessLocked(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():
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 的过程正式完成。
借鉴于:https://blog.csdn.net/ganyao939543405/article/details/76146760