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

Android 9(API レベル 28)以降、アプリで使用できる非 SDK インターフェースが制限されています。アプリが非 SDK インターフェースを参照したり、リフレクションや JNI を使用してハンドルの取得を試みたりするたびに、この制限が適用されます。この制限が導入されたことで、ユーザーやデベロッパーのエクスペリエンスが改善されるほか、ユーザーはクラッシュのリスクを、デベロッパーは緊急リリースを配布するリスクを低減できます。この決定について詳しくは、非 SDK インターフェースの使用を減らすことによる安定性の向上に関するブログ記事をご覧ください。

SDK インターフェースと非 SDK インターフェースの違い

公開 SDK インターフェースとは一般に、Android フレームワークのパッケージ インデックスに記述されているインターフェースのことです。非 SDK インターフェースの処理は、その API に抽象化されている詳細を実装するものです。そのため、非 SDK インターフェースは予告なく変更されることがあります。

クラッシュや予期しない動作を回避するには、SDK のクラスについて、正式に文書化されている部分のみを使用する必要があります。つまり、リフレクションなどのメカニズムを使用してクラスを操作する場合は、SDK に記述されていないメソッドやフィールドにはアクセスしないでください。

非 SDK API のリスト

Android の各リリースで、追加の非 SDK インターフェースには制限があります。この制限によって、アプリのリリース ワークフローに影響が及ぶ可能性があります。そのため、Google は、デベロッパー向けに、非 SDK インターフェースの使用を検出するツールを用意して Google にフィードバックを提供できるようにし、計画を立てて新しいポリシーに適応するための時間を提供したいと考えています。

非 SDK インターフェースの制限が開発ワークフローに及ぼす影響を最小限に抑えるため、対象 API レベルに応じて非 SDK インターフェースの使用をどの程度制限するかを定義するリストを設けて、非 SDK インターフェースを分類しています。次の表で、その各リストについて説明します。

リスト コードタグ 説明
ブロックリスト
  • blocked
  • 非推奨: blacklist
アプリの対象 API レベルに関係なく使用できない非 SDK インターフェース。アプリがこのインターフェースのいずれかにアクセスしようとすると、システムによってエラーがスローされます。
条件付きブロック
  • max-target-x
  • 非推奨: greylist-max-x

Android 9(API レベル 28)以降、アプリの対象 API レベルごとに制限される非 SDK インターフェースがあります。

このリストには、リスト内の非 SDK インターフェースにアクセスできるアプリの対象 API レベルのうち、最大レベル(max-target-x)のラベルが付きます。たとえば、Android Pie でブロックされず、Android 10 でブロックされるようになった非 SDK インターフェースは、max-target-pgreylist-max-p)リストに含まれます。ここで「p」は Pie、つまり Android 9(API レベル 28)を表します。

アプリが対象 API レベルで制限されているインターフェースにアクセスしようとすると、システムはその API がブロックリストに含まれるかのように動作します

サポート対象外
  • unsupported
  • 非推奨: greylist
制限がなく、アプリが使用できる非 SDK インターフェース。ただし、これらのインターフェースはサポートされていないので、予告なく変更される場合があります。これらのインターフェースは今後の Android バージョンで、max-target-x リストの条件付きブロックの対象となると想定しておいてください。
SDK
  • public-apisdk の両方
  • 非推奨: public-apiwhitelist の両方
自由に使用できるインターフェースであり、正式に文書化されている Android フレームワークのパッケージ インデックスの一部として現在サポートされています。
テスト API
  • test-api
互換性テストスイート(CTS)によるテストを容易にする API など、内部システムテストに使用されるインターフェース。テスト API は SDK の一部ではありませんAndroid 11(API レベル 30)以降はテスト API がブロックリストに登録されているため、対象 API レベルにかかわらずアプリで使用できません。すべてのテスト API はサポート対象外で、プラットフォームの API レベルにかかわらず予告なく変更される場合があります。

