SDK ランタイム

フィードバックを送信

Android プラットフォームでは、アプリ サンドボックスのコンセプトをもちいることで、プロセス境界に沿ったアプリコードの堅牢な実行とセキュリティ境界が維持されます。アプリにサードパーティのコードを含めることは一般的であり、多くの場合、広告 SDK や分析 SDK などの SDK の形をとります。このような再利用により、アプリ デベロッパーはアプリの差別化に専念できると同時に、専門家の力を借り、負担なく独自で行える範囲をさらに広げることができます。

ほとんどのオペレーティング システムと同様に、Android では、SDK はホストアプリのサンドボックス内で実行され、ホストアプリと同じ特権と権限を継承します。また、ホストアプリのメモリとストレージへのアクセス権も継承します。このアーキテクチャでは SDK とアプリを柔軟に統合できますが、非公開のユーザーデータが収集され共有される可能性も生じます。さらに、アプリ デベロッパーは、サードパーティ SDK の機能やアクセスするデータの範囲を十分に把握していない場合があり、アプリのデータ収集や共有の方法について説明することは困難です。

Android 13 では、SDK ランタイムという専用のランタイム環境でサードパーティ SDK を実行できる新しいプラットフォーム機能が追加されています。SDK ランタイムには、ユーザーデータの収集と共有に関して、次の強力な安全保護対策と保証が用意されています。

  • 実行環境の変更
  • SDK の権限とデータアクセス権の明確な定義

このデザインについては、モバイルアプリ広告コミュニティからのフィードバックを積極的に求めています。また、幅広いデベロッパー コミュニティからのフィードバックもお待ちしております。その他のユースケースのサポートなど、SDK ランタイムの今後のイテレーションを考えるうえで参考にさせていただきます。

目標

この提案では、以下の目標を達成することを目指します。

  • プロセスの分離と明確に定義された API およびデータアクセス制御を通じて、サードパーティ SDK によってユーザーのアプリデータが秘密裡にアクセスされたり共有されたりすることを抑えます。プロセスの分離の詳細については、このドキュメントの別のセクションをご覧ください。
  • SDK による一意の永続的な識別子へのアクセスを制限することで、サードパーティ SDK によってユーザーのアプリ使用状況が秘密裡に追跡されることを抑えます。
  • アプリ デベロッパーとエンドユーザーの負担を軽減し、安全性を確保したうえで、アプリに対する SDK アップデートの配信を推進します。信頼できる SDK の配信モデルの案については、このドキュメントの別のセクションをご覧ください。
  • アプリ デベロッパーが、アプリのデータアクセスと共有の方法について適切に説明できるようにします。
  • SDK デベロッパーが、JNI コードなどの安全でない特定の言語構造を制限することで、他の SDK による改ざんを防止できるようにします。
  • メディアを表示するリモートビューを完全に制御することで、広告 SDK が無効なトラフィックや広告の不正行為を検出して防止できるようにします。
  • アプリ デベロッパーと SDK デベロッパーへの過度な影響をできる限り最小に抑えます。

独立したプロセスで SDK を実行する

提案された SDK ランタイムでは、互換性のある SDK(このドキュメントではランタイム対応(RE)SDK と呼びます)がアプリの別のプロセスで動作するようになっています。プラットフォームにより、アプリのプロセスとその SDK ランタイム間の双方向通信が容易になります。詳細については、このドキュメントの通信に関するセクションをご覧ください。非 RE SDK は、現在と同様にアプリのプロセスに残ります。次の図は、これらの変更を示しています。

アプリプロセスを実行する全体を示す前の図
SDK 呼び出しコードと、このコードからの呼び出しを受け取る SDK は、SDK ランタイムに追加される前は、すべてアプリのプロセス内に存在します。

アプリプロセスと SDK ランタイム プロセスに分割されたプロセスを示す図
SDK 呼び出しコードを SDK ランタイムに追加すると、アプリのフォアグラウンド プロセスで、SDK 呼び出しコードは SDK インターフェースと通信します。これらのインターフェースはプロセスの境界を越えて SDK ランタイム プロセスに移動し、SDK 自体を呼び出します。

信頼性の高い新しい SDK 配信モデル

SDK とアプリの分離という提案は、SDK とアプリの配信という別の分離コンセプトにもつながります。この提案では、アプリの SDK ランタイムに正しい SDK がインストールされるように、配信とインストールについて信頼性の高いメカニズムが必要になります。そうすることで、無効な SDK が読み込まれないようにユーザーとアプリ デベロッパーを保護できるほか、アプリストアで SDK を配信するアプリ デベロッパーの負担を大幅に減らすことができます。

SDK を配信する際には、アプリストアにアップロードする前にアプリと静的にリンクしてパッケージ化する必要がありますが、これがなくなります。代わりに、次のプロセスが発生します。

  1. SDK デベロッパーは、アプリ自体とは別に、バージョニングされた SDK をアプリストアにアップロードできます。
  2. アプリ デベロッパーは、SDK の依存関係をバージョンごとに指定してビルドし、実際の SDK の依存関係を含まないアプリリリースをアップロードします。
  3. ユーザーがこのアプリをダウンロードする際には、インストール プロセスでアプリに指定された SDK の依存関係が使用され、アプリがアプリストアからダウンロードされます。

