Android 10 には、アプリに影響を与える可能性のある動作変更が含まれています。このページに記載されている変更は、アプリの targetSdkVersion
にかかわらず、Android 10 で実行されているアプリに適用されます。これらの変更に適切に対応するには、アプリをテストし、必要に応じて修正する必要があります。
アプリの targetSdkVersion が 29
以降の場合は、その他の変更にも対応する必要があります。詳しくは、29 をターゲットとするアプリの動作変更をご覧ください。
注: Android 10 では、このページに記載されている変更以外にも、以下のようなプライバシー保護に関する多くの変更や制限が導入されています。
- デバイスの位置情報へのバックグラウンドでのアクセス
- バックグラウンドからのアクティビティの起動
- 連絡先アフィニティ情報
- MAC アドレスのランダム化
- カメラのメタデータ
- 権限モデル
この変更はすべてのアプリに影響し、ユーザーのプライバシーを強化します。これらの変更をサポートする方法について詳しくは、プライバシーの変更点のページをご覧ください。
非 SDK インターフェースの制限
アプリの安定性と互換性を確保するため、Android 9(API レベル 28)から、アプリで使用できる非 SDK インターフェースが制限されています。Android 10 では、Android デベロッパーの協力や最新の内部テストに基づいて、制限対象となる非 SDK インターフェースのリストが更新されています。Google は、非 SDK インターフェースを制限する前に、その代わりとなる公開インターフェースを利用できるようにすることを目指しています。
Android 10(API レベル 29)をターゲットとしないアプリの場合、変更点によっては、すぐに影響が生じないこともあります。ただし、現時点で(アプリのターゲット API レベルに応じて)一部の非 SDK インターフェースを利用できていても、非 SDK のメソッドまたはフィールドをそのまま使用し続けると、将来的にアプリが機能しなくなるリスクが高くなります。
アプリが非 SDK インターフェースを使用しているかどうか不明な場合は、アプリをテストして確認できます。アプリが非 SDK インターフェースに依存している場合は、SDK の代替インターフェースへの移行を計画してください。ただし Google も、一部のアプリには非 SDK インターフェースを使用する正当なユースケースがあると承知しています。アプリの機能に使用している非 SDK インターフェースの代わりが見つからない場合は、新しい公開 API をリクエストしてください。
詳しくは、非 SDK インターフェースの制限に関する Android 10 での変更点と非 SDK インターフェースの制限をご覧ください。
ジェスチャー ナビゲーション
Android 10 以降、デバイス全体でジェスチャー ナビゲーションを有効にできます。ユーザーがジェスチャー ナビゲーションを有効にすると、アプリが API レベル 29 をターゲットにしているかどうかに関係なく、デバイス上のすべてのアプリが影響を受けます。たとえば、ユーザーが画面の端から内側にスワイプすると、アプリが画面の一部に対してそのジェスチャーを特別にオーバーライドしている場合を除き、システムはそのジェスチャーを「戻る」操作と解釈します。
アプリをジェスチャー ナビゲーションに対応させるには、アプリのコンテンツを画面全体に拡大し、競合するジェスチャーに適切に対処する必要があります。詳しくは、ジェスチャー ナビゲーションのドキュメントをご覧ください。
NDK
Android 10 では、NDK が次のように変更されています。
共有オブジェクトにテキストの再配置を含めることはできません
Android 6.0(API レベル 23)において、共有オブジェクト内でのテキストの再配置の使用が禁止されました。コードは現状のまま読み込まれ、変更してはなりません。この制限により、アプリの読み込み時間とセキュリティが改善されます。
Android 10 以降をターゲットとするアプリでは、この制限は、SELinux によって適用します。これらのアプリがテキストの再配置を含む共有オブジェクトの使用を続けると、動作できなくなる可能性が高くなります。
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/
内の関連する tombstone ファイルを調べます。実行専用メモリに関するクラッシュには、以下の中止メッセージが含まれています。
Cause: execute-only (no-read) memory access error; likely due to data in .text.
この問題を回避してメモリ インスペクションなどの操作を実行するために、mprotect()
を呼び出して実行専用セグメントを read+execute としてマークできますが、これは後で実行専用に戻すことを強くおすすめします。このアクセス権限の設定によって、アプリとユーザーの保護が強化されるためです。
セキュリティ
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 以前のバージョンでは、このオブジェクトは、セッションがセッション キャッシュに追加されてから呼び出されます)。 - 以前のバージョンの Android では
SSLEngine
インスタンスによりSSLHandshakeException
がスローされる状況において、Android 10 以降では代わりにSSLProtocolException
がスローされます。 - 0-RTT モードはサポートされていません。
必要に応じて、TLS 1.3 が無効になっている SSLContext
を取得するには、SSLContext.getInstance("TLSv1.2")
を呼び出します。また、対象オブジェクトに対して setEnabledProtocols()
を呼び出すことで、接続ごとにプロトコル バージョンの有効と無効を切り替えることもできます。
SHA-1 で署名された証明書は TLS では信頼されない
Android 10 では、SHA-1 ハッシュ アルゴリズムを使用している証明書は、TLS 接続では信頼されません。2016 年以降、このような証明書はルート CA によって発行されていないため、Chrome などの主要ブラウザでは信頼されなくなりました。
SHA-1 を使用している証明書を提示するサイトへの接続はすべて失敗します。
KeyChain の動作変更と機能強化
Google Chrome など一部のブラウザでは、TLS サーバーが TLS handshake の一環として証明書リクエスト メッセージを送信するときに、ユーザーが証明書を選択できます。Android 10 では、KeyChain.choosePrivateKeyAlias()
を呼び出してユーザーに証明書の選択を促すプロンプトを表示するときに、KeyChain
オブジェクトによって発行者と鍵の仕様パラメータが考慮されます。このプロンプトにはサーバー仕様に準拠しない選択肢は含まれません。
サーバーの仕様に一致する証明書がない場合や、デバイスに証明書がインストールされていない場合など、ユーザーが選択できる証明書がない場合は、証明書の選択を促すプロンプトは表示されません。
さらに、Android 10 以降では、鍵または CA 証明書を KeyChain
オブジェクトにインポートするために、デバイスが画面ロックされている必要はありません。
TLS と暗号化に関するその他の変更
Android 10 では、TLS と暗号化ライブラリに対する軽微な変更が反映されています。
- 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 拡張機能が考慮されます。 - Android Keystore の署名鍵など、不透明な署名鍵は TLS の RSA-PSS 署名で使用できます。
Wi-Fi Direct ブロードキャスト
Android 10 では、Wi-Fi Direct に関する以下のブロードキャストはスティッキーではありません。
スティッキー ブロードキャストであることを前提として登録時にこれらのブロードキャストを受信する仕様のアプリの場合は、代わりに初期化時に適切な get()
メソッドを使用して情報を取得するようにしてください。
Wi-Fi Aware 機能
Android 10 では、Wi-Fi Aware データパスを使用して 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 Q にアップグレードされても、アプリはその権限を保持します。ただし、アプリに権限がない場合は、デバイスのアップグレード後に権限を付与することはできません。
Go デバイス上のアプリがアクション ACTION_MANAGE_OVERLAY_PERMISSION
を含むインテントを送信すると、システムはリクエストを自動的に拒否し、デバイスの速度が低下するため権限が許可されないことを示す [設定] 画面が表示されます。Go デバイス上のアプリが Settings.canDrawOverlays()
を呼び出した場合、このメソッドは常に false を返します。繰り返しになりますが、デバイスが 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 では、アプリの利用に関して次のように動作が変更されました。
HTTPS 接続の変更
Android 10 を実行しているアプリが null
を setSSLSocketFactory()
に渡すと、IllegalArgumentException
が発生します。以前のバージョンでは、null
を setSSLSocketFactory()
に渡した場合、現在のデフォルト ファクトリを渡す場合と同じ効果がありました。
android.preference ライブラリのサポート終了
android.preference
ライブラリは Android 10 で非推奨になりました。代わりにデベロッパーは Android Jetpack の一部である AndroidX Preference ライブラリをご利用ください。移行と開発をサポートする参考情報として、更新された設定ガイドのほか、公開されているサンプルアプリとリファレンス ドキュメントもご確認ください。
ZIP ファイルのユーティリティ ライブラリの変更
Android 10 では、ZIP ファイルを処理する java.util.zip
パッケージのクラスに対して以下の変更が行われています。これらの変更により、java.util.zip
を使用する Android プラットフォームとその他のプラットフォーム間のライブラリの動作の一貫性が向上しています。
Inflater
以前のバージョンでは、Inflater
クラスの一部の関数が end()
の呼び出し後に呼び出されると、IllegalStateException
をスローしていました。Android 10 では、これらのメソッドは代わりに NullPointerException
をスローします。
ZipFile
Android 10 以降では、File
、int
、Charset
型の引数を取る ZipFile
のコンストラクタは、指定された ZIP ファイルにファイルが含まれていない場合、ZipException
をスローしません。
ZipOutputStream
Android 10 以降では、ZipOutputStream
の finish()
メソッドは、ファイルが含まれていない ZIP ファイルの出力ストリームの書き込みを試みても ZipException
をスローしません。
カメラに関する変更点
カメラを使用するアプリの多くは、デバイスが縦向きの構成である場合は、物理的にもデバイスが縦向きになっていると想定します(カメラの向きを参照)。以前はこの想定で問題ありませんでしたが、折りたたみ式など使用可能なフォーム ファクタの拡大に伴い変化しています。これらのデバイスで同様の想定が行われると、カメラのビューファインダーの表示が不適切に回転したり、拡大したりする原因になる可能性があります。
API レベル 24 以上をターゲットとするアプリでは、明示的に android:resizeableActivity
を設定して、マルチウィンドウ操作を処理するために必要な機能を提供する必要があります。
電池使用量のトラッキング
Android 10 以降、大規模な充電イベントの後にデバイスのプラグを抜くと、SystemHealthManager
は電池使用量の統計情報をリセットします。主要な充電イベントとはつまり、デバイスが完全に充電されること、またはほとんど電池残量がない状態からほぼ完全に充電された状態になることです。
Android 10 より前は、電池残量がほとんど変化していなくても、デバイスのプラグを抜くと電池使用量の統計情報がリセットされていました。
Android ビームを削除
Android 10 では、近距離無線通信(NFC)を介してデバイス間でデータ共有を開始するための古い機能、Android ビームが正式に終了します。また、関連する NFC API もいくつか終了します。必要に応じて、デバイス メーカー パートナーがオプションで Android ビームを使用し続けることはできますが、開発は行われていません。ただし、他の NFC 機能と API については Android で引き続きをサポートされます。また、タグからの読み取り、支払いなどのユースケースは想定どおりに動作し続けます。
java.math.BigDecimal.stripTrailingZeros() の動作の変更
BigDecimal.stripTrailingZeros()
は、入力値がゼロの場合に末尾のゼロを特別なケースとして保持しなくなりました。
java.util.regex.Matcher と Pattern の動作の変更
入力の開始時にゼロ幅の一致がある場合、split()
の結果が空の String
("")で始まらないように変更されました。これは String.split()
にも影響します。たとえば、以前は {"", "x"}
を返していた "x".split("")
は、{"x"}
を返すようになりました。"aardvark".split("(?=a)"
が {"", "a", "ardv", "ark"}
ではなく {"a", "ardv", "ark"}
を返すようになりました。
無効な引数の例外動作も改善されました。
- 置換
String
が単一のバックスラッシュで終わっている場合(これは無効です)、appendReplacement(StringBuffer, String)
がIndexOutOfBoundsException
ではなくIllegalArgumentException
をスローするようになりました。置換String
が$
で終わると、同じ例外がスローされるようになりました。以前は、このシナリオで例外はスローされませんでした。 replaceFirst(null)
がNullPointerException
をスローした場合に、Matcher
でreset()
を呼び出さなくなりました。一致がない場合もNullPointerException
がスローされるようになりました。以前は、一致があった場合にのみスローされていました。start(int group)
、end(int group)
、group(int group)
で、グループ インデックスが範囲外の場合、より一般的なIndexOutOfBoundsException
がスローされるようになりました。以前は、これらのメソッドはArrayIndexOutOfBoundsException
をスローしていました。
GradientDrawable のデフォルトの角度が TOP_BOTTOM になりました
Android 10 では、XML で GradientDrawable
を定義し、角度の測定値を指定しない場合、グラデーションの向きはデフォルトで TOP_BOTTOM
になります。これは、デフォルトが LEFT_RIGHT
だった以前のバージョンの Android とは異なります。
回避策として、AAPT2 の最新バージョンに更新すると、角度の測定が指定されていないレガシー アプリに対して、角度の測定が 0 に設定されます。
デフォルトの SUID を使用したシリアル化されたオブジェクトのロギング
Android 7.0(API レベル 24)以降、プラットフォームはシリアル化可能なオブジェクトのデフォルトの serialVersionUID
を修正しました。この修正は、API レベル 23 以前をターゲットとするアプリには影響しませんでした。
Android 10 以降では、アプリが API レベル 23 以前をターゲットとし、古い間違ったデフォルトの serialVersionUID
に依存している場合、システムは警告をログに記録し、コード修正を提案します。
具体的には、次のすべての条件を満たす場合に、システムは警告をログに記録します。
- アプリが API レベル 23 以前をターゲットにしている。
- クラスがシリアル化される。
- シリアル化されたクラスは、
serialVersionUID
を明示的に設定するのではなく、デフォルトのserialVersionUID
を使用します。 - デフォルトの
serialVersionUID
は、アプリが API レベル 24 以降をターゲットとしている場合のserialVersionUID
とは異なります。
この警告は、影響を受けるクラスごとに 1 回記録されます。警告メッセージには、推奨される修正方法が含まれています。これは、アプリが API レベル 24 以降をターゲットとしている場合に計算されるデフォルト値に serialVersionUID
を明示的に設定することです。この修正を使用すると、そのクラスのオブジェクトが API レベル 23 以前をターゲットとするアプリでシリアル化された場合、24 以降をターゲットとするアプリでオブジェクトが正しく読み取られるようになります。また、その逆も同様です。
java.io.FileChannel.map() の変更点
Android 10 以降、FileChannel.map()
は /dev/zero
のような非標準ファイルではサポートされません。非標準ファイルのサイズを truncate()
を使って変更することはできません。Android の以前のバージョンでは、truncate()
から返される errno をそのままにしていましたが、Android 10 は IOException をスローします。以前の動作が必要な場合は、ネイティブ コードを使用してください。