Bootstrap

浅谈VirtualApp

VA初始化操作

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就开始执行安装

Client App 的安装

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 的安装主要完成以下几件事情:

  1. 解析 manifest 拿到 apk 内部信息,包括组件信息,权限信息等。并将这些信息序列化到磁盘和内存中,以备打开时调用。
  2. 准备 App 在 VA 沙箱环境中的私有空间,并且复制一些必要的 apk 和 so libs。
  3. 最后通知前台安装完成。

解析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。

APP启动

VAService与通讯

VAservice

VirtualApp\lib\src\main\java\com\lody\virtual\server\am\*

首先,VAService 是指 VA 仿造 Android 原生 framework 层 Service 实现的一套副本,举例有 VActivityManagerService,它和系统 AMS 一样,只不过他管理的是 VA 内部 Client App 的组件会话。

VAService 统一管理

首先所有 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,而前台服务则不受影响。

ServiceFetcher

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

启动App

首先要了解的是 Android App 是组件化的,Apk 其实是 N 多个组件的集合,以及一些资源文件和 Assert,App 的启动有多种情况,只要在一个新的进程中调起了 apk 中任何一个组件,App 将被初始化,Application 将被初始化。

启动Activity

Hook startActivity(重定位 Intent 到 StubActivity)

首先在 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。
这个函数需要注意以下几点:

  1. VA 有意将安装和卸载 APP 的请求重定向到了卸载 VA 内部 APK 的逻辑。
  2. resolveActivityInfo 调用到了 VPM 的 resolveIntent,最终会远程调用到 VPMS 的 resolveIntent,然后 VPMS 就会去查询 VPackage 找到目标 Activity 并将信息附加在 ResolveInfo 中返回 VPM。
  3. 最后也是最重要的一点,startActivity 会调用到 VAM.startActivity,同样最终会远程调用到 VAMS 的 startActivity。
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);
    }
}
初始化 Application

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);
    }
恢复原 Intent 重定向到原 Activity

当 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 主要做了以下几个事情:

  1. 从 VPMS 获取 APK 的信息,根据设置控制 Dex 优化的开关。
  2. 调用 mirror.android.os.Process.setArgV0.call(processName); 设置进程的名称,如果不设置则还是 p0 p1 这样。
  3. 做 nativeHook 主要 Hook 一些 native 的函数,主要是一些 IO 函数,包括文件访问重定向等等。
  4. 准备一些 cache 临时文件夹。
  5. 设置 AppBinderData,AppBinderData 内部包含了 ApplicationInfo 和 provider 信息等重要的 apk 信息。可以理解为 framework 所需要的关键数据结构。
  6. 安装 ContentProvider
  7. 初始化用户的 Application 对象,并通过 Instrumentation 调用其 onCreate,代表着 Client App 的生命周期正式开始。

最后成功从 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);
}

启动插件 Service

原生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 调度中其实没有发挥什么作用。原因有以下几点:

  1. 首先 VA 内部的插件 Service 没有比较暴露给外部 App 调用,所以让 AMS 知晓 Service 的意义不大。
    其次和 Activity 必须有个 StubActivity 让 AMS 持有不一样,Service 生命周期和功能都极其简单,并且没有界面,没有交互,换句话说 Service 和其他 Framework Service(例如 WMS) 没有任何关系,所以其实并不需要 AMS 这一步存在。

  2. 那么综上所诉,为了启动插件 Service 我们其实可以绕过 AMS,直接调用 ApplicationThread 中的 scheduleCreateService 方法,Service 的会话储存交给 VAMS 就行。

startService 的实现

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

这里主要做了以下几个工作:

  • 和 Activity 创建的时候一样,调用 startProcessIfNeedLocked 检查 Application 是否初始化,没有则开始初始化 Application 流程。
  • 准备 ServiceRecord 和 ServiceInfo。
  • 如果 service 还没有创建,则直接调用 ApplicationThread.scheduleCreateService 创建 Service,可以看出这里直接跳过了 AMS。
  • 将 ServiceRecord 记录到 Service 列表,等待 bindService,如果是通过 bindService 自动创建的 Service,在创建 Service 完成后会进入 bindService 流程。
  • 同样的 bindService 也是直接调用系统的 ApplicationThread.scheduleBindService

BroadcastReceiver

VA 静态广播注册

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 注册。

  1. 首先注册 Receiver 的显式意图,每个显式意图被重定向成格式为 “VA_PKGNAME_CLASSNAME”的 componentAction 这么做的理由实际是真正注册是 VAService 进程空间的 StaticBroadcastReceiver 代理 Receiver,而不是 VA Client App 进程空间,所以直接注册 VA Client App 中的真实类名是没有意义的,这样通过 VAService 代理然后再从 Intent 中取出的 “VA_PKGNAME_CLASSNAME”到 VA Client 中找到真正的 Receiver,这个逻辑和 Activity 的处理有些相似。
  2. 然后就是遍历 Intent-Filter,每个 Intent-Filter 注册一个 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;
    }
}
  • 这里拦截了创建快捷图标的 Intent,这是一个发给 Launcher 的隐式广播,VA 把这个请求拦截下来因为如果不拦截这个快捷方式就会指向外部的 App,并且如果外部 App 没有安装,此广播也不会发生作用。VA 把这个广播换成了自己的逻辑。
  • 注意 ComponentUtils.redirectBroadcastIntent(), 类似 Activity 用代理 Intent 包裹真正的 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;
}

ContentProvider

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

这里主要做了几件事情:

  1. 通过 VPMS 拿到解析好的目标 ProviderInfo,启动目标 Provider 所在的进程,怎么启动?远程调用 VAMS,然后 VAMS 再通过 AMS 远程调用注册在插件进程的 StubContentProvider.call 初始化插件进程。这时候 VAMS 就会持有目标插件进程的 IClient 句柄,以备后续调用。
  2. 准备 ContentProviderHolder 相关的事情,ContentProviderHolder 有两个成员变量provider、connection,provider 是目标 Provider 的 IBinder 句柄。
  3. 远程调用了 VAMS 的 acquireProviderClient(), 将任务抛给了远端的 VAMS。

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

;