この新たな配布メカニズムにより、SDK デベロッパーは、アプリ デベロッパーの関与なしに、SDK に互換性を破る変更(つまり、API やそのセマンティクスの変更なし)を加え、デバイスに配布できます。こうした互換性を損なわない SDK の変更は、アプリ デベロッパーが新しい SDK でアプリを再ビルドするのを待つ必要も、エンドユーザーによるアプリの更新を待つ必要もなく、デプロイまたはロールバックできます。互換性を破る変更については、アプリ デベロッパーが更新する必要がありますが、SDK デベロッパーは最新の互換性を破る変更や修正をより迅速かつ均一に、より多くの人々に提供でき、理想的にはバージョン サポートを最小限に抑えることができます。

次の図は、SDK ディストリビューションに対して提案されている変更を示しています。

変更前の図
SDK ランタイムが導入される前は、デベロッパーは SDK を直接アプリに送信していました。

変更後の図
SDK ランタイムの導入後、SDK デベロッパーは SDK アップロード UI を使用して SDK をアプリストアに公開します。 アプリストアは、SDK の依存関係とともにエンドユーザー デバイスへのアプリの配信を処理します。

SDK とアプリのビルド、実行、配信方法の変更

この提案は、柔軟な SDK ランタイムと配信技術の実現を目的とした最初のものです。以降のセクションでは、次の幅広いカテゴリにわたって一連の変更を提案します。

  • アクセス: 権限、メモリ、ストレージ
  • 実行: 言語、ランタイムの変更、ライフサイクル、メディアのレンダリング
  • 通信: アプリ~SDK 間、SDK~SDK 間
  • 開発: このモデルでのビルド、デバッグ、テストの方法
  • 配信: Android、アプリ、SDK のバージョン間での配信、更新、ロールバックの方法

このドキュメントには、一般的な質問に対応するためのよくある質問も記載されています。

これは初期の設計案であり、エコシステムのメンバーにとっては意味のある変更となる可能性があることを Google は理解しています。そのため Google では積極的にフィードバックを募っており、Issue Tracker からフィードバックをいただくようお願いしています。

アクセス

システムのプライバシーを管理するということは、さまざまな当事者による複数のリソースへのアクセス方法を管理するということを意味します。Google は、プライバシーに関する価値提案を満たすために、アプリ、SDK、ユーザーデータへのアクセスモデルを更新し、最小権限の原則に従って、機密情報になり得るデータへの非公開のアクセスを防止することを提案します。

SDK の権限

別のプロセスとして、SDK ランタイムは、ユーザーがアプリに付与した権限を継承するのではなく、明確に定義された権限セットを使用します。広告関連の SDK で使用される権限に関する予備調査に基づき、SDK ランタイムの SDK からデフォルトで以下の権限にアクセスできるようにすることを提案します。

  • INTERNET: ウェブサービスと通信できるようにするためのインターネット アクセス。
  • ACCESS_NETWORK_STATE: ネットワークに関する情報へのアクセス。
  • クロスアプリ識別子にアクセスすることなく、主要な広告機能を提供できるプライバシー保護 API の利用に関する権限。
  • AD_ID: 広告 ID をリクエストする機能。これも、この権限に対するアプリのアクセス権によって制限されます。
  • BIND_GET_INSTALL_REFERRER_SERVICE: Google Play Install Referrer API を使用してアプリのインストール元を特定する機能。

現在、プライバシーとユーザビリティの両面からエンドユーザーへの影響を抑えつつ、追加の権限を承認するかどうか、またどのように承認するかについて検討しています。この権限のセットでは対応できないと考えられるユースケースがあれば、ぜひフィードバックをお寄せください

メモリ

SDK ランタイムには、独自のプロセスがあるため、独自の分離されたメモリ空間があります。この構造においては、SDK がアプリのメモリ領域にアクセスすることがデフォルトで拒否され、同様に SDK のメモリ領域にアクセスすることもできなくなります。最小権限の原則に沿ったうえで、このデフォルトの動作を維持することを提案します。

ストレージ

ここでの提案の目的は、SDK が通常のオペレーションのためにストレージにアクセスする必要性と、永続ストレージを使用したアプリ間やプロセス間のトラッキングを最小限に抑えることのバランスをとることです。ストレージにアクセスする方法について、次のように更新することを提案します。

  • アプリは SDK ストレージに直接アクセスできなくなります。その逆も同様です。
  • このデバイスの外部ストレージには SDK からアクセスできません。
  • 各 SDK ランタイム内には、すべての SDK からアクセスできるストレージと、特定の SDK 専用のストレージの両方があります。

