【VirtualAPP 双开系列04】VirtualAPP 可扩展 AIDL 分析

目录:

  • 1. 什么是 AIDL?
  • 2. 为什么要用 AIDL?
  • 3. VirtualAPP AIDL 使用
  • 4. IPC 总线(IPCBus)动态扩展
  • 5. 总结

 

1. 什么是 AIDL?

AIDL: Android Interface Definition Language, 即 Android 接口定义语言。

 

2. 为什么要用 AIDL?

Android 中每个应用都是独立的进程,拥有自己的虚拟机,虚拟地址,应用之间的内存不止不能互相访问,存在应用隔离,因此两个应用不能像面向对象语言一样直接进行接口的调用。两个进程之间的调用叫做 IPC(进程间通信)。Android 中进程之间的 IPC 调用有:管道、共享内存、消息队列、信号量、socket、binder,从性能、安全角度最终选择了 Binder.

 

3. VirtualAPP AIDL 使用

我们以获取已安装的应用列表为例。

3.1 AIDL

IAppManager.aidl:

package com.android.dockercore.server;

import com.android.dockercore.remote.InstalledAppInfo;

interface IAppManager {
    // ...
    List<InstalledAppInfo> getInstalledApps(int flags);
    // ...
}

InstallAppInfo.aidl:

package com.android.dockercore.remote;

parcelable InstalledAppInfo;

3.2 Java

InstalledAppInfo 对应的 java 类:

public final class InstalledAppInfo implements Parcelable {

    public String packageName;
    public String apkPath;
    public String libPath;
    public boolean dependSystem;
    public int appId;

    public InstalledAppInfo(String packageName, String apkPath, String libPath, boolean dependSystem, boolean skipDexOpt, int appId) {
        this.packageName = packageName;
        this.apkPath = apkPath;
        this.libPath = libPath;
        this.dependSystem = dependSystem;
        this.appId = appId;
    }

    public File getOdexFile() {
        return VEnvironment.getOdexFile(packageName);
    }

    public ApplicationInfo getApplicationInfo(int userId) {
        return VPackageManager.get().getApplicationInfo(packageName, 0, userId);
    }

    public PackageInfo getPackageInfo(int userId) {
        return VPackageManager.get().getPackageInfo(packageName, 0, userId);
    }

    public int[] getInstalledUsers() {
        return DockerCore.get().getPackageInstalledUsers(packageName);
    }

    public boolean isLaunched(int userId) {
        return DockerCore.get().isPackageLaunched(userId, packageName);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.packageName);
        dest.writeString(this.apkPath);
        dest.writeString(this.libPath);
        dest.writeByte(this.dependSystem ? (byte) 1 : (byte) 0);
        dest.writeInt(this.appId);
    }

    protected InstalledAppInfo(Parcel in) {
        this.packageName = in.readString();
        this.apkPath = in.readString();
        this.libPath = in.readString();
        this.dependSystem = in.readByte() != 0;
        this.appId = in.readInt();
    }

    public static final Creator<InstalledAppInfo> CREATOR = new Creator<InstalledAppInfo>() {
        @Override
        public InstalledAppInfo createFromParcel(Parcel source) {
            return new InstalledAppInfo(source);
        }

        @Override
        public InstalledAppInfo[] newArray(int size) {
            return new InstalledAppInfo[size];
        }
    };
}

再看看编译生成的 IAppManager java 类:

