Android修炼之检测非SDK接口

栏目: Android · 发布时间: 6年前

内容简介:上篇文章一般来说,SDK接口是指在Android框架软件包索引中记录的接口,其对立面自然就叫非SDK接口了。Android 9引入了针对非SDK接口的使用限制,无论是直接使用还是通过反射或JNI间接使用。这意味着,通过反射之类的语义来操作某个类时,不应访问SDK中未列出的函数或字段(通常都有Android 9将非SDK接口都放在了各名单中:

上篇文章 Android修炼之Pie 适配的搬运工 中介绍了Android P的一些行为变更并提供了一些对齐刘海和非SDK接口的适配建议,大部分人还是更加关心非SDK接口的问题,所以本文来说一下如何检测非SDK接口。

区分SDK接口和非SDK接口

一般来说,SDK接口是指在Android框架软件包索引中记录的接口,其对立面自然就叫非SDK接口了。Android 9引入了针对非SDK接口的使用限制,无论是直接使用还是通过反射或JNI间接使用。这意味着,通过反射之类的语义来操作某个类时,不应访问SDK中未列出的函数或字段(通常都有 @hide 标志)。

Android 9将非SDK接口都放在了各名单中:

  1. 白名单:自然就是可以直接使用的SDK接口;
  2. 浅灰名单:仍可以访问的非 SDK 函数/字段;
  3. 深灰名单:包含我们在开发期间未看到使用,但是我们可能已经忽视的函数/字段。列入深灰名单的函数/字段是那些与SDK和浅灰名单中的公开接口紧密相关的函数/字段。
    • 对于目标SDK低于API级别28的应用,允许使用深灰名单接口;
    • 对于目标SDK为API 28或更高级别的应用:行为与黑名单相同;
  4. 黑名单:受限,无论目标SDK如何。平台将表现为似乎接口并不存在。

这些名单都可以在:非SDK接口名单中找到。如果不想编译AOSP,可以直接下载该页的 tgz 文件,解压即可看到对应的 txt 文件。

如何检测非SDK接口?

查看logcat日志

在Android 9的系统中,如你的应用中使用了非SDK接口,系统将会在APP运行时打印日志;如果访问了某些“列入灰名单的”非SDK接口,系统还可能显示Toast;如果访问了“列入黑名单的”非SDK接口,系统将引发异常。

日志消息

在开发过程中,我们可以通过AS的logcat来查看日志,否则就是通过 adb logcat 了。非SDK接口的日志会显示在正在运行的应用的PID下,大概格式是:

Accessing hidden field Landroid/net/wifi/WifiManager;->WIFI_SCAN_AVAILABLE:Ljava/lang/String; (dark greylist, reflection)
复制代码
  • Accessing hidden:固定格式
  • field:可能是method,表示调用的是属性还是方法
  • Landroid/net/wifi/WifiManager:表示调用的类名
  • ->WIFI_SCAN_AVAILABLE:Ljava/lang/String;:表示调用的属性和方法名
  • (dark greylist, reflection):前半部分表示该非SDK接口在哪个名单中,后半部分表示被调用的方式,比如:reflection(反射)和JNI

这里给出几个示例:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        Field field = null;
        try {
            field = wifiManager.getClass().getDeclaredField("WIFI_SCAN_AVAILABLE");
            Log.d("ThirdActivity", (String) field.get(wifiManager));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 直接在浅灰名单中找的接口
    public void testLightGreyList(View view) {
        ReflectUtils.getMethod(TelephonyManager.class, "isMultiSimEnabled");
    }

    // 直接在深灰名单中找的接口
    @TargetApi(Build.VERSION_CODES.M)
    public void testDarkGreyList(View view) {
        ReflectUtils.getField(CarrierConfigManager.class, "KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL");
    }

    // 直接在黑名单中找的接口
    public void testBlackList(View view) {
        try {
            ReflectUtils.getMethod(ReflectUtils.getClass("android.net.util.IpUtils"), "ipChecksum", ByteBuffer.class, int.class);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
复制代码

他们的日志如下:

Accessing hidden field Landroid/net/wifi/WifiManager;->WIFI_SCAN_AVAILABLE:Ljava/lang/String; (dark greylist, reflection)
Accessing hidden method Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z (light greylist, reflection)
Accessing hidden field Landroid/telephony/CarrierConfigManager;->KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL:Ljava/lang/String; (dark greylist, reflection)
Accessing hidden method Landroid/net/util/IpUtils;->ipChecksum(Ljava/nio/ByteBuffer;I)S (blacklist, reflection)
复制代码

注意:在debug的时候,只有触发了对应的调用逻辑,才会打印日志,而不是静态检测。所以新项目中,我们在开发过程中就要注意非SDK接口的调用。

Toast和Dialog提示

可能因为我的模拟器用的是Android P的正式版,去除了Toast提示。所以,在测试的时候并没有看到相关的Toast提示。在预览版中应该有Toast提示功能。当然,也可能是我没有触发“某些灰名单中的非SDK接口”(官方文档原话)的原因。

不过,当我把TargetSDK改为27时,出现过这种对话框提示:

Android修炼之检测非SDK接口

引发异常

官方说明:

Android修炼之检测非SDK接口

经测试,只有 深灰名单黑名单 中的非SDK接口会引发异常和错误。

注意:当TargetSDK>=28时,深灰名单和黑名单都会引发异常;而当TargetSDK<28时,只有黑名单会引发异常。示例结果如下:

Android修炼之检测非SDK接口
Android修炼之检测非SDK接口

使用veridex检测工具

谷歌提供了一个静态检测工具:veridex,可以帮助我们检测apk中是否使用了非SDK接口。这里使用 veridex-linux.zip 进行测试,解压后目录结构如下:

Android修炼之检测非SDK接口
可以看到它里面包含了各名单的txt文件,其中 appcompat.sh

就是运行脚本。

将待检测的apk文件拷贝到veridex目录下,运行以下命令即可:

./appcompat.sh --dex-file=文件名.apk --imprecise
复制代码

结果:

Android修炼之检测非SDK接口

这里显示的数量明显比我们示例中的多,这是为什么?观察详细内容,发现veridex把Android自己调用的也检测出来了。

如果去掉 --imprecise 会检测不出来黑名单的接口。

Android修炼之检测非SDK接口

我们可以通过重定向将日志保存在文件中,再进行细致的分析。

我们主要关注黑名单和深灰名单。可以看到,日志中给出了调用非SDK接口的位置,很容易定位。

Android修炼之检测非SDK接口

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax for Web Application Developers

Ajax for Web Application Developers

Kris Hadlock / Sams / 2006-10-30 / GBP 32.99

Book Description Reusable components and patterns for Ajax-driven applications Ajax is one of the latest and greatest ways to improve users’ online experience and create new and innovative web f......一起来看看 《Ajax for Web Application Developers》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换