行为变更:所有应用

Android 10 包含一些可能会影响您的应用的行为变更。本页面列出的变更适用于在 Android 10 上运行的应用(无论应用的 targetSdkVersion 如何)。您应该测试 并根据需要进行修改,以适当地支持这些更改。

如果您的应用的 targetSdkVersion 为 29 或更高,则您还需要支持其他变更。请务必阅读针对应用的行为变更 目标 29

注意 :除了本页列出的变更外,Android 10 引入了大量基于隐私的更改和限制,包括 以下:

  • 在后台访问设备位置信息
  • 从后台启动 Activity
  • 联系人亲密程度信息
  • 随机分配 MAC 地址
  • 相机元数据
  • 权限模型

这些变更会影响所有应用并加强用户隐私。要详细了解 如何支持这些更改,请参阅 隐私权变更页面。

限制非 SDK 接口

为了帮助确保应用的稳定性和兼容性,Android 平台开始限制应用在 Android 9(API 级别 28)中使用非 SDK 接口。Android 10 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。我们的目标是 在限制使用非 SDK 接口之前,可能会提供替代方案。

如果您不以 Android 10(API 级别 29)为目标平台,那么其中一些变更 可能不会立即对您产生影响。然而,虽然您目前仍可以使用一些非 SDK 接口(具体取决于应用的目标 API 级别),但只要您使用任何非 SDK 方法或字段,终归存在导致应用出问题的显著风险。

如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用,进行确认。如果您的应用依赖于非 SDK 接口,建议您开始计划迁移到 SDK 替代方案。然而,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,则应请求新的公共 API

如需了解详情,请参阅 Android 10 中有关限制非 SDK 接口的更新以及针对非 SDK 接口的限制

手势导航

从 Android 10 开始,用户可以在 Google Play 商店中 设备。如果用户启用手势导航,这会影响设备上的所有应用 (无论应用是否以 API 级别 29 为目标平台)。例如,如果用户滑入 系统会将该手势解读为“返回” 导航,除非应用针对某些部分明确替换该手势 屏幕上。

为了确保您的应用与手势导航兼容,您需要将应用内容扩展到屏幕边缘,并适当地处理存在冲突的手势。如需了解详情,请参阅手势导航文档。

NDK

Android 10 包含 NDK 方面的以下变更。

共享对象不得包含文本重定位

Android 6.0(API 级别 23)已禁止使用 共享对象中的文本重定位。代码必须按原样加载,不得 修改。此变更可以缩短应用的加载时间并提高安全性。

SELinux 对以 Android 10 为目标平台的应用强制执行此限制 或更高版本。如果这些应用继续使用包含文本的共享对象 因此出现故障的风险较高。

Bionic 库和动态链接器路径变更

从 Android 10 开始,若干路径都采用符号链接,而不是 常规文件如果应用一直以来依赖的都是采用常规文件形式的路径,则可能会出现中断:

  • /system/lib/libc.so -> /apex/com.android.runtime/lib/bionic/libc.so
  • /system/lib/libm.so -> /apex/com.android.runtime/lib/bionic/libm.so
  • /system/lib/libdl.so -> /apex/com.android.runtime/lib/bionic/libdl.so
  • /system/bin/linker -> /apex/com.android.runtime/bin/linker

这些更改也适用于文件的 64 位版本,包括 已将“lib/”替换为“lib64/”。

为了确保兼容性,符号链接会基于旧路径提供。例如: /system/lib/libc.so 是指向 /apex/com.android.runtime/lib/bionic/libc.so。因此 “dlopen(“/system/lib/libc.so”)”会继续运行,但应用会找到 当它们实际尝试通过 /proc/self/maps或类似的值,这并不常见,但我们发现 有些应用会在反黑客攻击流程中采取这种做法。如果是, 应将 /apex/… 路径添加为 Bionic 文件的有效路径。

系统二进制文件/库会映射到只执行内存

