動作の変更点: すべてのアプリ

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)では、共有オブジェクト内でのテキスト再配置の使用が禁止されています。コードはそのままの状態で読み込む必要があり、変更しないでください。この制限により、アプリの読み込み時間とセキュリティが改善されます。

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/ にある関連する tombstone ファイルを調べます。実行専用関連のクラッシュには、次の中止メッセージが含まれます。

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 以前のバージョンでは、これらのオブジェクトはセッションがセッション キャッシュに追加された後に呼び出されます)。
  • 以前のバージョンの 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 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 の要件により、最近更新されていないアプリを実行したときにのみ、この警告が表示されます。他のストアを通じて配信されているアプリについても、2019 年中に同様の対象 API 要件が適用されます。これらの要件について詳しくは、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 を実行しているアプリが nullsetSSLSocketFactory() に渡すと、IllegalArgumentException が発生します。以前のバージョンでは、nullsetSSLSocketFactory() に渡すと、現在のデフォルト ファクトリを渡す場合と同じ効果がありました。

android.preference ライブラリのサポート終了

android.preference ライブラリは、Android 10 で非推奨になりました。代わりに Android Jetpack の一部である AndroidX Preference ライブラリを使用してください。移行と開発に役立つその他のリソースについては、更新された設定ガイド公開されているサンプルアプリリファレンス ドキュメントをご覧ください。

ZIP ファイルのユーティリティ ライブラリの変更

Android 10 では、ZIP ファイルを処理する java.util.zip パッケージのクラスに以下の変更が行われています。これらの変更により、Android と、java.util.zip を使用する他のプラットフォームとの間で、ライブラリの動作の一貫性が向上しています。

Inflater

以前のバージョンでは、Inflater クラスの一部のメソッドは、end() の呼び出し後に呼び出された場合に IllegalStateException をスローしていました。Android 10 では、これらのメソッドは代わりに NullPointerException をスローします。

ZipFile

Android 10 以降では、指定された ZIP ファイルにファイルが含まれていない場合、FileintCharset 型の引数を取る ZipFile のコンストラクタZipException をスローしません。

ZipOutputStream

Android 10 以降では、ZipOutputStreamfinish() メソッドは、ファイルが含まれていない ZIP ファイルの出力ストリームを書き込もうとしても、ZipException をスローしません。

カメラに関する変更点

カメラを使用するアプリの多くは、デバイスが縦向き構成の場合、カメラの向きで説明されているように、物理デバイスも縦向きになっていることを前提としています。これまではこれは安全な前提でしたが、折りたたみ式デバイスなど、利用可能なフォーム ファクタが拡大するにつれて変わりました。このようなデバイスを想定すると、カメラのビューファインダーの表示が不適切に回転またはスケーリング(あるいはその両方)される可能性があります。

API レベル 24 以降をターゲットとするアプリでは、android:resizeableActivity を明示的に設定し、マルチウィンドウ操作の処理に必要な機能を提供する必要があります。

電池使用量のトラッキング

Android 10 以降では、主な充電イベントの後にデバイスが電源から外されるたびに、SystemHealthManager によってバッテリー使用量の統計情報がリセットされます。大まかに言うと、主要な充電イベントとは、デバイスが完全に充電された、またはほぼ充電された状態からほぼ充電された状態のいずれかを指します。

Android 10 より前では、電池残量がわずかに変化していなくても、デバイスが電源から外されるたびに電池使用量の統計情報がリセットされます。

Android ビームを削除

Android 10 では、近距離無線通信(NFC)を使用してデバイス間のデータ共有を開始するための古い機能である Android ビームのサポートが正式に終了します。また、関連する NFC API のいくつかのサポートも終了します。Android ビームは、使用を希望するデバイス メーカー パートナーには引き続き任意で利用可能ですが、開発は終了しています。Android は引き続き他の NFC 機能や API をサポートしており、タグからの読み取りや支払いなどのユースケースは引き続き想定どおりに機能します。

java.math.BigDecimal.stripTrailingZeros() の動作の変更

BigDecimal.stripTrailingZeros() は、入力値がゼロの場合に、末尾のゼロを特殊なケースとして保持しなくなりました。

java.util.regex.Matcher と Pattern の動作の変更

split() の結果が、入力の先頭がゼロ幅の一致があった場合に、空の String("")で始まらないように変更されました。これは String.split() にも影響します。たとえば、以前のバージョンの Android では {"", "x"} を返していましたが、"x".split(""){"x"} を返すようになりました。"aardvark".split("(?=a)"{"", "a", "ardv", "ark"} ではなく {"a", "ardv", "ark"} を返すようになりました。

無効な引数に対する例外の動作も改善されました。

  • 置換 String が単独のバックスラッシュで終わると、appendReplacement(StringBuffer, String)IndexOutOfBoundsException ではなく IllegalArgumentException をスローするようになりました。これは誤りです。置換先の String$ で終わる場合、同じ例外がスローされるようになりました。以前は、このシナリオでは例外はスローされませんでした。
  • replaceFirst(null)NullPointerException をスローした場合に、Matcherreset() を呼び出さなくなりました。一致するものがない場合にも 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 を使用します。
  • デフォルトの 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 がスローされます。以前の動作が必要な場合は、ネイティブ コードを使用する必要があります。