The Android Developer Challenge is back! Submit your idea before December 2.

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

Android 10 には、アプリに影響を与える可能性のある動作変更が含まれています。このドキュメントに記載されている変更は、アプリの targetSdkVersion にかかわらず、Android 10 で実行されているアプリに適用されます。これらの変更に適切に対応するには、アプリをテストし、必要に応じて修正する必要があります。

アプリの targetSdkVersion が 29 以降の場合は、その他の変更にも対応する必要があります。詳しくは、29 をターゲットとするアプリの動作変更をご覧ください。

注: このドキュメントに記載されている動作変更のほかに、Android 10 のプライバシー機能を必ず確認して対応するようにしてください。

非 SDK インターフェースの制限

アプリの安定性と互換性を確保するため、Android 9(API レベル 28)から、アプリで使用できる非 SDK インターフェースが制限されています。Android 10 では、Android デベロッパーの協力や最新の内部テストに基づいて、制限対象となる非 SDK インターフェースのリストが更新されています。Google は、非 SDK インターフェースを制限する前に、その代わりとなる公開インターフェースを利用できるようにすることを目指しています。

Android 10(API レベル 29)をターゲットとしないアプリの場合、変更点によっては、すぐに影響が生じないこともあります。ただし、現時点ではグレーリストに記載されている非 SDK インターフェース(アプリのターゲット API レベルによる)を利用できていても、そのまま非 SDK の手法やフィールドを使用し続けていると、将来的には高い確率でアプリが機能しなくなるおそれがあります。

アプリが非 SDK インターフェースを使用しているかどうか不明な場合は、アプリをテストして確認することができます。アプリが非 SDK インターフェースを使用している場合は、SDK インターフェースへの移行を計画するようにしてください。ただし Google も、一部のアプリには非 SDK インターフェースを使用する正当なユースケースがあると承知しています。現在のアプリの機能に使用している非 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 モードはサポートされていません。

必要に応じて、SSLContext.getInstance("TLSv1.2") を呼び出して、TLS 1.3 が無効になっている SSLContext を取得できます。また、対象オブジェクトに対して setEnabledProtocols() を呼び出すことで、接続ごとにプロトコル バージョンの有効と無効を切り替えることができます。

SHA-1 で署名された証明書は TLS では信頼されない

Android 10 では、SHA-1 ハッシュ アルゴリズムが使用されている証明書は、TLS 接続では信用されません。2016 年以降、このような証明書はルート CA によって発行されていないため、Chrome などの主要ブラウザでは信頼されなくなりました。

サイトへの接続を試みたときに SHA-1 が使用されている証明書を提示すると、その接続はすべて失敗します。

KeyChain の動作変更と機能強化

Google Chrome など一部のブラウザでは、TLS サーバーが TLS ハンドシェイクの一部として証明書リクエスト メッセージを送信するときに、ユーザーが証明書を選択できます。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 が返されます。繰り返しになりますが、デバイスが 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 では、アプリの利用に関して次のように動作が変更されました。

  • UsageStats アプリの使用統計情報の改善 - Android 10 では、アプリが分割画面モードやピクチャー イン ピクチャー モードで使用された場合でも、UsageStats によりアプリの使用状況を正確にトラッキングできます。また、Android 10 では、Instant App の使用状況も正しくトラッキングできます。

  • アプリ単位のグレースケール表示 - Android 10 では、アプリをグレースケール表示モードに設定できます。

  • アプリ単位の distraction state - Android 10 ではアプリごとに「distraction state」に設定できます。この状態のアプリの通知は抑制され、おすすめアプリとしてアプリが表示されることはありません。

  • 停止と再生 - Android 10 では、停止中のアプリは音声を再生できません。

HTTPS 接続の変更

Android 10 で実行中のアプリから setSSLSocketFactory()null を渡すと、IllegalArgumentException が発生します。以前のバージョンでは、setSSLSocketFactory()null を渡した場合、現在の SSLSocketFactory のデフォルト値を渡すのと同じ効果がありました。

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

Android 10 では、android.preference ライブラリのサポートが終了しています。デベロッパーは、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 以降では、FileintCharset の各型の引数をとる ZipFile のコンストラクタに、ファイルが含まれていない ZIP ファイルを渡しても、ZipException はスローされません。

ZipOutputStream

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

カメラに関する変更点

カメラを使用するアプリの多くは、デバイスが縦向きの構成である場合は、物理的にもデバイスが縦向きになっていると想定します(カメラの向きを参照)。以前はこの想定で問題ありませんでしたが、折りたたみ式など使用可能なフォーム ファクタの拡大に伴い変化しています。これらのデバイスで同様の想定が行われると、カメラのビューファインダーの表示が不適切に回転したり、拡大したりする原因になる可能性があります。

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

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

Android 10 以降では、主要な充電イベントの後にデバイスのプラグを抜くと、SystemHealthManager によって電池使用量の統計情報がリセットされます。主要な充電イベントとはつまり、デバイスが完全に充電されること、またはほとんど電池残量がない状態からほぼ完全に充電された状態になることです。

Android 10 より前は、電池残量がほとんど変化していなくても、デバイスのプラグを抜くと電池使用量の統計情報がリセットされていました。

Android ビームを削除

Android 10 では、近距離無線通信(NFC)を介してデバイス間でデータ共有を開始するための古い機能、Android ビームが正式に終了します。また、関連する NFC API もいくつか終了します。必要に応じて、デバイス メーカー パートナーがオプションで Android ビームを使用し続けることはできますが、開発は行われていません。ただし、他の NFC 機能と API については Android で引き続きをサポートされます。また、タグからの読み取り、支払いなどのユースケースは想定どおりに動作し続けます。