現在のストレージ モデルと同様に、ストレージ自体のサイズに任意の制限はありません。SDK はアセットをキャッシュに保存するためにストレージを使用できます。このストレージは、SDK がアクティブに実行されていないときに定期的にクリアされます。

実行

アプリ、SDK、ユーザーの間でプライベート システムを確保するには、実行コンテキスト自体(コード形式、言語構造、アクセス可能な API、システムデータ)でプライバシー境界を強化するか、少なくとも回避する手段を導入しないようにする必要があります。同時に、現在の SDK の高機能なプラットフォームとランタイム機能の大部分にも引き続きアクセスできるようにします。このバランスをとるために、ランタイム環境に対する一連の更新を提案します。

コード

Android コード(アプリと SDK)は、コードの記述言語が Kotlin か Java かにかかわらず、主に Android ランタイム(ART)によって解釈されます。豊富な ART と言語構造に加え、代替手段(特にネイティブ コード)と比較した場合の検証可能性の高さから、機能とプライバシーのバランスが適切に保たれているように見えます。Google では、JNI アクセスをサポートせず、ランタイム対応の SDK コードを Dex バイトコードのみで構成することを提案しています。

カスタム パッケージの SQLite を使用するなどのユースケースもあります。ネイティブ コードを使用している場合には、Android SDK の組み込みバージョンの SQLite など、代替手段に置き換える必要があります。

SELinux

Android では、各プロセス(root として実行されているものを含む)が特定の SELinux コンテキストで実行されるため、カーネルでシステム サービス、ファイル、デバイス、その他のプロセスへのアクセス制御を管理できます。Google が進めようとしているプライバシー保護の回避を最小限に抑えつつ、SDK のユースケースの大部分を保持するために、システム以外のアプリの SELinux コンテキストから、SDK ランタイムを対象に次のように更新することを提案します。

  • アクセスできるシステム サービスを一部に限る(設計中)。
  • SDK が APK 内のコードの読み込みと実行しかできないようにする
  • アクセスできるシステム プロパティを一部に限る(設計中)。

API

SDK ランタイム内でのリフレクション API と呼び出し API の使用は許可されます。ただし、別のランタイム対応 SDK でリフレクション API や呼び出し API を使用することはできません。禁止 API の提案の全文については、今後のアップデートでお知らせします。

さらに、最近の Android プラットフォーム リリースでは、プライバシー強化のために永続的な識別子へのアクセスが制限されるようになりました。SDK ランタイムでは、クロスアプリ トラッキングに使用される可能性のある識別子へのアクセスをさらに制限することを提案します。

SDK ランタイム API は、フォアグラウンドで実行されているアプリからのみアクセスできます。バックグラウンドでアプリから SdkSandboxManager API にアクセスしようとすると、SecurityException がスローされます。

また、RE SDK では、通知 API を使用したユーザー通知の送信がいかなる時点でもできません。

Lifecycle

現在、アプリ SDK はホストアプリのライフサイクルに従うようになっています。つまり、アプリがフォアグラウンドで開始または終了される、シャットダウンされる、メモリ負荷のためにオペレーティング システムによって強制停止されると、アプリ SDK も同じ動作をします。そこで、アプリ SDK を別のプロセスに分割するよう提案しますが、これはライフサイクルを次のように変更することを意味します。

  • アプリは、ユーザーまたはオペレーティング システムによって終了させることができる。直後に、SDK ランタイムが自動的に終了する。
  • SDK ランタイムは、メモリ負荷や、SDK での未処理の例外などにより、オペレーティング システムによって終了させることができる。

    Android 13 ではアプリがフォアグラウンドにある場合、SDK ランタイムは高優先度で実行され、停止する可能性は低くなります。アプリがバックグラウンドに移行すると、SDK ランタイム プロセスの優先度が低くなり、停止の対象になります。アプリがフォアグラウンドに戻っても、SDK ランタイム プロセスの優先度は低いままです。そのため、メモリ不足で終了してしまう可能性は、アプリより非常に高くなります。

    Android 14 以降では、アプリと SDK ランタイムのプロセス優先度は一致しています。アプリと SDK ランタイムの ActivityManager.RunningAppProcessInfo.importance のプロセス優先度はほぼ同じです。

    アプリの実行中に SDK ランタイムが終了した場合(SDK に未処理の例外がある場合など)、以前に読み込まれたすべての SDK とリモートビューを含む SDK ランタイムの状態が失われます。アプリ デベロッパーは、次のいずれかの方法で SDK ランタイムの終了に伴って処理を実行できます。

    • このプロポーザルでは、関連するライフサイクル コールバック メソッドをアプリ デベロッパーに提供し、SDK ランタイムの終了が発生したタイミングを検出します。
    • 広告の表示中に SDK ランタイムが終了した場合、広告が想定どおりに機能しなくなる可能性があります。たとえば、ビューが画面上でフリーズし、操作できなくなることがあります。アプリでは、ユーザー エクスペリエンスに影響しない場合は広告ビューを削除できます。
    • アプリでは SDK の読み込みと広告のリクエストを再試行できます。
    • Android 14 では、SDK の読み込み中に SDK ランタイムが終了し、アプリ デベロッパーが前述のライフサイクル コールバック メソッドを登録していない場合、デフォルトではアプリは終了します。SDK を読み込んだアプリプロセスのみが正常に終了します。
    • 通信のために SDK から返されたバインダ オブジェクト(SandboxedSdk など)は、アプリで使用されている場合に DeadObjectException をスローします。

    このライフサイクル モデルは、今後の更新で変更される可能性があります。

    永続的な障害が発生した場合には、アプリ デベロッパーは SDK を使用しないグレースフル デグラデーションを予定する必要があります。あるいは、SDK がアプリのコア機能に不可欠であればユーザーに通知する必要があります。このアプリと SDK の間のインタラクションについて詳しくは、このドキュメントの通信のセクションをご覧ください。