从 Android 10 开始,系统二进制文件的可执行段 而库会映射到只执行(不可读取)内存, 技术来防范代码重用攻击。如果您的应用对 标记为只执行的内存段,无论是来自 bug、漏洞还是 有意的内存检查 - 系统会向您的应用发送 SIGSEGV 信号。

您可以通过检查 /data/tombstones/ 中的 tombstone 文件。与只执行相关的崩溃 包含以下中止消息:

Cause: execute-only (no-read) memory access error; likely due to data in .text.

要解决此问题以执行内存检查等操作, 可通过调用 mprotect()。不过,我们强烈建议您将其设置回 因为这种访问权限设置能够更好地 保护您的应用和用户。

安全

Android 10 包含安全方面的以下变更。

TLS 1.3 默认处于启用状态

在 Android 10 及更高版本中,默认情况下会为所有 Google Chat 服务器启用 TLS 1.3 TLS 连接。以下是有关 TLS 1.3 实现的一些重要的详细信息:

  • TLS 1.3 加密套件不可自定义。支持的 TLS 1.3 加密方式 启用 TLS 1.3 时,始终会启用套件。任何尝试停用 方法是调用 setEnabledCipherSuites() 被忽略。
  • 在协商 TLS 1.3 时, HandshakeCompletedListener 对象会在会话添加到会话缓存之前调用。(在 TLS 1.2 中) 和其他以前的版本,这些对象在添加会话之后调用 写入会话缓存)。
  • 在某些情况下,SSLEngine 实例会抛出 SSLHandshakeException已开启 这些实例会抛出 改为 SSLProtocolException (在 Android 10 及更高版本中)。
  • 不支持 0-RTT 模式。

如果需要,您可以通过调用SSLContext SSLContext.getInstance("TLSv1.2")。 您还可以为每个连接启用或停用协议版本,方法是 正在呼叫setEnabledProtocols() 相应对象

TLS 不信任使用 SHA-1 签名的证书

在 Android 10 中,使用 SHA-1 哈希算法的证书 不受信任。根 CA 未颁发此类证书 自 2016 年起,Chrome 或其他主流浏览器不再信任它们。

如果某网站使用的是 SHA-1 证书,则任何尝试连接该网站的操作都将失败。

KeyChain 行为变更和改进

当 TLS 服务器在 TLS 握手中发送证书请求消息时,某些浏览器(如 Google Chrome)允许用户选择证书。截至 Android 10、 KeyChain 对象遵循颁发者和 调用 KeyChain.choosePrivateKeyAlias() 以 向用户显示证书选择提示。需要注意的是,此提示不包含不符合服务器规范的选项。

如果没有可供用户选择的证书, 或设备没有任何 则不会显示证书选择提示。

此外,在 Android 10 或更高版本上,无需具备设备屏幕锁定功能,就能将密钥或 CA 证书导入 KeyChain 对象中。

其他 TLS 和加密更改

TLS 和加密库发生了几项细微更改, 在 Android 10 上生效:

  • AES/GCM/NoPadding 和 ChaCha20/Poly1305/NoPadding 密码会返回更多 来自 getOutputSize() 的准确缓冲区空间大小。
  • 与以下密钥的连接尝试中会忽略 TLS_FALLBACK_SCSV 加密套件: 使用 TLS 1.2 或更高版本的最高协议。由于 TLS 服务器方面的改进 实现,我们不建议尝试 TLS 外部回退。相反, 我们建议依赖于 TLS 版本协商
  • ChaCha20-Poly1305 是 ChaCha20/Poly1305/NoPadding 的别名。
  • 带有尾随点的主机名不属于有效的 SNI 主机名。
  • CertificateRequest 中的 supported_signature_algorithms 扩展为 在为证书响应选择签名密钥时遵循。
  • 不透明的签名密钥(如 Android 密钥库中的密钥)可以 TLS 中的 RSA-PSS 签名。

WLAN 直连广播

