行為變更:所有應用程式

Android 10 包含可能對應用程式造成影響的行為變更。無論應用程式的 targetSdkVersion 為何,本頁所列變更都會套用到在 Android 10 上執行應用程式時。建議您測試應用程式,並視需要修改,以便妥善支援這些變更。

如果應用程式的 targetSdkVersion 為 29 以上版本,您也必須支援其他變更。請務必詳閱指定 29 為目標版本應用程式的行為變更

注意: 除了本頁列出的變更外,Android 10 還推出了多項隱私權相關變更和限制,包括:

  • 裝置位置資訊的背景存取權
  • 背景活動開始
  • 聯絡人相依性資訊
  • MAC 位址隨機化
  • 相機中繼資料
  • 權限模型

這些異動會影響所有應用程式,並提升使用者隱私。如要進一步瞭解如何支援這些變更,請參閱「隱私權變更」頁面。

非 SDK 介面限制

為了確保應用程式穩定性和相容性,平台已開始限制應用程式在 Android 9 (API 級別 28) 中使用的非 SDK 介面。基於與 Android 開發人員合作及最新的內部測試,Android 10 包含更新後的受限制非 SDK 介面清單。我們的目標是在限制非 SDK 介面之前,確保可以使用公用替代方案。

如果您不以 Android 10 (API 級別 29) 為目標,則此處所述的某些變更可能不會立即對您造成影響。不過,雖然您目前可使用某些非 SDK 介面 (視應用程式的目標 API 級別而定),但使用任何非 SDK 方法或欄位時,一律可能會導致應用程式停止運作。

如果不確定應用程式是否使用非 SDK 介面,可對應用程式進行測試以便確認。如果您的應用程式仰賴非 SDK 介面,則建議您開始規劃遷移至 SDK 替代方案。我們瞭解有些應用程式可使用非 SDK 介面運作。如果您除了為應用程式中的某個功能使用非 SDK 介面外,已別無他法,則應要求新的公用 API

詳情請參閱 Android 10 的非 SDK 介面限制更新內容,以及非 SDK 介面的相關限制

手勢操作

從 Android 10 開始,使用者可以跨裝置啟用手勢操作功能。如果使用者啟用手勢操作,則無論應用程式是否指定 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 開始,系統二進位檔和程式庫的可執行區段會對應至記憶體僅供執行 (不可讀取),做為強化程式碼重複使用技術的強化技術。如果應用程式對標示為「僅供執行」的記憶體區段執行讀取作業 (無論是因錯誤、安全漏洞或意圖記憶體檢查),系統都會傳送 SIGSEGV 信號至應用程式。

您可以在 /data/tombstones/ 中查看相關的空值標記檔案,判斷這個行為是否導致當機。與僅執行相關的當機事件包含下列取消訊息:

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

如要解決這個問題 (例如執行記憶體檢查等作業),您可以呼叫 mprotect(),將「僅限執行」區段標示為「讀取 + 執行」。不過,強烈建議您先將這項設定重新設為僅執行 (僅限執行),因為這項存取權限設定可為應用程式和使用者提供更完善的保護。

安全性

Android 10 提供下列安全性變更。

預設啟用 TLS 1.3

在 Android 10 以上版本中,所有傳輸層安全標準 (TLS) 連線均預設啟用 TLS 1.3。以下是有關實作 TLS 1.3 的幾項重要細節:

  • TLS 1.3 加密套件不開放自訂。啟用 TLS 1.3 時,一律會啟用支援的 TLS 1.3 加密套件。若嘗試呼叫 setEnabledCipherSuites() 來停用這些功能,系統會予以忽略。
  • 協商 TLS 1.3 時,系統會「先」呼叫 HandshakeCompletedListener 物件,再將工作階段加入工作階段快取。(在 TLS 1.2 和其他舊版本中,這些物件是在工作階段新增至工作階段快取「之後」才會呼叫)。
  • 在某些情況下,當 SSLEngine 執行個體在舊版 Android 上擲回 SSLHandshakeException 時,這些例項會在 Android 10 以上版本擲回 SSLProtocolException
  • 不支援 0-RTT 模式。

如有需要,您可以呼叫 SSLContext.getInstance("TLSv1.2"),取得已停用 TLS 1.3 的 SSLContext。您也可以對適當物件呼叫 setEnabledProtocols(),根據個別連線啟用或停用通訊協定版本。

