Android修炼之检测非SDK接口

avatar
Android @奇舞团Android团队

前言

上篇文章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时,出现过这种对话框提示:

Dialog提示

引发异常

官方说明:

非SDK接口引发后果

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

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

深灰名单引发异常

黑名单引发异常

使用veridex检测工具

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

veridex
可以看到它里面包含了各名单的txt文件,其中appcompat.sh就是运行脚本。

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

./appcompat.sh --dex-file=文件名.apk --imprecise

结果:

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

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

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

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

定位问题

总结

  1. 在开发过程中可以通过日志查看是否调用了非SDK接口;
  2. 主要注意深灰名单和黑名单的接口调用,虽然程序中经常写有try catch,但还是竟可能找到绕过或者替代的方案;
  3. 使用veridex分析apk时,最好带上--imprecise参数,可以看到更多详细的信息;
  4. 示例代码:github.com/zjxstar/And…

参考资料

  1. 官网
  2. 史上最严管控,Android P非SDK接口管控特性解读及适配
  3. Android P非SDK的隐藏API调用检测

关注微信公众号,最新技术干货实时推送

image