在 Android 10 中,以下与 WLAN 直连相关的广播不具有粘性:

如果您的应用依赖于在注册时接收这些广播,因为 之前已保持粘性,请在初始化时使用适当的 get() 方法 获取信息。

WLAN 感知功能

Android 10 扩大了支持范围,现在可以使用 WLAN 感知数据路径轻松创建 TCP/UDP 套接字。如需创建连接到 ServerSocket 的 TCP/UDP 套接字,客户端 设备需要知道服务器的 IPv6 地址和端口。这在之前需要通过频外方式进行通信(例如使用 BT 或 WLAN 感知第 2 层消息传递),或者使用其他协议(例如 mDNS)通过频内方式发现。包含 对于 Android 10 设备,可以在网络设置过程中传达这些信息。

服务器可以执行以下任一操作:

  • 初始化 ServerSocket,并设置或获取要使用的端口。
  • 将端口信息指定为 WLAN 感知网络请求的一部分。

以下代码示例展示了如何将端口信息指定为 网络请求:

Kotlin

val ss = ServerSocket()
val ns = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
  .setPskPassphrase("some-password")
  .setPort(ss.localPort)
  .build()

val myNetworkRequest = NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
  .setNetworkSpecifier(ns)
  .build()

Java

ServerSocket ss = new ServerSocket();
WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier
  .Builder(discoverySession, peerHandle)
  .setPskPassphrase(some-password)
  .setPort(ss.getLocalPort())
  .build();

NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
  .setNetworkSpecifier(ns)
  .build();

然后,客户端会执行 Wi-Fi 感知网络请求以获取 IPv6 并 服务器提供的端口:

Kotlin

val callback = object : ConnectivityManager.NetworkCallback() {
  override fun onAvailable(network: Network) {
    ...
  }
  
  override fun onLinkPropertiesChanged(network: Network,
      linkProperties: LinkProperties) {
    ...
  }

  override fun onCapabilitiesChanged(network: Network,
      networkCapabilities: NetworkCapabilities) {
    ...
    val ti = networkCapabilities.transportInfo
    if (ti is WifiAwareNetworkInfo) {
       val peerAddress = ti.peerIpv6Addr
       val peerPort = ti.port
    }
  }
  override fun onLost(network: Network) {
    ...
  }
};

connMgr.requestNetwork(networkRequest, callback)

Java

callback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    ...
  }
  @Override
  public void onLinkPropertiesChanged(Network network,
      LinkProperties linkProperties) {
    ...
  }
  @Override
  public void onCapabilitiesChanged(Network network,
      NetworkCapabilities networkCapabilities) {
    ...
    TransportInfo ti = networkCapabilities.getTransportInfo();
    if (ti instanceof WifiAwareNetworkInfo) {
       WifiAwareNetworkInfo info = (WifiAwareNetworkInfo) ti;
       Inet6Address peerAddress = info.getPeerIpv6Addr();
       int peerPort = info.getPort();
    }
  }
  @Override
  public void onLost(Network network) {
    ...
  }
};

connMgr.requestNetwork(networkRequest, callback);

Go 设备上的 SYSTEM_ALERT_WINDOW

在 Android 10(Go 版本)设备上运行的应用无法接收 SYSTEM_ALERT_WINDOW 权限。这是因为绘制叠加窗口会占用过多内存, 这对低内存 Android 系统的性能特别不利 设备。

如果在搭载 Android 9 或更低版本的 Go 版设备上运行的应用收到 SYSTEM_ALERT_WINDOW 权限,那么即使 设备升级到 Android 10。不过,尚不具有此权限的应用在设备升级后便无法获得此权限了。

如果 Go 设备上的应用发送包含该操作的 intent ACTION_MANAGE_OVERLAY_PERMISSION, 系统会自动拒绝请求,并将用户转到 Settings 屏幕中,显示该应用不允许使用此权限,因为它 会降低设备的运行速度。如果 Go 设备上的应用调用 Settings.canDrawOverlays(), 该方法始终返回 false。同样,这些限制不适用于 该 SDK 在对设备进行以下更改之前便已获得 SYSTEM_ALERT_WINDOW 权限 已升级到 Android 10。