public interface IAppManager extends android.os.IInterface {

    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.android.dockercore.server.IAppManager {

        private static final java.lang.String DESCRIPTOR = "com.android.dockercore.server.IAppManager";

        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.android.dockercore.server.IAppManager interface,
         * generating a proxy if needed.
         */
        public static com.android.dockercore.server.IAppManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.android.dockercore.server.IAppManager))) {
                return ((com.android.dockercore.server.IAppManager) iin);
            }
            return new com.android.dockercore.server.IAppManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case TRANSACTION_getInstalledAppInfo: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _arg1;
                    _arg1 = data.readInt();
                    com.android.dockercore.remote.InstalledAppInfo _result = this.getInstalledAppInfo(_arg0, _arg1);
                    reply.writeNoException();
                    if ((_result != null)) {
                        reply.writeInt(1);
                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.android.dockercore.server.IAppManager {

            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public com.android.dockercore.remote.InstalledAppInfo getInstalledAppInfo(java.lang.String pkg, int flags) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                com.android.dockercore.remote.InstalledAppInfo _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(pkg);
                    _data.writeInt(flags);
                    mRemote.transact(Stub.TRANSACTION_getInstalledAppInfo, _data, _reply, 0);
                    _reply.readException();
                    if ((0 != _reply.readInt())) {
                        _result = com.android.dockercore.remote.InstalledAppInfo.CREATOR.createFromParcel(_reply);
                    } else {
                        _result = null;
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_getInstalledAppInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
    }

    public com.android.dockercore.remote.InstalledAppInfo getInstalledAppInfo(java.lang.String pkg, int flags) throws android.os.RemoteException;
}

 

3.3 如何添加 IBinder

3.4 获取 IInterface 进行使用

 

4. IPC 总线(IPCBus)动态扩展

AIDL 虽然让跨进程通信变得很简单,但无法实现运行时,动态扩展功能。每次 AIDL 的接口变化,都需要重新编译。在 VirtualApp 里,通过 IPC 总线,实现了运行时动态的扩展能力。

AIDL 自动生成的 Stub 和 Stub.Proxy 的主要功能:

  • 生成 code,如TRANSACTION_getPid, TRANSACTION_getMyData,用于传输方法名的传输
  • 传输方法名 (即 code) 和方法参数,调用真正实现类对应的方法

 

通过 IPC 总线实现这两个能力后,就可以实现运行时增加通信能力,整体框架如下:

 

5. 总结

客户端要获取 IBinder 对象有两种方式:

  • 异步获取:通过绑定 Service 获取
  • 同步获取:通过 ContentProvider 获取


整体过程如下图所示:

 

参考:

https://handsomeliuyang.github.io/2020/08/09/%E7%BB%8F%E9%AA%8C%E6%80%BB%E7%BB%93/%E5%8F%8C%E5%BC%80%E7%B3%BB%E5%88%97%EF%BC%9AAIDL%E5%8E%9F%E7%90%86%E7%AE%80%E4%BB%8B%E5%8F%8A%E5%8A%A8%E6%80%81%E6%89%A9%E5%B1%95%E5%AE%9E%E7%8E%B0/

 




 

简介VirtualApp是一个App虚拟化引擎(简称VA)。VirtualApp已兼容Android 0(8.0 Preview)。VirtualApp在你的App内创建一个虚拟空间,你可以在虚拟空间内任意的安装、启动和卸载APK,这一切都与外部隔离,如同一个沙盒。运行在VA中的APK无需在外部安装,即VA支持免安装运行APK。VA目前被广泛应用于双开/多开、应用市场、模拟定位、一键改机、隐私保护、游戏修改、自动化测试、无感知热更新等技术领域,但它决不仅限于此,Android本身就是一个极其开放的平台,免安装运行APK这一Feature打开了无限可能--------这都取决于您的想象力。申明当您需要将VirtualApp用于商业用途时,请务必联系QQ:10890 购买商业授权。您如果未经授权将VirtualAppApp模块作为您自己的App用于牟利或上传软件市场,我们取证后将直接报警(侵犯著作权罪)。购买商业授权是对我们最大的支持和认可,我们将投入更多精力和时间来不断完善优化VirtualApp,作为购买商业授权的回报,您可以获得未开放的商业版本和1vs1的支持(技术、运营、预警)!同时我们也支持基于VirtualAppAPP订制开发,请联系:QQ:10890 洽谈。请注意VirtualApp代码的更新频率非常快(以小时为单位),每一次代码的更新都有可能修复重大BUG,所以请 watch 本项目,并注意随时更新代码,以免给您带来损失!已支持的加固(不断更新)360加固腾讯加固梆梆加固梆梆企业版(12306客户端 Pass)爱加密百度加固娜迦加固乐变加固网易易盾通付盾(已支持的加固均可通过VA来脱壳,本技术不公开)在VA使用Google服务VA支持运行官方的Google服务套件,同时我们也提供了对MicroG的支持。您可以通过在VA中安装MicroG来支持Google服务,这样,即使外部没有Google服务,用户也可以在VA中享受Google服务。MicroG套件可在此下载:Download MicroGMicroG的必要模块:Services CoreServices Framework ProxyStore如果您需要在VA中使用官方的Google服务套件(外部已安装的前提下),则可以通过 GmsSupport.installGms(userId) 来安装。注意,您不能同时安装MicroGms和官方的Gms。使用说明前往你的Application并添加如下代码:@Override     protected void attachBaseContext(Context base) {         super.attachBaseContext(base);         try {             VirtualCore.getCore().startup(base);         } catch (Throwable e) {             e.printStackTrace();         }     }安装App:VirtualCore.getCore().installApp({APK PATH}, flags);启动App:VirtualCore.getCore().uninstallApp({PackageName});该App的基本信息:VirtualCore.getCore().findApp({PackageName});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值