アプリの対象 API レベルによっては部分的に使用できる非 SDK インターフェースもありますが、非 SDK のメソッドやフィールドの使用を続けていると、今後アプリが機能しなくなる可能性が高くなります。アプリが非 SDK インターフェースに依存している場合は、SDK インターフェースまたは別の手段への移行を計画してください。アプリの機能に使用している非 SDK インターフェースの代わりが見つからない場合は、新しい公開 API をリクエストしてください。

インターフェースが属しているリストの特定

非 SDK インターフェースのリストはプラットフォームの一部として作成されています。各 Android リリースについて詳しくは、下記のセクションをご覧ください。

Android 14(ベータ版)

Android 14(API レベル 34)の場合、非 SDK のすべてのインターフェースと対応するリストを記述した次のファイルをダウンロードできます。

ファイル: hiddenapi-flags.csv

SHA-256 チェックサム: 7e00db074cbe51c51ff4b411f7b48e98692951395c5c17d069c822cc1d0eae0f

Android 14 での非 SDK API リストの変更点について詳しくは、非 SDK インターフェースの制限に関する Android 14 での変更点をご覧ください。

Android 13

Android 13(API レベル 33)の場合、非 SDK のすべてのインターフェースと対応するリストを記述した次のファイルをダウンロードできます。

ファイル: hiddenapi-flags.csv

SHA-256 チェックサム: 233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3

Android 13 での非 SDK API リストの変更点(Android 13 で条件付きでブロックされる API の代替として推奨される公開 API など)について詳しくは、非 SDK インターフェースの制限に関する Android 13 での変更点をご覧ください。

Android 12

Android 12(API レベル 31)の場合、非 SDK のすべてのインターフェースと対応するリストを記述した次のファイルをダウンロードできます。

ファイル: hiddenapi-flags.csv

SHA-256 チェックサム: 40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761

Android 12 での非 SDK API リストの変更点(Android 12 で条件付きでブロックされる API の代替として推奨される公開 API など)について詳しくは、Android 12 でのリスト内容の変更をご覧ください。

Android 11

Android 11(API レベル 30)の場合、非 SDK のすべてのインターフェースと対応するリストを記述する次のファイルをダウンロードできます。

ファイル: hiddenapi-flags.csv

SHA-256 チェックサム: a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56

Android 11 での非 SDK API リストの変更点(Android 11 で条件付きでブロックされる API の代替として推奨される公開 API など)について詳しくは、Android 11 でのリスト内容の変更をご覧ください。

Android 10

Android 10(API レベル 29)の場合、非 SDK のすべてのインターフェースと対応するリストを記述した次のファイルをダウンロードできます。

ファイル: hiddenapi-flags.csv

SHA-256 チェックサム: f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb

Android 10 での非 SDK API リストの変更点(Android 10 で条件付きでブロックされる API の代替として推奨される公開 API など)について詳しくは、Android 10 でのリスト内容の変更をご覧ください。

Android 9

Android 9(API レベル 28)の場合、制限されていない(グレーリストに登録されている)非 SDK API のリストは、次のテキスト ファイルに記載されています(hiddenapi-light-greylist.txt)。

ブロックリスト(blacklist)と条件付きでブロックされている API のリスト(ダークグレー リスト)は、ビルド時に抽出されます。

AOSP からリストを生成する

AOSP を使用する場合は、非 SDK のすべてのインターフェースと対応するリストを含む hiddenapi-flags.csv ファイルを生成できます。生成するには、AOSP ソースをダウンロードして、次のコマンドを実行します。

m out/soong/hiddenapi/hiddenapi-flags.csv

ファイルは次の場所に生成されます。

out/soong/hiddenapi/hiddenapi-flags.csv

制限付きの非 SDK インターフェースにアクセスした場合に想定される動作

次の表に、ブロックリストに登録されている非 SDK インターフェースにアプリがアクセスしようとした場合に想定される動作を示します。

