从Android P开始,谷歌开始对非 SDK 接口使用进行限制,该变更被称为Android史上最严管控之一。在Android Q中,谷歌继续加强了对非SDK接口的使用限制,黑名单接口数量大幅增长,部分非SDK接口被删除,将导致大面积应用无法正常使用的问题,需要开发者重点关注并进行适配。
变更介绍
1、非SDK接口定义
SDK接口:
谷歌官方网站能查到的接口都是SDK接口,查询链接:
https://developer.android.com/reference/packages
非SDK接口:
除了谷歌开放的SDK接口之外的其他JAVA接口都是非SDK接口。
2、滥用非SDK接口的危害
非SDK接口在Android不同版本间存在很大的差异,使用非SDK接口容易带来兼容性问题。
3、非SDK接口管控名单说明
1、名单类型说明
名单类型
影响
greylist
targetSDK>=P时,警告
greylist-max-o
targetSDK<P时,警告;>=P时,不允许调用
greylist-max-p
targetSDK<Q时,警告;>=Q时,不允许调用
blacklist
所有三方应用不允许调用
2、名单查看
开发者可以使用预编译版本的veridex工具来查看非sdk接口名单。veridex 工具链接:
https://android.googlesource.com/platform/prebuilts/runtime/+/refs/heads/master/appcompat/
该工具目录下面的hiddenapi-flags.csv文件就是所有的SDK和非SDK接口名单及其对应的接口类型,开发者可以下载查看。
3、名单变化
•Android P 中109810个接口被加入了Android Q 接口黑名单;
•Android P 中10642个接口(非SDK+SDK)在Android Q中被删除。
*注:以上数据基于Android Q Beta 1统计。
变更影响
1、影响范围
所有非系统应用都可能会受到影响,从名单变化来看,黑名单接口大大增加,Q版本有很多非SDK接口被删除,都会导致应用出现兼容性问题,影响很大,需要所有应用排查和整改。
在Android Q beta被删除的非SDK接口中,部分接口依然存在应用调用,导致了明显的兼容性问题。目前已经测试发现,很多应用由于调用Landroid/view/DisplayListCanvas;->callDrawGLFunction2(J)V接口出现了crash 问题,开发者应重点关注。其余调用较多的接口名单如下:
<pre style="margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
Landroid/app/INotificationManager;->enqueueToast(Ljava/lang/String;Landroid/app/ITransientNotification;I)V
Landroid/graphics/drawable/StateListDrawable;->getStateDrawableIndex([I)I
Landroid/hardware/fingerprint/Fingerprint;->getFingerId()I
Landroid/media/MediaFile;->isWMAEnabled()Z
Landroid/media/MediaFile;->isWMVEnabled()Z
Landroid/media/MediaFile;->sMimeTypeMap:Ljava/util/HashMap;
Landroid/media/ThumbnailUtils$SizedThumbnailBitmap;-><init>(Landroid/media/ThumbnailUtils$1;)V
Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap;
Landroid/telephony/SignalStrength;->mCdmaDbm:I
Landroid/telephony/SignalStrength;->mCdmaEcio:I
Landroid/telephony/SignalStrength;->mEvdoDbm:I
Landroid/telephony/SignalStrength;->mEvdoEcio:I
Landroid/telephony/SignalStrength;->mEvdoSnr:I
Landroid/telephony/SignalStrength;->mGsmBitErrorRate:I
Landroid/telephony/SignalStrength;->mGsmSignalStrength:I
Landroid/view/DisplayListCanvas;->callDrawGLFunction2(J)V
Landroid/view/DisplayListCanvas;->drawGLFunctor2(JLjava/lang/Runnable;)V
Landroid/view/DisplayListCanvas;->drawRenderNode(Landroid/view/RenderNode;)V
Landroid/view/RenderNode;->create(Ljava/lang/String;Landroid/view/View;)Landroid/view/RenderNode;
Landroid/view/RenderNode;->discardDisplayList()V
Landroid/view/RenderNode;->end(Landroid/view/DisplayListCanvas;)V
Landroid/view/RenderNode;->isValid()Z
Landroid/view/RenderNode;->output()V
Landroid/view/RenderNode;->setClipToBounds(Z)Z
Landroid/view/RenderNode;->setLeftTopRightBottom(IIII)Z
Landroid/webkit/TokenBindingService$TokenBindingKey;-><init>()V
Landroid/widget/TextView;->onProvideStructure(Landroid/view/ViewStructure;)V
Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
Lcom/android/internal/telephony/CallManager;->getAllPhones()Ljava/util/List;
Lcom/android/internal/telephony/CommandsInterface$RadioState;->isOn()Z
Lcom/android/internal/telephony/CommandsInterface;->getRadioState()Lcom/android/internal/telephony/CommandsInterface$RadioState;
Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(ZLjava/lang/String;)Z
Lcom/android/internal/telephony/dataconnection/DcTracker;->onDataSetupComplete(Landroid/os/AsyncResult;)V
Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V
Lcom/android/internal/telephony/ITelephony;->endCall()Z
Lcom/android/internal/telephony/ITelephony;->getVoiceMessageCount()I
Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataConnectionFailed(Ljava/lang/String;Ljava/lang/String;)V
</pre>
2、兼容性表现
在DeveloperPreview的后续版本中,访问non-SDK接口的各种方法都会产生错误或其他不良结果,具体如下表所示:
适配指导
1、获取应用使用的所有非SDK接口列表
方法1:通过扫描分析动态运行日志获取
a) 关键日志
Accessing hidden fieldLandroid/os/Message;->flags:I (light greylist, JNI)
b)调试命令
在Android Q中,启用对非SDK接口的访问的命令已更改,开发者需要通过更改API强制策略来启用对开发设备上的非SDK接口的访问,ADB命令如下:
adb shell settings put globalhidden_api_policy 1
API强制策略中的整数值可以设置为以下三个选项:
0:禁用所有非SDK接口检测。使用此设置会禁用非SDK接口使用的所有日志消息,并阻止您使用StrictMode API测试应用程序。
1:允许访问所有非SDK接口,但打印日志消息,并显示任何非SDK接口使用情况的警告,使用此设置还允许您使用StrictMode API测试您的应用程序。
2:禁止使用属于黑名单的非SDK接口或目标API级别的受限制灰名单。
建议开发者将数值设置为1,再通过自动化或人工测试遍历应用所有功能和界面,然后通过抓取的日志分析调用的非SDK接口。
如需将API强制策略重置,可以使用以下命令进行设置:
adb shell settings deleteglobal hidden_api_policy
*以上命令不需要root设备。
方法2:通过谷歌提供的veridex静态扫描工具获取
veridex静态扫描工具下载链接:
https://android.googlesource.com/platform/prebuilts/runtime/+/refs/heads/master/appcompat/
使用说明请查看压缩包中README.txt文件,如果是linux系统,可以参考以下方法进行使用:
Linux x64
Download veridex-linux.zip,unzip the file and run with:
./appcompat.sh--dex-file=test.apk(替换成开发者自己的apk文件路径)
2、非SDK接口整改
三方应用需要重点关注max-o、max-p和黑名单的非SDK接口,需要找可替代的SDK接口进行适配。
3、无法整改的接口申请添加到浅灰名单
如果应用无法找到可替代的SDK接口整改,而且必须要使用这个非SDK接口,建议开发者直接给谷歌反馈申请新的公共API,申请链接:https://partnerissuetracker.corp.google.com/issues/new?component=328403&template=1027267
开发者需要按照下面的模板反馈信息:
反馈的信息需要包括:
- 使用的非SDK接口详细信息:
- Accessing hidden fieldLandroid/os/Message;->flags:I (light greylist, JNI)
- 使用这些API的原因,包括接口使用的详细场景描述
- 为什么任何相关的公共SDK API不足以满足您的需要。
- 您尝试过的任何其他替代方案以及为什么这些方法都无法解决。
网友评论