Android 三方APP调用系统隐藏API

背景

在Android系统中,出于保护目的,Android framework对有些API 添加了@hide,@SystemApi注解,三方APP是无法直接通过SDK调用的。但有时我们有功能需求,期望我们的APP可以调用系统隐藏API,或我们在framework service开发了某个API,期望我们的APP可以调用这些隐藏API。

这里介绍3种Android三方APP调用系统隐藏API的方法

系统隐藏API,我们以WifiManager中的getVerboseLoggingLevel()为例,其没有权限检查,三方APP可以通过下面演示的三种方式直接调用。

http://androidxref.com/9.0.0_r3/xref/frameworks/base/wifi/java/android/net/wifi/WifiManager.java#3561

3556    /**
3557     * Get the WiFi verbose logging level.This is used by settings
3558     * to decide what to show within the picker.
3559     * @hide
3560     */
3561    public int getVerboseLoggingLevel() {
3562        try {
3563            return mService.getVerboseLoggingLevel();
3564        } catch (RemoteException e) {
3565            throw e.rethrowFromSystemServer();
3566        }
3567    }

1. 通过APP加载framework编译的classes jar的方式访问隐藏API

1.1 我这里访问的WifiManager.getVerboseLoggingLevel API,其位于com.android.wifi.apex里面,所以其classes jar位于SSI分支编译结果的下面目录。

ssi-code-branch\out_sys\target\common\obj\JAVA_LIBRARIES\framework-wifi.com.android.wifi_intermediates\classes.jar

如果你们API位于framework目录,相应需要去比如下面目录找。

ssi-code-branch\out_sys\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar

1.2 拷贝classes.jar到APP源码HideApiDemo\app\libs目录,并更名classes.jar 为com.android.wifi.classes.jar,方便识别。

1.3 在HideApiDemo\app\build.gradle的dependencies里面增加jar编译引入。

    implementation files('libs\\com.android.wifi.classes.jar')

1.4 在Android studio编译过程中Android SDK加载优先级高于我们的com.android.wifi.classes.jar。会导致隐藏API访问失败,所以我们需要修改一下sdk加载优先级。在HideApiDemo\app\build.gradle增加下面内容。

gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
        Set<File> fileSet = options.bootstrapClasspath.getFiles()
        List<File> newFileList = new ArrayList<>();
        newFileList.add(new File("libs/com.android.wifi.classes.jar"))
        newFileList.addAll(fileSet)
        options.bootstrapClasspath = files(
                newFileList.toArray()
        )
    }
}

1.5 接着我们就可以直接在java代码调用WifiManager.java中的隐藏API。

    private int getVerboseLoggingLevel_method_1() {
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        try {
            return wifiManager.getVerboseLoggingLevel();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

2. 通过反射方式调用系统隐藏API。

可以使用java现有反射API实现下面逻辑。

    private int getVerboseLoggingLevel_method_2() {
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        try {
            Class<?> wmClass = Class.forName("android.net.wifi.WifiManager");
            Method getVerboseLoggingLevelMethod = wmClass.getMethod("getVerboseLoggingLevel");
            getVerboseLoggingLevelMethod.setAccessible(true);
            int verboseLoggingLevel = (int) getVerboseLoggingLevelMethod.invoke(wifiManager);
            return verboseLoggingLevel;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

3. 通过代理方式调用系统隐藏API。

3.1 首先我们在APP根目录创建一个AndroidStub的java-library库模块,并根据WifiManager.java在Android源码目录创建其代理类WifiManager.java文件。

3.2 接着我们在APP根目录再创建一个FrameworkProxy的java-library库模块,并创建一个WifiManagerProxy.java 代理类,由该类去调用WifiManager.java中隐藏API。

3.3 在APP根目录的settings.gradle为这两个模块引入编译。

include ':AndroidStub'
include ':FrameworkProxy'

3.4 在HideApiDemo\app\build.gradle的dependencies里面增加代理工程编译引入。

    implementation project(':FrameworkProxy')

3.5 接着我们就可以直接在java代码调用WifiManager.java中的隐藏API。

    private int getVerboseLoggingLevel_method_3() {
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        try {
            if (wifiManager == null) {
                Log.e(TAG, "getVerboseLoggingLevel fails, WifiManager is null");
                return -1;
            }
            return new WifiManagerProxy().getVerboseLoggingLevel(wifiManager);
        } catch (NoClassDefFoundError | NoSuchMethodError e) {
            Log.e(TAG, "getVerboseLoggingLevel API does not support");
        }
        return -1;
    }

这三种方式中,个人最推荐使用第三种方式调用系统隐藏API。因为第一种方式会给APP加载很多不用的类,占用较大APP内存。第二种方式不方便阅读,看着比如复杂。第三方方式兼顾第一第二种方式的优点。

功能调试

编译APK安装手机,执行下面命令,打开Wifi verbose log,
adb shell cmd wifi set-verbose-logging enabled

接着点击APP test1, test2, test3按钮,就可以获取到1的状态值。


执行下面命令,关闭Wifi verbose log,接着点击APP test1, test2, test3按钮,就可以获取到0的状态值。隐藏API调用成功。
adb shell cmd wifi set-verbose-logging disabled

demo 代码及apk见下面链接
链接: https://pan.baidu.com/s/1Owlz9ioYBXA9Tz_uxy2KSw?pwd=5rtm

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值