非 RE SDK では、サービス、アクティビティ、ブロードキャストなど、組み込みアプリで使用できる標準的な OS プリミティブを引き続き使用できますが、RE SDK では使用できません。

特別な場合

次のようなケースはサポートされていないため、予期しない動作が発生する可能性があります。

  • 複数のアプリが同じ UID を共有している場合、SDK ランタイムが正常に機能しない可能性があります。共有 UID のサポートは今後追加される可能性があります。
  • 複数のプロセスを持つアプリの場合、SDK の読み込みはメインプロセスで行う必要があります。

メディアのレンダリング

複数の SDK で、テキスト、画像、動画などのコンテンツをアプリ指定のビューにレンダリングする場合があります。これを実現するために、リモート レンダリング アプローチを提案します。このアプローチでは、SDK が SDK ランタイム内からメディアをレンダリングしますが、アプリ指定のビューでメディアをレンダリングできるように SurfaceControlViewHost API を使用します。これにより、SDK では、ユーザーに限定された方法でメディアをレンダリングする機能が提供されるとともに、レンダリングされたメディアに対する無効または不正なユーザー操作の防止と検出が行えます。

SDK ではなくアプリがレンダリングするネイティブ広告は、SDK ランタイムの SDK でサポートされます。ネイティブ広告以外でも、シグナルの収集処理とクリエイティブの取得処理が一貫して行われます。これについては現在調査中です。

インストリーム動画広告は、アプリ内のプレーヤーに表示される動画とともに配信される広告です。動画が SDK のプレーヤーやビューではなく、アプリ内のプレーヤー内で再生されるため、レンダリング モデルは他の広告フォーマットとは異なります。Google は、サーバーサイドの広告挿入と SDK ベースの広告挿入の両方をサポートするメカニズムを検討しています。

システムの健全性

Google は、システムの健全性に関して SDK ランタイムがエンドユーザーのデバイスに与える影響を最小限に抑えることを目指しており、そのための方法を設計しています。ただし、Android(Go エディション)など、システム リソースが非常に限られている一部のエントリー レベル Android 13 デバイスでは、システムの健全性に影響するため、SDK ランタイムがサポートされません。SDK ランタイムを正常に使用するために必要な最小要件については、近日中にお知らせいたします。

通信

現在、アプリと SDK は同じプロセスで実行されているため、両者の間の通信は妨げられず、仲介もされません。また、Android では、SDK で通信の開始と終了を行う場合でもアプリ間の通信が可能です。この自由な通信モデルにより、さまざまなユースケースが実現される一方で、アプリとアプリ、アプリ内の SDK と SDK、アプリ間の SDK と SDK の間で、非公開のデータが共有される可能性が生じます。このような通信の価値と Google が掲げた目標の実現との間でバランスを取ることを目指し、通信モデルを次のように更新することを提案します。

アプリ~SDK 間

アプリと SDK の間のインターフェースは SDK への最も一般的な通信経路です。SDK の API には、ユーザー向けの差別化とイノベーションの多くが存在しています。Google は、SDK のイノベーションと差別化の機能を保つことを目指します。その結果として、SDK がアプリに対して API を公開し、アプリがイノベーションの恩恵をすべて受けられるようにすることを提案します。

具体的には、SDK ランタイムのプロセス境界構造をふまえ、アプリと SDK の間の境界を越えて API の呼び出しとレスポンスまたはコールバックを伝送するために、アプリ内でアクセス可能なマーシャリング レイヤを構築します。このマーシャリング レイヤのインターフェースは SDK デベロッパーが定義し、Google が開発する公式のオープンソース ビルドツールで生成します。

この提案では、アプリ デベロッパーと SDK デベロッパーがマーシャリングに関連するボイラープレートを記述しなくていいようにすることを目指します。また同時に、SDK デベロッパーに柔軟性を提供しつつ、SDK コードが SDK ランタイムで実行されるようにして、Google の目指すプライバシー目標を達成できるようにします。なお、この方法を採用する場合には、API の定義言語とツールについて、デベロッパーの意見を取り入れて設計する予定です。