关于以旧版 Android 系统为目标平台的应用的警告

搭载 Android 10 或更高版本的设备首次向用户发出警告 它们可以运行任何以 Android 5.1(API 级别 22)或更低版本为目标平台的应用。如果应用 需要用户授予权限时,用户也会获得 在允许应用首次运行之前调整应用的权限 。

由于 Google Play 的目标 API 要求, 用户只有在运行尚未更新的应用时才会看到这些警告 。对于通过其他商店分发的应用,我们也将于 2019 年引入类似的目标 API 方面的要求。如需详细了解 有关要求,请参阅在 2019 年

移除了 SHA-2 CBC 加密套件

以下 SHA-2 CBC 加密套件已从平台中移除:

  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

这些加密套件不如使用 GCM 的类似加密套件安全,并且大多数服务器要么同时支持这些加密套件的 GCM 变体和 CBC 变体,要么二者均不支持。

应用使用

Android 10 引入了与应用使用情况相关的以下行为变更:

  • UsageStats 应用使用情况改进 - Android 10 通过 UsageStats(用于 在分屏或画中画模式下使用。此外, Android 10 会正确跟踪免安装应用的使用情况。

  • 按应用开启灰度模式 - Android 10 可以按应用设置灰度显示模式。

  • 按应用设定的分心状态 - Android 10 可以有选择地将应用设置为“分心状态”其中 禁止显示通知,也不会将其显示为推荐的应用。

  • 暂停和播放 - 在 Android 10 中,暂停的应用无法播放音频。

HTTPS 连接变更

如果运行 Android 10 的应用将 null 传递到 setSSLSocketFactory(), IllegalArgumentException 。在以前的版本中,将 null 传入 setSSLSocketFactory() 与传入当前的 default 参数 工厂

android.preference 库已弃用

从 Android 10 开始,将弃用 android.preference 库。开发者应改用 AndroidX preference 库,Android 平台的一部分 Jetpack。如需更多有助于迁移和 请参阅经过更新的设置 指南和我们的公开示例 应用参考文档

ZIP 文件实用程序库变更

Android 10 对 java.util.zip 中的类引入了以下更改: 软件包,用于处理 ZIP 文件。这些更改使得库的行为 在 Android 和其他使用 java.util.zip 的平台之间保持一致。

Inflater

在以前的版本中,Inflater 类中的某些方法 IllegalStateException 是在调用 end() 之后调用的。 在 Android 10 中,这些方法会抛出 NullPointerException

ZipFile

在 Android 10 及更高版本中,针对 ZipFile 采用 FileintCharset 类型的参数时,系统不会抛出 ZipException(如果提供的 ZIP 文件) 不包含任何文件。

ZipOutputStream

在 Android 10 及更高版本中, finish() 方法(位于 ZipOutputStream 不会抛出 ZipException,如果它尝试写入 不包含任何文件的 ZIP 文件的输出流。

摄像头变更

许多使用相机的应用都会假定,如果设备采用纵向配置, 那么实体设备也处于纵向模式,如 相机方向。过去可以做出这样的假设,但 随着可折叠设备等可用外形规格的扩展而发生变化。针对这些设备做出这样的假定可能导致相机取景器的显示产生错误的旋转和/或缩放。

针对 API 级别 24 或更高级别的应用应明确设置 android:resizeableActivity,并提供必要的功能来处理 多窗口操作。

电池用量跟踪

从 Android 10 开始, 重置了 SystemHealthManager 在设备过了很长一段时间后拔掉电源时的电池使用情况统计信息 充电事件。一般来说,主要的充电事件是:设备 已充满电,或者设备电量从几乎耗尽到几乎已耗尽 。

在 Android 10 之前,每当设备 也不管电池电量有多小的变化。

Android Beam 已弃用

在 Android 10 中,我们正式弃用了 Android Beam, 通过近距离无线通信 (NFC) 发起设备间的数据共享。 我们还弃用了一些相关的 NFC API。Android Beam 仍会保留 希望使用它的设备制造商合作伙伴可以选择性提供,但这不是 。不过,Android 仍将继续支持其他的 NFC 功能和 API,并且从标签和付款中读取数据等使用场景仍将继续按预期执行。

java.math.BigDecimal.stripTrailingZeros() 行为变更

如果输入值为零,BigDecimal.stripTrailingZeros() 不再将尾随零保留为特殊情况。

java.util.regex.Matcher 和模式行为变更

当输入开头存在零宽度匹配时,split() 的结果已更改为不再以空 String(“”)开头。这也会影响 String.split()。例如,"x".split("") 现在会返回 {"x"} 而它以前在旧版 Android 上会返回 {"", "x"}"aardvark".split("(?=a)" 现在返回 {"a", "ardv", "ark"},而不是 {"", "a", "ardv", "ark"}

无效参数的异常行为也得到了改进:

  • appendReplacement(StringBuffer, String) 现在会抛出 IllegalArgumentException,而不是 IndexOutOfBoundsException,如果 替换 String 以单独的反斜杠结尾,这种做法非法。通过 如果替换 String$ 结尾,则会抛出相同的异常。 之前,在这种情况下不会抛出异常。
  • 如果 replaceFirst(null) 抛出reset()Matcher NullPointerException。现在,在以下情况下也会抛出 NullPointerException 不匹配。以前,只有在存在匹配项时才会抛出此异常。
  • start(int group)end(int group)group(int group) 现在抛出更多 如果组索引超出范围,则常规 IndexOutOfBoundsException。 以前,这些方法会抛出 ArrayIndexOutOfBoundsException

GradientDrawable 的默认角度现在为 TOP_BOTTOM

在 Android 10 中,如果您在 XML 中定义了 GradientDrawable 但未提供角度测量值,则渐变方向默认为 TOP_BOTTOM。这是与之前版本的 Android 相比有所不同,之前版本中的默认值为 LEFT_RIGHT

作为一种权宜解决方法,如果您更新到最新版本的 AAPT2,当未指定角度测量值时,该工具会为旧版应用设置角度测量值 0。

使用默认 SUID 记录序列化对象的日志

从 Android 7.0(API 级别 24)开始,Android 平台修复了 默认为 serialVersionUID 以实现可序列化 对象。此次修复 未影响以 API 级别 23 或更低级别为目标平台的应用。

从 Android 10 开始,如果应用以 API 级别 23 或更低级别为目标平台 并且依赖于旧的、不正确的默认serialVersionUID系统日志 警告并建议代码修复。

具体而言,如果满足以下所有条件,系统就会记录警告:

  • 应用以 API 级别 23 或更低级别为目标平台。
  • 类是序列化的。
  • 序列化类使用默认 serialVersionUID,而不是 来明确设置 serialVersionUID
  • 默认的 serialVersionUIDserialVersionUID 不同 如果应用的目标 API 级别为 24 或更高级别,则会发生该错误。

系统会针对每个受影响的类记录一次此警告。 警告消息包含建议的解决方法, 将 serialVersionUID 设置为使用该值时计算的默认值 应用的目标 API 级别为 24 或更高级别。通过使用这种修复方法 该类中的对象在面向 API 级别的应用中序列化 23 或更低版本,则以 24 或更高级别为目标平台的应用将可以正确读取该对象。 反之亦然。

java.io.FileChannel.map() 变更

从 Android 10 开始,对于大小无法使用 truncate() 更改的非标准文件(例如 /dev/zero),不支持 FileChannel.map()。上一项 Android 版本 truncate(),但 Android 10 会抛出 IOException。如果您需要旧版行为 所以必须使用原生代码