アクセス方法 結果
Dalvik 命令によるフィールドの参照 NoSuchFieldError がスローされる
Dalvik 命令によるメソッドの参照 NoSuchMethodError がスローされる
Class.getDeclaredField() または Class.getField() を使用したリフレクション NoSuchFieldException がスローされる
Class.getDeclaredMethod()Class.getMethod() を使用したリフレクション NoSuchMethodException がスローされる
Class.getDeclaredFields()Class.getFields() を使用したリフレクション 非 SDK メンバーが結果に含まれない
Class.getDeclaredMethods()Class.getMethods() を使用したリフレクション 非 SDK メンバーが結果に含まれない
env->GetFieldID() を使用する JNI NULL が返され、NoSuchFieldError がスローされる
env->GetMethodID() を使用する JNI NULL が返され、NoSuchMethodError がスローされる

非 SDK インターフェースのテスト

アプリ内の非 SDK インターフェースのテスト方法をいくつか紹介します。

デバッグ可能なアプリを使用したテスト

デバッグ可能なアプリを作成して、Android 9(API レベル 28)以上が稼働するデバイスまたはエミュレータで実行することにより、非 SDK インターフェースをテストできます。使用するデバイスまたはエミュレータを、アプリの対象 API レベルと一致させるようにします。

テストの実行中にアプリが特定の非 SDK インターフェースにアクセスすると、システムによってログメッセージが出力されます。このログメッセージで以下の詳細情報を確認できます。

  • 宣言しているクラス、名前、型(Android ランタイムで使用されている形式)。
  • アクセス手段(リンク、リフレクション、JNI のいずれか)。
  • 非 SDK インターフェースが属しているリスト。

adb logcat を使用すると、これらのログ メッセージにアクセスできます(実行中のアプリの PID の下に表示されます)。ログ内のエントリの例を次に示します。

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)

StrictMode API を使用したテスト

StrictMode API を使用して非 SDK インターフェースをテストすることもできます。この API を有効にするには、detectNonSdkApiUsage メソッドを使用します。StrictMode API を有効にすると、非 SDK インターフェースを使用するたびに penaltyListener を使用してコールバックを受信し、カスタム処理を実装することができます。コールバックで提供される ViolationThrowable からの派生オブジェクトで、埋め込まれているスタック トレースから使用状況がわかります。

veridex ツールを使用したテスト

APK で veridex 静的解析ツールを実行することもできます。veridex ツールは、APK のコードベース(サードパーティ ライブラリを含む)全体をスキャンして、検出した非 SDK インターフェースの使用状況を報告します。

veridex ツールには以下の制限事項があります。

  • JNI を介した呼び出しは検出できません。
  • リフレクションを介した呼び出しのサブセットのみを検出できます。
  • 非アクティブなコードパスの解析は API レベルのチェックに制限されています。
  • SSE4.2 命令と POPCNT 命令をサポートするマシンでのみ実行できます。

Windows

ネイティブ Windows バイナリは提供されていませんが、Linux 用 Windows サブシステム(WSL)を使用して Linux バイナリを実行することで、Windows で veridex ツールを実行できます。WSL をインストールして、Linux ディストリビューションとして Ubuntu を選択してから、このセクションの手順を行ってください。

Ubuntu をインストール後、Ubuntu ターミナルを起動し、次の手順を行います。

  1. ビルド済みの Android ランタイム リポジトリから veridex ツールをダウンロードします。
  2. appcompat.tar.gz ファイルの内容を抽出します。
  3. 抽出したフォルダ内で veridex-linux.zip ファイルを見つけて解凍します。
  4. 解凍したフォルダに移動して、次のコマンドを実行します。your-app.apk には、テストする APK を指定します。

    ./appcompat.sh --dex-file=your-app.apk
    

macOS