一般的なインタラクション モデルは次のようになります。

  • アプリがインターフェースを通じて SDK を呼び出し、コールバックで渡す。
  • SDK がコールバックを使用して非同期的にリクエストを処理し、応答する。
  • 任意のパブリッシャー サブスクライバー モデルに一般化できる。つまり、アプリはコールバックで SDK のイベントに登録でき、イベントが発生するとコールバックがトリガーされる。

この新しいクロスプロセス構造を提案することで、アプリ自体のプロセス ライフサイクルと、SDK ランタイムのプロセス ライフサイクルという 2 つのプロセス ライフサイクルを管理する必要が生じます。今回の提案では、この点を可能な限り自動化することで、アプリ デベロッパーと SDK デベロッパーへの影響を最小限に抑えることを目指しています。次の図は、検討中のアプローチを示しています。

図
アプリと SDK の起動時にアプリと SDK の間のインタラクションを示すシーケンス図。

プラットフォームでは、SDK ランタイム プロセスに SDK を動的に読み込み、プロセスの状態の変化について通知を受け、SDK ランタイムに読み込まれた SDK とやりとりするための新しい API が公開されます。

上の図のグラフは、マーシャリング レイヤがない下位レベルでのアプリ間通信を示しています。

アプリは、次の手順で SDK ランタイム プロセスで実行されている SDK と通信します。

  1. アプリは SDK とやりとりする前に、SDK を読み込むようプラットフォームにリクエストします。システムの整合性を確保するために、アプリがマニフェスト ファイルで読み込む予定の SDK を指定します。指定された SDK だけが読み込みを行えます。

    次のコード スニペットに API の例を示します。

    SdkSandboxManager.loadSdk(String sdkName, Bundle data, Executor executor,
        OutcomeReceiver<SandboxedSdk, LoadSdkException> receiver)
    
  2. SDK は、読み込み完了の通知を受け取り、そのインターフェースを返します。このインターフェースは、アプリプロセスで使用するためのものです。プロセス境界外でインターフェースを共有するには、インターフェースを IBinder オブジェクトとして返す必要があります。

    バインドされたサービスガイドでは、IBinder を提供するさまざまな方法について説明しています。いずれの場合も、SDK と呼び出し元アプリの間で一貫性を保つ必要があります。図では、AIDL を例として使用しています。

  3. SdkSandboxManagerIBinder インターフェースを受け取り、アプリに返します。

  4. アプリは IBinder を取得して SDK インターフェースにキャストし、その関数を呼び出します。

    IBinder binder = sandboxSdk.getInterface();
    ISdkInterface mySdkInterface = ISdkInterface.Stub.asInterface(binder);
    mySdkInterface.something();
    

アプリは、次の手順で SDK からメディアをレンダリングすることもできます。

  1. このドキュメントのメディア レンダリングのセクションで説明したように、SDK を取得してビューにメディアをレンダリングするために、アプリは requestSurfacePackage() を呼び出して該当する SurfaceControlViewHost.SurfacePackage を取得します。

    次のコード スニペットに API の例を示します。

    SdkSandboxManager.requestSurfacePackage(String sdkName, Bundle extraParams,
            Executor executor,
            OutcomeReceiver<Bundle, RequestSurfacePackageException> receiver)
    
  2. アプリは SurfaceViewsetChildSurfacePackage API を介して、返された SurfacePackageSurfaceView に埋め込むことができます。

    次のコード スニペットに API の例を示します。

    SurfaceView.setChildSurfacePackage(SurfacePackage surfacePackage)
    

この提案では、IBinder API と requestSurfacePackage() API は汎用であり、アプリから直接呼び出されることを想定していません。代わりに、先に説明したように、アプリ デベロッパーの負担を軽減するため、これらの API は生成された API リファレンスによって「shim」レイヤで呼び出されます。

SDK~SDK 間

多くの場合、同じアプリ内の 2 つの SDK は通信する必要があります。これは、特定の SDK が構成要素 SDK で構成されるように設計されている場合や、呼び出し元アプリからのリクエストに対応するために、異なる当事者の 2 つの SDK が連携する必要がある場合に発生する可能性があります。

考慮すべき重要なケースが 2 つあります。

  • 両方の SDK がランタイム対応の場合。この場合、両方の SDK が SDK ランタイムで実行され、すべての保護が適用されます。SDK は、現在アプリ内で行っているような通信を行うことができません。そのため、SdkSandboxController の API が追加され、読み込まれたすべての RE-SDK の SandboxedSdk オブジェクトを取得できるようになりました。これにより、RE-SDK が SDK ランタイムに読み込まれた他の SDK と通信できるようになります。
  • 1 つの SDK のみがランタイム対応の場合
    • 呼び出し元 SDK がアプリ内で実行されている場合は、SDK ランタイム内の 2 番目の SDK をアプリ自体が呼び出す場合と同じように動作します。
    • 呼び出し元の SDK が SDK ランタイム内で実行されている場合、このプロポーザルでは、アプリのコードがリッスン、処理し、提供されたコールバックで応答するアプリ間セクションで説明した IBinder を使用してメソッドを公開することをおすすめします。
    • ランタイム対応でない広告 SDK は自身を登録できない可能性があるため、パートナー SDK またはアプリ SDK をアプリの直接依存関係として含み、登録を処理するメディエータ SDK を作成することをおすすめします。このメディエータ SDK は、ランタイム非対応の SDK や他のアプリの依存関係と、アダプタとして機能するランタイム対応のメディエータ間の通信を確立します。