使用 SHA-1 簽署的憑證不受 TLS 信任

在 Android 10 中,TLS 連線不會信任使用 SHA-1 雜湊演算法的憑證。根 CA 自 2016 年起就未曾核發這類憑證,Chrome 或其他主要瀏覽器也不再信任這類憑證。

如果連線目標為使用 SHA-1 憑證的網站,則任何連線嘗試都會失敗。

KeyChain 行為變更和強化措施

Google Chrome 等部分瀏覽器會在 TLS 握手期間,趁著 TLS 伺服器傳送憑證要求訊息時,允許使用者選擇憑證。在 Android 10,KeyChain 物件會在呼叫 KeyChain.choosePrivateKeyAlias() 來向使用者顯示憑證選擇提示時,遵循頒發單位和金鑰規格參數。具體來說,此提示含有的選項皆符合伺服器規格。

如果沒有可供使用者選取的憑證,例如在憑證不符合伺服器規格,或裝置未安裝任何憑證的情況下,則系統根本不會顯示憑證選取提示。

此外,Android 10 以上版本不必設定裝置螢幕鎖定,即可將金鑰或 CA 憑證匯入 KeyChain 物件。

其他 TLS 和密碼學變更

TLS 和密碼學程式庫有幾項小幅變更,會在 Android 10 生效:

  • AES/GCM/NoPadding 和 ChaCha20/Poly1305/NoPadding 加密演算法會從 getOutputSize() 傳回更準確的緩衝區大小。
  • 如果嘗試連線時使用的最高通訊協定版本為 TLS 1.2 以上版本,系統會省略 TLS_FALLBACK_SCSV 加密套件。TLS 伺服器實作程序已經過提升,因此不建議嘗試採用 TLS 外部備用機制,而應採用 TLS 版本協商。
  • ChaCha20-Poly1305 是 ChaCha20/Poly1305/NoPadding 的別名。
  • 以點結尾的主機名稱並非有效的 SNI 主機名稱。
  • 選擇憑證回應的簽署金鑰時,系統會依循 CertificateRequest 中的 supported_signature_algorithms 擴充功能。
  • 在 TLS 中,Android KeyStore 金鑰等不透明的簽署金鑰可以與 RSA-PSS 簽章搭配使用。

Wi-Fi Direct 廣播

在 Android 10 中,下列與 Wi-Fi Direct 相關的廣播訊息並非固定式:

如果您的應用程式因為固定式持續而需要在註冊時接收這些廣播訊息,請在初始化時改用適當的 get() 方法取得資訊。

Wi-Fi 感知功能

Android 10 開始支援使用 Wi-Fi 感知資料路徑建立 TCP/UDP 通訊端。如要建立連線至 ServerSocket 的 TCP/UDP 通訊端,用戶端裝置必須知道伺服器的 IPv6 位址和通訊埠。先前需要使用 BT 或 Wi-Fi Aware 第 2 層通訊功能,才能透過頻外通訊,或是利用 mDNS 等其他通訊協定在頻內發現。在 Android 10 中,可在設定網路設定時傳遞相關資訊。

伺服器可以執行下列其中一項操作:

  • 初始化 ServerSocket,並設定或取得要使用的通訊埠。
  • 在 Wi-Fi Aware 網路要求中指定通訊埠資訊。

以下程式碼範例說明如何在網路要求中指定通訊埠資訊:

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 Aware 網路要求,以取得 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 裝置上的應用程式傳送含有 ACTION_MANAGE_OVERLAY_PERMISSION 動作的意圖,系統會自動拒絕要求,並將使用者導向「設定」畫面,說明該權限因為裝置速度緩慢,因此無法授予權限。如果 Go 裝置上的應用程式呼叫 Settings.canDrawOverlays(),此方法一律會傳回 false。再次強調,這些限制不適用於在裝置升級至 Android 10 前獲得 SYSTEM_ALERT_WINDOW 權限的應用程式。

應用程式指定舊版 Android 裝置的警告

在搭載 Android 10 以上版本的裝置首次執行任何指定 Android 5.1 (API 級別 22) 以下版本的應用程式時,系統會向使用者顯示警告。如果應用程式要求使用者授予權限,也可以在應用程式首次執行前,讓使用者可以調整應用程式的權限。