macOS で veridex ツールを実行する方法は次のとおりです。

  1. ビルド済みの Android ランタイム リポジトリから veridex ツールをダウンロードします。
  2. appcompat.tar.gz ファイルの内容を抽出します。
  3. 抽出したフォルダ内で veridex-mac.zip ファイルを見つけて解凍します。
  4. 解凍したフォルダに移動して、次のコマンドを実行します。/path-from-root/your-app.apk には、テストする APK について、システムのルート ディレクトリからのパスを指定します。

    ./appcompat.sh --dex-file=/path-from-root/your-app.apk
    

Linux

Linux で veridex ツールを実行する方法は次のとおりです。

  1. ビルド済みの Android ランタイム リポジトリから veridex ツールをダウンロードします。
  2. appcompat.tar.gz ファイルの内容を抽出します。
  3. 抽出したフォルダ内で veridex-linux.zip ファイルを見つけて解凍します。
  4. 解凍したフォルダに移動して、次のコマンドを実行します。your-app.apk には、テストする APK を指定します。

    ./appcompat.sh --dex-file=your-app.apk
    

Android Studio の lint ツールを使用したテスト

Android Studio でアプリをビルドするたびに、lint ツールはコードに問題がないかどうか検査します。非 SDK インターフェースを使用しているアプリの場合、そのインターフェースがどのリストに含まれるかに応じて、ビルドのエラーや警告が表示されることがあります。

コマンドラインから lint ツールを実行したり、特定のプロジェクト、フォルダ、ファイルで検査を手動で実行したりすることもできます。

Google Play Console を使用したテスト

アプリを Google Play Console のテストトラックにアップロードすると、自動的にテストが行われて問題がないかどうかチェックされ、リリース前レポートが生成されます。非 SDK インターフェースを使用しているアプリの場合、そのインターフェースがどのリストに含まれるかに応じて、エラーや警告がリリース前レポートに表示されます。

詳しくは、リリース前レポートを使って問題を特定する記事での Android の互換性に関する説明をご覧ください。

新しい公開 API のリクエスト

アプリの機能に使用している非 SDK インターフェースの代わりが見つからない場合は、Issue Tracker で機能リクエストを作成して、新しい公開 API をリクエストできます。

機能リクエストを作成する際は、以下の情報を提供してください。

  • アプリで使用しているサポート対象外の API(Accessing hidden ... logcat メッセージに表示される完全な記述子を含む)。
  • その API を使用する必要がある理由(低レベルの詳細情報だけでなく、API が必要な機能の高レベルの詳細情報を含む)。
  • 関連する公開 SDK API では目的を果たせない理由。
  • 試してみた他の方法と、それらがうまくいかなかった理由。

機能リクエストでこれらの詳細情報を提供すると、新しい公開 API が認められる可能性が高くなります。

その他の質問

このセクションでは、デベロッパーからよく寄せられるその他の質問に対する回答を紹介します。

一般的な質問

Google ではどのようにしてあらゆるアプリに関するニーズを Issue Tracker で収集するのですか?

Google では、以下の方法によって強化されたアプリの静的解析を利用して、Android 9(API レベル 28)向けの最初のリストを作成しました。

  • 主要な Play アプリと Play 以外のアプリの手動によるテスト
  • 内部レポート
  • 内部ユーザーからの自動データ収集
  • デベロッパーのプレビュー レポート
  • 誤検出が増えないように設計されたその他の静的解析

Google では新しいリリースごとにリストを評価しており、その際、Issue Tracker からのデベロッパー フィードバックだけでなく、API の使用状況も考慮します。

非 SDK インターフェースへのアクセスを有効にするにはどうすればよいですか?

adb コマンドを使用して API 適用ポリシーを変更することで、開発デバイスでの非 SDK インターフェースへのアクセスを有効にすることができます。使用するコマンドは、API レベルに応じて異なります。ユーザーに root 権限のあるデバイスでなくてもコマンドを実行できます。

Android 10(API レベル 29)以降

アクセスを有効にするには、次の adb コマンドを使用します。

コマンド:

adb shell settings put global hidden_api_policy  1

API 適用ポリシーをデフォルト設定に戻すには、次のコマンドを使用します。

adb shell settings delete global hidden_api_policy
Android 9(API レベル 28)

アクセスを有効にするには、次の adb コマンドを使用します。

adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

API 適用ポリシーをデフォルトの設定に戻すには、次のコマンドを使用します。

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

API 適用ポリシーの整数は以下のいずれかの値に設定できます。

  • 0: 非 SDK インターフェースの検出をすべて無効にします。この設定にすると、非 SDK インターフェースの使用を示すログメッセージがすべて無効になり、StrictMode API を使用したアプリのテストができなくなります。この設定は推奨されません。
  • 1: すべての非 SDK インターフェースへのアクセスが有効になりますが、非 SDK インターフェースの使用について警告するログメッセージが出力されます。この設定にすると、StrictMode API を使用してアプリをテストすることもできます。
  • 2: ブロックリストに登録されている非 SDK インターフェースと、対象 API レベルの条件付きでブロックされる非 SDK インターフェースを使用できないようにします。

非 SDK インターフェースのリストに関する質問

非 SDK API のリストはシステム イメージのどこにありますか?

これらのリストは、プラットフォームの dex ファイル内にあるフィールドとメソッドのアクセス フラグビットにエンコードされています。システム イメージ内にこれらのリストを含む個別のファイルはありません。

異なる OEM デバイスでも、Android バージョンが同じであれば、非 SDK API のリストは同じですか?

OEM は独自のインターフェースをブロックリストに追加できますが、AOSP の非 SDK API のリストからインターフェースを削除することはできません。CDD はこうした変更を防止しています。Android ランタイムがリストを適用しているかどうかは CTS テストで確認できます。

ネイティブ コードには、非 NDK インターフェースに関する制限はありますか?

Android SDK には Java インターフェースが含まれています。Android 7(API レベル 26)以降、ネイティブ C / C++ コードの非 NDK インターフェースへのアクセスは制限されるようになりました。詳しくは、Android N でのプライベート C / C++ シンボルの制限による安定性の向上に関するブログ記事をご覧ください。

dex2oat または DEX ファイルの操作を制限する計画はありますか?

dex2oat バイナリへのアクセスを制限するアクティブな計画はありませんが、Dalvik 実行可能形式で公に規定されている部分以外に、DEX ファイル形式を安定版または公開版のインターフェースにする予定はありません。Google は、dex2oat と、DEX 形式の未指定の部分をいつでも変更または削除する権限を有します。また、dex2oat によって生成された ODEX(別名 OAT)、VDEX、CDEX などの派生ファイルはすべて、未指定の形式であることに注意してください。

重要なサードパーティ SDK(難読化ツールなど)で非 SDK インターフェースを使用する必要がある場合、今後 Android バージョンとの互換性を維持するにはどうすればよいですか?この場合、Android の互換性要件を放棄できますか?

SDK ごとに互換性要件を放棄する予定はありません。非 SDK インターフェースがサポート対象外リスト(以前のグレーリスト)に分類されているかどうかだけに頼って互換性を維持している SDK デベロッパーは、SDK インターフェースか別の手段への移行を検討することをおすすめします。非 SDK インターフェースの代わりに使用できる手段が見つからない場合は、新しい公開 API をリクエストする必要があります。

非 SDK インターフェースの制限はすべてのアプリ(サードパーティのアプリだけでなく、システムアプリやファースト パーティのアプリを含む)に適用されますか?

はい、適用されます。ただし、プラットフォーム キーで署名されたアプリと一部のシステム イメージ アプリは除きます。この除外は、システム イメージに含まれるアプリ(または更新対象のシステム イメージ アプリ)にのみ適用されます。このリストは、SDK API ではなく、プライベート プラットフォーム API(LOCAL_PRIVATE_PLATFORM_APIS := true)に対してビルドされるアプリのみを対象にしています。