SDK 間通信の機能セットは、以下のカテゴリに分類されます。

  • SDK ランタイム内の SDK 間通信(最新のデベロッパー プレビューで利用可能)
  • アプリと SDK ランタイム間の SDK 間通信(最新のデベロッパー プレビューで利用可能)
  • メディエーションのビューとリモート レンダリングの仕組み(開発中の提案)

プリミティブが設計中で、次のユースケースが検討されています。

  1. メディエーションと入札: 多くの広告 SDK にはメディエーションや入札の機能があります。これにより SDK は他のさまざまな SDK を呼び出して、広告の表示(メディエーション)や、オークション(入札)を行うためのシグナル収集を行います。調整 SDK は通常、調整 SDK が提供するアダプターを通じて他の SDK を呼び出します。前述のプリミティブを考慮すると、調整 SDK は、RE かどうかにかかわらず、通常のオペレーションのためにすべての RE SDK と非 RE SDK にアクセスできる必要があります。この場合のレンダリングについては現在調査中です。
  2. 機能の検出: 一部の SDK プロダクトはより少ない SDK で構成されています。このようなプロダクトでは、SDK 間での検出プロセスを通じて、アプリ デベロッパーに公開される最終的な機能セットが特定されます。このユースケースを有効にするために、登録と検出のプリミティブが想定されます。
  3. パブリッシャー サブスクリプション モデル: 一部の SDK はイベントのセントラル パブリッシャーを持つように設計されます。これは、他の SDK またはアプリが通知を受け取るためにコールバックを通じて登録できるものです。前述のプリミティブは、このユースケースをサポートする必要があります。

アプリ~アプリ間

アプリ間通信では、通信する 2 つのプロセスの少なくとも 1 つがランタイム対応の SDK であり、開示されていないデータ共有の潜在的なベクトルになります。そのため、SDK ランタイムは、クライアント アプリケーション以外のアプリや、別のアプリ用に作成された別の SDK ランタイムの SDK と直接通信チャネルを確立できません。これは、次の方法で確立できます。

  • SDK では、<service><contentprovider><activity> などのコンポーネントをマニフェストで定義できません。
  • SDK では ContentProvider の公開やブロードキャストの送信ができません。
  • SDK は別のアプリに属するアクティビティを起動できますが、このインテントで送信できる内容には制限があります。たとえば、このインテントにエクストラやカスタム アクションを追加することはできません。
  • SDK は、サービスの許可リストの開始またはバインドのみできます。
  • SDK はシステム ContentProvider のサブセット(com.android.providers.settings.SettingsProvider など)にのみアクセスできます。この場合、取得されたデータには識別子がなく、ユーザーの指紋の作成には使用できません。これらのチェックは、ContentResolver を使用した ContentProvider へのアクセスにも適用されます。
  • SDK は、保護されたブロードキャスト レシーバのサブセット(android.intent.action.AIRPLANE_MODE など)にのみアクセスできます。

マニフェスト タグ

SDK のインストール時に PackageManager は SDK のマニフェストを解析し、禁止されたマニフェスト タグが存在する場合は SDK のインストールに失敗します。たとえば、SDK では <service>, <activity>, <provider><receiver> などのコンポーネントを定義できません。また、マニフェストで <permission> を宣言することもできません。インストールに失敗したタグは、SDK ランタイムではサポートされていません。インストールに失敗しないが、通知なく無視されるタグは、今後の Android バージョンでサポートされる可能性があります。

これらのチェックは、SDK が SDK バンドルの作成に使用するビルド時ツールや、アプリケーション ストアへのアップロード時にも適用できます。

アクティビティのサポート

SDK ランタイム環境の SDK は、マニフェスト ファイルにアクティビティ タグを追加できず、Context.startActivity を使用して独自のアクティビティを開始することもできません。代わりに、プラットフォームはリクエストに応じて SDK のアクティビティを作成し、SDK と共有します。

プラットフォーム アクティビティのタイプは android.app.Activity です。プラットフォーム アクティビティは、アプリのアクティビティの一つから開始され、アプリタスクの一部です。FLAG_ACTIVITY_NEW_TASK はサポートされていません。

SDK がアクティビティを開始するには、SdkSandboxActivityHandler タイプのインスタンスを登録する必要があります。これは、アプリが SdkSandboxManager::startSdkSandboxActivity(Activity, IBinder) を呼び出してアクティビティを開始したときに、アクティビティの作成について通知するために使用されます。