根據 Google Play 的目標 API 規定,只有當使用者執行的應用程式最近均未更新時,使用者才會看到這些警告。如果是透過其他商店發行的應用程式,類似的目標 API 要求會在 2019 年生效。如要進一步瞭解這些規定,請參閱「在 2019 年擴大目標 API 級別規定」。

已移除 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 推出了下列與應用程式使用情形相關的行為變更:

  • 使用統計資料應用程式使用狀況改善 - 此外,Android 10 也能正確追蹤免安裝應用程式的使用情形。

  • 個別應用程式灰階 -

  • 個別應用程式乾擾狀態 -

  • 暫停並播放 -

HTTPS 連線變更

如果執行 Android 10 的應用程式將 null 傳遞至 setSSLSocketFactory(),就會發生 IllegalArgumentException。在先前版本中,將 null 傳遞至 setSSLSocketFactory() 的效果與傳入目前預設工廠的效果相同。

android.preference 程式庫已淘汰

android.preference 程式庫已於 Android 10 淘汰。開發人員應改用 Android Jetpack 中的 AndroidX 偏好設定資料庫。如需其他有助於遷移和開發的資源,請參閱新版設定指南公開範例應用程式參考說明文件

ZIP 檔案公用程式庫異動

Android 10 針對處理 ZIP 檔案的 java.util.zip 套件中的類別推出了下列變更。這些變更可以讓 Android 和其他使用 java.util.zip 的平台更一致的程式庫行為。

發射機

在先前版本中,如果在呼叫 end() 後叫用 Inflater 類別中的某些方法,就會擲回 IllegalStateException。在 Android 10 中,這些方法會改為擲回 NullPointerException

ZIP 檔案

在 Android 10 以上版本中,如果提供的 ZIP 檔案不包含任何檔案,ZipFile 的建構函式會使用 FileintCharset 類型的引數,不會擲回 ZipException

ZipOutputStream

在 Android 10 及以上版本中,如果對不包含任何檔案的 ZIP 檔案寫入輸出串流,ZipOutputStream 中的 finish() 方法不會擲回 ZipException

相機變更

許多使用相機的應用程式會假設裝置為直向設定,則實體裝置也處於直向,如「相機方向」所述。這是過去的安全假設,但隨著摺疊式裝置等可用的板型規格增加,這項假設又有所改變。在這些裝置上,這樣的假設可能會導致相機觀景窗畫面旋轉或縮放 (或兩者皆不正確)。

目標 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"}

我們也改善了無效引數的例外狀況行為:

  • 如果替換的 String 以孤單反斜線結尾,appendReplacement(StringBuffer, String) 現在會擲回 IllegalArgumentException,而不是 IndexOutOfBoundsException。如果替換的 String$ 結尾,系統會擲回相同的例外狀況。先前在這個情況下不會擲回例外狀況。
  • replaceFirst(null)如果擲回 NullPointerException,則不再reset()Matcher 上呼叫 。如果沒有相符項目,現在也會擲回 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) 開始,平台已修正可序列化物件的預設 serialVersionUID。這項修正不會影響目標 API 級別為 23 以下的應用程式。

從 Android 10 開始,如果應用程式指定的 API 級別為 23 以下,且仰賴舊的錯誤預設 serialVersionUID,系統會記錄警告並提供程式碼修正建議。

具體來說,如果符合下列所有條件,系統就會記錄警告:

  • 應用程式指定 API 級別 23 以下為目標。
  • 類別已序列化。
  • 序列化類別會使用預設的 serialVersionUID,而非明確設定 serialVersionUID
  • 如果應用程式指定的 API 級別為 24 以上,則預設的 serialVersionUIDserialVersionUID 不同。

系統會針對每個受影響的類別記錄一次這項警告。警告訊息內含建議的修正方式,意指將 serialVersionUID 明確設為若應用程式指定 API 級別 24 以上時將會計算的預設值。透過該修正,您可以確保如果指定該類別的物件在目標 API 級別 23 以下的應用程式進行序列化,則目標為 24 以上級別的應用程式也能正確讀取該物件,反之亦然。

java.io.FileChannel.map() 變更

自 Android 10 起,非標準檔案 (例如 /dev/zero) 不支援 FileChannel.map(),因此無法使用 truncate() 變更其大小。舊版 Android 會隱藏 truncate() 傳回的 errno,但 Android 10 會擲回 IOException。如果您需要舊行為,必須使用原生程式碼。