アクティビティのリクエストの流れを以下のグラフに示します。

図
アクティビティの起動フローを示すシーケンス図。

開発環境

この提案の基本方針は、デベロッパー エコシステムへの影響を可能な限り最小限に抑えることです。このプロポーザルでは、RE アプリと SDK を作成、ビルド、デバッグするための包括的な開発ツールセットがデベロッパーに提供されます。この提案の整合性を確保するため、RE アプリと SDK の構成、作成、ビルドの方法にいくつかの変更があります。

オーサリング

Android Studio と関連ツールが SDK ランタイムに対応するように更新される予定です。デベロッパーが RE アプリと SDK を正しく設定し、既存の呼び出しやサポートされていない呼び出しを関連する新しい代替方法に更新できるようにサポートします。この提案では、デベロッパーにオーサリング フェーズでいくつかの手順を踏むよう求めています。

アプリ デベロッパー

アプリ マニフェストで、アプリの RE SDK と SDK 証明書の依存関係を指定する必要があります。今回の提案全体で、この依存関係の指定をアプリ デベロッパーからの信頼できる情報源として扱います。次に例を示します。

  • 名前: SDK またはライブラリのパッケージ名。
  • メジャー バージョン: SDK のメジャー バージョン コード。
  • 証明書ダイジェスト: SDK ビルドの証明書ダイジェスト。関連するアプリストアを通じて、SDK デベロッパーが特定のビルドについてこの値を取得して登録することを提案します。

これは、RE であるかどうかにかかわらず、アプリストアで配布される SDK にのみ適用されます。SDK を静的にリンクするアプリでは、現在の依存関係メカニズムを使用します。

デベロッパーへの影響を最小限に抑えるという目標をふまえると、SDK ランタイムをサポートするターゲット API レベルが指定されれば、ビルドが SDK ランタイムをサポートしているデバイスで実行されているかどうかにかかわらず、アプリ デベロッパーがビルドを 1 つ用意すれば済むようになることが重要です。

SDK デベロッパー

今回の提案では、RE SDK デベロッパーが、SDK またはライブラリ エンティティを表す新しい要素をマニフェストで明示的に宣言する必要があります。さらに、依存関係と同様の値のセットとマイナー バージョンを指定する必要があります。

  • 名前: SDK またはライブラリのパッケージ名。
  • メジャー バージョン: SDK のメジャー バージョン コード。
  • マイナー バージョン: SDK のマイナー バージョン コード。

RE SDK デベロッパーは、ビルド時の依存関係として他の RE SDK を使用している場合、アプリ デベロッパーが同じ依存関係を宣言する際と同じ方法で RE SDK を宣言する必要が生じます。RE SDK が非 RE SDK に依存する場合は、静的にリンクされます。非 RE SDK が、SDK ランタイムでサポートされていない機能を必要とする場合、またはアプリのプロセスで実行される必要がある場合、ビルド時またはテストパス中に検出される問題が発生する可能性があります。

RE SDK デベロッパーが、RE 未対応デバイスのサポート継続を必要とする場合もあります。RE 未対応デバイスには、Android 12 以前や、このドキュメントのシステムの健全性に関するセクションで説明した、システム リソースが非常に限られているエントリーレベルの Android 13 デバイスなどが挙げられます。Google は、SDK デベロッパーが単一のコードベースを保持して RE 環境と非 RE 環境に対応できるようにするためのアプローチに取り組んでいます。

ビルド

アプリ デベロッパー

アプリ デベロッパーがビルドステップで変更を必要とすることはほとんどないと見込まれます。SDK の依存関係は、ローカル分散またはアプリストアで分散(RE かどうか)に関係なく、lint チェック、コンパイル、ビルドのためにマシン上に存在する必要があります。アプリ デベロッパーから提供されるこれらの詳細情報と通常の使用状況を、Android Studio で抽象化し、可能な限り透明性を保つことを提案します。

DEBUG ビルドでは、デバッグを可能にするためにすべてのコードとシンボルを含める必要がありますが、RELEASE ビルドでは必要に応じて、アプリストアで配布される SDK(RE は問わない)をすべて最終的なアーティファクトから削除します。

今は設計の初期段階であるため、具体化するときに詳しくお伝えします。

SDK デベロッパー

Google は、SDK の非 RE 版と RE 版を単一のアーティファクトに組み込んで配信できるようにする取り組みを進めています。これによりアプリ デベロッパーは、RE 版と非 RE 版の両方の SDK で別々のビルドをサポートする必要がなくなります。

アプリと同様に、lint チェック、コンパイル、ビルドを行うためには、アプリストアで配信される依存関係 SDK がマシン上に存在する必要があります。これは、Android Studio によりシームレスに容易に行えるようになることが期待されます。

テスト

アプリ デベロッパー

この提案で説明しているとおり、アプリ デベロッパーは、Android 13 を搭載したデバイスで通常と同じようにアプリをテストすることが可能です。アプリをビルドしたら、RE デバイスまたはエミュレータにインストールできます。このインストール プロセスでは、SDK がリモート SDK リポジトリから取得されたか、ビルドシステムからキャッシュに保存されたかにかかわらず、デバイスまたはエミュレータの SDK ランタイムに正しい SDK がインストールされます。

SDK デベロッパー

SDK デベロッパーは通常、デバイスとエミュレータ上で自社のテストアプリを使用して開発内容をテストします。この点については、今回の提案で変更されることはありません。アプリ内検証は上述のアプリ デベロッパー向けの手順と同様に実施でき、RE アプリと非 RE アプリの両方に単一のビルド アーティファクトが使用されます。SDK デベロッパーは、SDK ランタイムかどうかにかかわらず、コードをステップスルーできます。ただし、高度なデバッグツールやプロファイリング ツールには制約の生じる場合があります。これについては現在調査中です。

配信

アプリの SDK からの分離を提案することで、SDK をアプリストアで配布することが可能になります。これは特定のアプリストアに限ったことではなく、全体として可能です。次のようなメリットがあります。

  • SDK の品質と一貫性が確保されます。
  • SDK デベロッパー向けのパブリケーションが合理化されます。
  • SDK のマイナー バージョン アップデートがインストール済みのアプリに迅速にロールアウトされます。

SDK の配信をサポートするには、アプリストアで以下の機能をほぼすべて提供する必要があります。

  • SDK デベロッパーが、アプリストアで配信可能な SDK をストアにアップロードし、アップデートやロールバックを行い、場合によっては削除を行うメカニズム。
  • SDK とその提供元、アプリとその提供元の整合性を確保し、依存関係を解決するメカニズム。
  • 一貫した信頼性を保ち、パフォーマンスの高い方法でデバイスにデプロイするメカニズム。

制限の進化

SDK ランタイムのコードに伴う制限は、Android の今後のバージョンで進化することが予想されます。アプリの互換性を確保するため、特定の SDK レベルのメインライン モジュール アップデートでは、こうした制限が変更されることはありません。特定の targetSdkVersion に関連付けられた動作は、アプリストア ポリシーを通じて targetSdkVersion のサポートが終了するまで保持されます。また、targetSdkVersion のサポート終了はアプリの場合よりも速い頻度で行われる可能性があります。特に最初の数リリースでは、Android SDK のバージョン間で制限が頻繁に変更されることを想定してください。

さらに、次のバージョンの Android で提案された制限セットを受けるグループに外部と内部のテスターが参加できるようにするカナリア メカニズムも構築しています。これにより、Google は制限セットに対して提案される変更に関するフィードバックと自信を得ることができます。

よくある質問

  1. 広告関連の SDK とは何ですか。

    広告関連の SDK とは、広告主が所有していないアプリで、営利目的のメッセージを使用したユーザーのターゲティングを促進する SDK です。これには、以降のターゲティング用にユーザー グループを作成できるアナリティクス SDK、広告配信 SDK、広告の不正使用防止 SDK と不正行為防止 SDK、エンゲージメント SDK、アトリビューション SDK などが含まれますが、これらに限定されません。

  2. どのような SDK でも SDK ランタイムで実行できますか?

    最初は広告関連の SDK に重点を置いていますが、プライバシーの保護を重視し、上記の条件に基づいて運用できると考える、広告関連以外の SDK のデベロッパーは、SDK ランタイムで実行されている SDK に関するフィードバックを送信できます。ただし、SDK ランタイムはすべての SDK 設計と互換性を持つように設計されているわけではありません。記載されている制限以外にも、SDK ランタイムは、ホスティング アプリとのリアルタイムまたは高スループットの通信を必要とする SDK には適さない可能性があります。

  3. プロセスを Java ベースのランタイム内で分離するのではなく、プロセスを分離することを選んだのはなぜですか。

    現在、Java ベースのランタイムは、Android ユーザーにとって望ましいプライバシー保証に必要なセキュリティ境界を容易に実現できません。実装するには数年にわたる取り組みが必要となり、成功する保証もありません。そのため、プライバシー サンドボックスでは、実績があり、理解の進んでいる技術であるプロセス境界を使用しています。

  4. SDK を SDK ランタイム プロセスに移行すると、ダウンロード サイズやディスク容量を節約できますか?

    複数のアプリを同じバージョンのランタイム対応 SDK と統合すると、ダウンロード サイズとディスク容量を節約できます。

  5. アプリがバックグラウンドになった場合、SDK ランタイムでアクセスできるアプリのライフサイクル イベントにはどのようなものがありますか?

    Google は、クライアント アプリのアプリレベルのライフサイクル イベント(アプリがバックグラウンドに移行する、アプリがフォアグラウンドに移行するなど)で SDK ランタイムに通知する設計のサポートに積極的に取り組んでいます。設計とサンプルコードは、今後のデベロッパー プレビューで共有されます。