ホストベースのカード エミュレーションの概要

NFC 機能を備えている Android デバイスの多くは、すでに NFC カード エミュレーションをサポートしています。ほとんどの場合、カードはデバイス内のセキュア エレメントと呼ばれる別のチップによってエミュレートされます。携帯通信会社が提供する SIM カードの多くにもセキュア エレメントが含まれています。

Android 4.4 以降では、ホストベースのカード エミュレーションと呼ばれる、セキュア エレメントを必要としない新たなカード エミュレーションの方式が導入されました。この機能により、あらゆる Android アプリがカードをエミュレートして、NFC リーダーと直接通信できます。このトピックでは、Android でのホストベースのカード エミュレーション(HCE)の仕組みと、この手法を使用して NFC カードをエミュレートするアプリの開発方法について説明します。

セキュア エレメントを使用したカード エミュレーション

セキュア エレメントを使用して NFC カード エミュレーションが提供される場合、エミュレートされるカードは、Android アプリを通じてデバイス上のセキュア エレメントにプロビジョニングされます。ユーザーがデバイスを NFC 端末にかざすと、デバイス内の NFC コントローラが、リーダーからのデータをすべてセキュア エレメントに直接転送します。図 1 にこのコンセプトを示します。

NFC リーダーが NFC コントローラを介してセキュア エレメントから情報を取得する図
図 1. セキュア エレメントを使用した NFC カード エミュレーション

セキュア エレメント自体が NFC 端末との通信を実行し、Android アプリはトランザクションに一切関与しません。トランザクションが完了した後、Android アプリはセキュア エレメントにトランザクションのステータスを直接クエリして、ユーザーに通知できます。

ホストベースのカード エミュレーション

ホストベースのカード エミュレーションを使用して NFC カードをエミュレートする場合、データはセキュア エレメントに転送されるのではなく、ホスト CPU に直接転送されます。図 2 は、ホストベースのカード エミュレーションの仕組みを示しています。

NFC リーダーが NFC コントローラを介して CPU から情報を取得する図
図 2. セキュア エレメントを使用しない NFC カード エミュレーション

サポートされている NFC カードとプロトコル

HCE プロトコル スタックを示す図
図 3. Android の HCE プロトコル スタック

NFC 規格は数多くのプロトコルをサポートしており、エミュレートできるカードの種類もさまざまです。

Android 4.4 以降では、今日の市場で一般的に使用されている複数のプロトコルがサポートされています。非接触型決済カードなどの既存の非接触型カードの多くが、すでにこうしたプロトコルに基づいています。また、それ自体がリーダーとして動作する Android NFC デバイスを含む、今日の市場の数多くの NFC リーダーでも、こうしたプロトコルがサポートされています(IsoDep クラスを参照)。これにより、Android 搭載デバイスのみを使用して、HCE に基づくエンドツーエンドの NFC ソリューションを構築してデプロイできます。

具体的には、Android 4.4 以降では、NFC フォーラムの ISO-DEP 仕様(ISO/IEC 14443-4 をベースとする)に基づく、ISO/IEC 7816-4 仕様の定義に従って Application Protocol Data Units(APDU)を処理するカードのエミュレートをサポートしています。Android が必須としているのは、NFC-A(ISO/IEC 14443-3 Type A)テクノロジーでの ISO-DEP のエミュレートのみです。NFC-B(ISO/IEC 14443-4 Type B)テクノロジーのサポートはオプションです。図 3 は、これらの仕様のレイヤを図示したものです。

HCE サービス

Android の HCE アーキテクチャは、Android Service コンポーネント(HCE サービス)に基づいています。サービスの主な利点の 1 つは、一切のユーザー インターフェースを持たずにバックグラウンドで動作できることです。これは、ポイントカードや交通系カードといった、利用時にユーザーにアプリの起動を求めるべきでない数多くの HCE アプリに特に適しています。デバイスを NFC リーダーにかざすと、適切なサービスが(まだ動作していない場合は)起動して、バックグラウンドでトランザクションを実行します。必要に応じて、そうしたサービスから追加の UI(ユーザーへの通知など)を表示することもできます。

サービスの選択

ユーザーがデバイスを NFC リーダーにかざしたときに、Android システムは、その NFC リーダーが通信する必要のある HCE サービスを識別する必要があります。ISO/IEC 7816-4 仕様では、アプリケーション ID(AID)を中心としてアプリを選択する方法を定義しています。AID は最大 16 バイトで構成されます。既存の NFC リーダー インフラストラクチャ向けのカードをエミュレートする場合、そうしたリーダーが予期する AID は通常、パブリックに登録されているよく知られた AID(例: Visa や MasterCard などの決済ネットワークの AID)です。

デベロッパーが自身のアプリ用に新たなリーダー インフラストラクチャをデプロイする場合は、独自の AID を登録する必要があります。AID の登録手順は、ISO/IEC 7816-5 仕様で定義されています。Android 用 HCE アプリをデプロイする場合は、他のアプリとの競合を回避するために、7816-5 に従って AID を登録することをおすすめします。

AID グループ

特定のアプリを実装するために、HCE サービスで複数の AID を登録し、すべての AID のデフォルトのハンドラとして設定することが必要な場合があります。グループ内の一部の AID が別のサービスに転送されることはサポートされていません。

一緒に保持される AID のリストは、AID グループと呼ばれます。AID グループ内のすべての AID に対して、Android は次のいずれかを保証します。

  • グループ内のすべての AID がこの HCE サービスにルーティングされます。
  • グループ内のどの AID もこの HCE サービスにルーティングされない(たとえば、別のサービスでもそのグループ内の AID を 1 つ以上リクエストしており、ユーザーがそちらのサービスを優先している場合)。

つまり、グループ内の AID の一部が異なる複数の HCE サービスにルーティングされる可能性がある、といった中間的な状態は存在しません。

AID グループとカテゴリ

各 AID グループはカテゴリに関連付けることができます。これにより Android が HCE サービスをカテゴリ別にグループ化することができ、それによって、ユーザーが AID レベルではなくカテゴリ レベルでデフォルトを設定できます。AID は一般のユーザーには無関係のため、アプリ内のユーザー向けの部分では AID を表示しないでください。

Android 4.4 以降では、次の 2 つのカテゴリがサポートされています。

HCE サービスを実装する

ホストベースのカード エミュレーションを使用して NFC カードをエミュレートするには、NFC トランザクションを処理する Service コンポーネントを作成する必要があります。

HCE をサポートしているかどうかを確認する

デバイスが HCE をサポートしているかどうかは、アプリで FEATURE_NFC_HOST_CARD_EMULATION 機能を確認することによって確認できます。アプリのマニフェストで <uses-feature> タグを使用して、アプリが HCE 機能を使用すること、また、アプリを動作させるためにその機能が必要かどうかを宣言します。

サービスの実装

Android 4.4 以降には、HCE サービスを実装するためのベースとして使用できる Service クラス(HostApduService クラス)が用意されています。

最初のステップは、次のコードサンプルに示すように HostApduService を拡張することです。

Kotlin

class MyHostApduService : HostApduService() {

    override fun processCommandApdu(commandApdu: ByteArray, extras: Bundle?): ByteArray {
       ...
    }

    override fun onDeactivated(reason: Int) {
       ...
    }
}

Java

public class MyHostApduService extends HostApduService {
    @Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
       ...
    }
    @Override
    public void onDeactivated(int reason) {
       ...
    }
}

HostApduService は、オーバーライドして実装する必要がある 2 つの抽象メソッドを宣言します。そのうちの 1 つである processCommandApdu() は、NFC リーダーからサービスに APDU が送信されるたびに呼び出されます。APDU は ISO/IEC 7816-4 仕様で定義されています。APDU は、NFC リーダーと HCE サービスとの間で交換されるアプリケーションレベルのパケットです。このアプリケーションレベルのプロトコルは半二重です。NFC リーダーはコマンド APDU を送信し、応答 APDU が返信されるまで待機します。

前述のとおり、Android では、リーダーが通信をリクエストしている HCE サービスを、AID を使用して特定します。通常、NFC リーダーがデバイスに送信する最初の APDU は SELECT AID APDU です。この APDU には、リーダーが通信をリクエストしている AID が含まれています。Android は APDU からその AID を抽出し、HCE サービスを解決して、そのサービスに APDU を転送します。

processCommandApdu() から応答 APDU のバイトを返すことで、応答 APDU を送信できます。このメソッドはアプリのメインスレッドで呼び出されますが、メインスレッドのブロックは避ける必要があります。応答 APDU をすぐに計算して返すことができない場合は null を返します。その後、必要な作業を別のスレッド上で実行し、作業が完了したら HostApduService クラスに定義されている sendResponseApdu() メソッドを使用して応答を送信します。

Android は、次のいずれかの状態になるまで、リーダーからの新しい APDU をサービスに転送し続けます。

  • NFC リーダーが別の SELECT AID APDU を送信し、OS によってその AID が別のサービスに解決される。
  • NFC リーダーとデバイスとの間の NFC リンクが切断される。

どちらの場合も、クラスの onDeactivated() の実装が、上記 2 つの状態のどちらが発生したかを示す引数を指定して呼び出されます。

既存のリーダー インフラストラクチャと連携する場合は、リーダーの予期する既存のアプリケーションレベルのプロトコルを HCE サービスに実装する必要があります。

自身で管理する新しいリーダー インフラストラクチャをデプロイする場合は、独自のプロトコルと APDU シーケンスを定義できます。APDU の量と交換するデータのサイズをできるだけ抑えてください。そうすることで、ユーザーがデバイスを NFC リーダーにかざす時間が短時間で済むようになります。妥当なデータの上限値は約 1 KB です。このサイズなら通常 300 ミリ秒以内でデータを交換できます。

マニフェストでのサービスの宣言と AID の登録

サービスは通常どおりマニフェストで宣言する必要がありますが、サービスの宣言にいくつかの項目を追加する必要があります。

  1. HostApduService インターフェースを実装する HCE サービスであることをプラットフォームに伝えるには、サービス宣言に SERVICE_INTERFACE アクションのインテント フィルタを追加します。

  2. このサービスがリクエストする AID グループをプラットフォームに伝えるために、HCE サービスに関する追加情報を含んだ XML リソースを指定する SERVICE_META_DATA <meta-data> タグをサービスの宣言に含めます。

  3. android:exported 属性を true に設定し、サービスの宣言で android.permission.BIND_NFC_SERVICE 権限を要求します。前者の属性が、外部アプリによるサービスのバインドを可能にします。その後、後者の権限によって、android.permission.BIND_NFC_SERVICE 権限を持つ外部アプリのみがサービスにバインドできるように強制します。android.permission.BIND_NFC_SERVICE はシステム権限であるため、これによって、サービスにバインドできるのは事実上 Android OS だけになります。

HostApduService マニフェスト宣言の例を次に示します。

<service android:name=".MyHostApduService" android:exported="true"
         android:permission="android.permission.BIND_NFC_SERVICE">
    <intent-filter>
        <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
    </intent-filter>
    <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
               android:resource="@xml/apduservice"/>
</service>

この meta-data タグでは apduservice.xml ファイルを指定します。そのようなファイルで、2 つの独自 AID を含んだ単一の AID グループの宣言の記述例を次に示します。

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc"
           android:requireDeviceUnlock="false">
    <aid-group android:description="@string/aiddescription"
               android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

<host-apdu-service> タグには、アプリの UI に表示できるサービスの説明を、ユーザー向けのわかりやすい形で指定した <android:description> 属性を含める必要があります。requireDeviceUnlock 属性を使用すると、このサービスを呼び出して APDU を処理する前にデバイスのロック解除を必須とするように指定できます。

<host-apdu-service> には <aid-group> タグを含める必要があります。各 <aid-group> タグでは、以下のようにする必要があります。

  • android:description 属性を含めます。この属性には、AID グループの説明を、UI での表示に適したユーザー向けのわかりやすい形で指定します。
  • android:category 属性を設定して、その AID グループが属するカテゴリを示します(例: CATEGORY_PAYMENT または CATEGORY_OTHER で定義される文字列定数)。
  • 1 つ以上の <aid-filter> タグを含めます。各タグには 1 つの AID が含まれます。AID は 16 進数形式で指定し、偶数個の文字を含める必要があります。

HCE サービスとして登録するには、アプリが NFC 権限を保持していることも必要です。

AID の競合の解決

複数の HostApduService コンポーネントが 1 台のデバイスにインストールされる場合があり、同じ AID が複数のサービスによって登録される可能性があります。Android は、次の手順で呼び出すサービスを決定します。

  1. ユーザーが選択したデフォルトのウォレット アプリが AID を登録している場合、そのアプリが呼び出されます。
  2. デフォルトのウォレット アプリが AID を登録していない場合、AID を登録したサービスが呼び出されます。
  3. 複数のサービスが AID を登録している場合、Android はどのサービスを呼び出すかをユーザーに尋ねます。

フォアグラウンド サービスの設定

フォアグラウンドのアプリは setPreferredService を呼び出して、特定のアクティビティがフォアグラウンドにあるときに優先するカード エミュレーション サービスを指定できます。このフォアグラウンド アプリの設定は、AID の競合解決をオーバーライドします。これは、ユーザーが NFC カード エミュレーションを使用する可能性があるとアプリが予測している場合に推奨される方法です。

Android 13 以降

設定 UI のデフォルトの支払い選択リストに適合するように、バナーの要件を正方形のアイコンに調整します。理想的には、アプリ ランチャー アイコンのデザインと同じである必要があります。この調整により、一貫性が高まり、見た目がよりすっきりします。

Android 12 以前

サービス バナーのサイズを 260x96 dp に設定し、メタデータ XML ファイル内で <host-apdu-service> タグにドローアブル リソースを指定した android:apduServiceBanner 属性を追加して、サービス バナーのサイズを設定します。次に例を示します。

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
        android:description="@string/servicedesc"
        android:requireDeviceUnlock="false"
        android:apduServiceBanner="@drawable/my_banner">
    <aid-group android:description="@string/aiddescription"
               android:category="payment">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

ウォレット アプリ

Android 15 以降には、デフォルトのウォレット アプリのロールが用意されています。このロールは、ユーザーが [設定] > [アプリ] > [デフォルト アプリ] に移動して選択できます。これにより、デバイスを支払い端末にかざしたときに呼び出されるデフォルトのウォレット アプリが定義されます。Android では、決済カテゴリで AID グループを宣言した HCE サービスをウォレット アプリとみなします。

アプリがデフォルトのウォレット アプリかどうかを確認する

アプリがデフォルトのウォレット アプリかどうかを確認するには、RoleManager.isRoleHeld()RoleManager.ROLE_WALLET を渡します。

アプリがデフォルトではない場合は、RoleManager.ROLE_WALLETRoleManager.createRequestRoleIntent() に渡すことで、デフォルトのウォレット ロールをリクエストできます。

ウォレット アプリに必要なアセット

視覚性に優れた魅力的なユーザー エクスペリエンスを提供するため、HCE ウォレット アプリは、サービスバナーを提供する必要があります。

観察モード

Android 15 では、Observe Mode 機能が導入されています。有効にすると、デバイスは NFC ポーリング ループを監視し、その通知を適切な HostApduService コンポーネントに送信して、特定の NFC 端末とのやり取りの準備を整えることができます。HostApduService は、truesetObserveModeEnabled() に渡すことで、デバイスをオブザーバ モードにできます。これにより、NFC トランザクションを許可せず、代わりにポーリング ループをパッシブに監視するように NFC スタックに指示します。

ポーリング ループ フィルタ

HostApduService のポーリング ループ フィルタは、次のいずれかの方法で登録できます。

ポーリング ループ フィルタが標準以外のポーリング フレームに一致すると、NFC スタックは processPollingFrames() メソッドを呼び出して、それらのポーリング フレームを対応する HostApduService に転送します。これにより、サービスは、ユーザーが取引の準備ができており、取引を行う意思があることを確認するために必要な手順(ユーザーの認証など)を実行できます。NFC リーダーがポーリング ループで標準フレームのみを使用している場合、NFC スタックは、そのサービスがフォアグラウンドにある場合は優先フォアグラウンド サービスに、それ以外の場合はデフォルトのウォレット ロール保持者にポーリング フレームを転送します。

ポーリング フレーム通知には、ベンダー固有のフィールド強度の測定値も含まれます。この値は、getVendorSpecificGain() を呼び出すことで取得できます。ベンダーは、1 バイト以内に収まる限り、独自のスケールを使用して測定値を提供できます。

ポーリング ループに応答して、オブザーバビリティ モードから移行する

サービスがトランザクションの準備ができたら、falsesetObserveModeEnabled() に渡すことで、オブザーバビリティ モードを終了できます。NFC スタックは、トランザクションの続行を許可します。

HostApduService コンポーネントは、マニフェストで shouldDefaultToObserveModetrue に設定するか、CardEmulation.setShouldDefaultToObserveModeForService() を呼び出すことで、優先されるお支払いサービスである場合は常にオブザーバモードを有効にするように指定できます。

HostApduService コンポーネントと OffHostApduService コンポーネントは、受信したポーリング ループ フレームに一致するポーリング ループ フィルタを自動的に無効にし、マニフェストの PollingLoopFilter 宣言で autoTransacttrue に設定してトランザクションを続行できるようにすることもできます。

フォアグラウンド サービスの設定

フォアグラウンドのアプリは setPreferredService を呼び出して、特定のアクティビティがフォアグラウンドにあるときに優先するカード エミュレーション サービスを指定できます。このフォアグラウンド アプリの設定は、特定のサービスに対する shouldDefaultToObserveMode の値に対応するデバイスの観察モードの状態をオーバーライドします。この設定は、次のいずれかの方法で設定できます。

画面オフとロック画面の動作

HCE サービスの動作は、デバイスで実行されている Android のバージョンによって異なります。

Android 15 以降

デフォルトのウォレット アプリが、Observe モードをサポートしているデバイスで Observe モードをオンにすると、そのアプリはトランザクションを開始できるタイミングを制御するため、ロック解除と画面オフの動作をオーバーライドします。ウォレット アプリによっては、オブザーバビリティ モードで識別可能なポーリング ループ パターンが検出されなかった場合、トランザクションを続行する前にデバイスのロックを解除することが求められる場合があります。

デベロッパーは、リーダー デバイスと連携して識別可能なポーリング ループ パターンを出力し、アプリからこれらのパターンを処理するように登録することをおすすめします。

Android 12 以降

Android 12(API レベル 31)以降をターゲットとするアプリでは、requireDeviceScreenOnfalse に設定することで、デバイスの画面をオンにすることなく NFC 決済を有効にできます。

Android 10 以降

Android 10(API レベル 29)以降を搭載したデバイスは、セキュア NFC をサポートしています。セキュア NFC がオンの場合、デバイスの画面がオフになっているときは、すべてのカード エミュレータ(ホスト アプリケーションとオフホスト アプリケーション)を使用できません。セキュア NFC がオフの場合、デバイスの画面がオフになっているときは、オフホスト アプリケーションを使用できます。セキュア NFC のサポートを確認するには、isSecureNfcSupported() を使用します。

Android 10 以降を搭載したデバイスでは、android:requireDeviceUnlocktrue に設定する機能は、Android 9 以前を搭載したデバイスと同じですが、セキュア NFC がオフの場合にのみ適用されます。つまり、セキュア NFC がオンになっている場合、android:requireDeviceUnlock の設定に関係なく、HCE サービスはロック画面から機能しません。

Android 9 以前

Android 9(API レベル 28)以前を搭載したデバイスでは、デバイスの画面がオフになると NFC コントローラとアプリケーション プロセッサが完全にオフになります。そのため、HCE サービスは画面がオフのときには機能しません。

Android 9 以前でも、HCE サービスはロック画面から機能できます。ただし、これは HCE サービスの <host-apdu-service> タグの android:requireDeviceUnlock 属性によって制御されます。デフォルトでは、デバイスのロック解除は不要であり、デバイスがロックされていてもサービスが呼び出されます。

HCE サービスの android:requireDeviceUnlock 属性を true に設定した場合、次の場合にデバイスのロック解除を求めるプロンプトが表示されます。

  • ユーザーが NFC リーダーをタップする。
  • NFC リーダーが、そのサービスへと解決される AID を選択します。

ロック解除後、Android によって、トランザクションを完了するためにユーザーにもう一度デバイスをかざすよう求めるダイアログが表示されます。このようにする必要がある理由は、ロック解除のためにユーザーが NFC リーダーからデバイスを離す場合があるためです。

セキュア エレメント カードとの共存

このセクションでは、カード エミュレーションにセキュア エレメントを使用するアプリをデプロイしたデベロッパー向けの内容を記載しています。Android における HCE の実装は、セキュア エレメントの使用を含む他のカード エミュレーションの実装方法と同時に機能するように設計されています。

この共存は、AID ルーティングという原則に基づいています。NFC コントローラは、ルーティング ルールを記した(有限の)リストで構成されるルーティング テーブルを保持します。各ルーティングルールには AID と宛先が含まれます。宛先は、Android アプリの稼働しているホスト CPU か、接続されたセキュア エレメントのいずれかです。

NFC リーダーが SELECT AID を含む APDU を送信すると、NFC コントローラはその APDU を解析して、AID がルーティング テーブル内にある AID と一致するかどうかを確認します。一致する場合、その APDU と後続の APDU はすべて、一致した AID に関連付けられている宛先に送信されます。この送信は、別の SELECT AID APDU が受信されるか NFC リンクが切断されるまで続きます。

図 4 は、このアーキテクチャを示しています。

NFC リーダーがセキュア エレメントと CPU の両方と通信する図
図 4. セキュア エレメントとホストカード エミュレーションの両方で動作する Android

通常、NFC コントローラは APDU のデフォルト ルートも含んでいます。ルーティング テーブルに AID が見つからない場合は、デフォルト ルートが使用されます。この設定はデバイスによって異なる場合がありますが、Android デバイスは、アプリによって登録された AID がホストに正しく転送されるよう保証することが要求されています。

HCE サービスを実装する Android アプリやセキュア エレメントを使用する Android アプリが、ルーティング テーブルの設定について心配する必要はありません。設定は Android 側で自動的に処理されます。Android 側で認識する必要がある情報は、どの AID を HCE サービスで処理でき、どの AID をセキュア エレメントで処理できるかということだけです。ルーティング テーブルは、インストールされているサービスと、ユーザーが優先として構成したサービスに基づいて自動的に構成されます。

次のセクションでは、カード エミュレーションにセキュア エレメントを使用するアプリの AID を宣言する方法について説明します。

セキュア エレメントの AID の登録

カード エミュレーションにセキュア エレメントを使用するアプリは、マニフェストでオフホスト サービスを宣言できます。そのようなサービスの宣言は、HCE サービスの宣言とほぼ同じです。例外は次のとおりです。

  • インテント フィルタで使用するアクションは SERVICE_INTERFACE に設定する必要があります。
  • メタデータ名属性は SERVICE_META_DATA に設定する必要があります。
  • メタデータの XML ファイルでは、<offhost-apdu-service> ルートタグを使用する必要があります。

    <service android:name=".MyOffHostApduService" android:exported="true"
           android:permission="android.permission.BIND_NFC_SERVICE">
      <intent-filter>
          <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/>
      </intent-filter>
      <meta-data android:name="android.nfc.cardemulation.off_host_apdu_service"
                 android:resource="@xml/apduservice"/>
    </service>
    

2 つの AID を登録する対応する apduservice.xml ファイルの例を次に示します。

<offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc">
    <aid-group android:description="@string/subscription" android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</offhost-apdu-service>

android:requireDeviceUnlock 属性はオフホスト サービスには適用されません。これは、ホスト CPU がトランザクションに関与しないので、デバイスがロック状態のときにセキュア エレメントによるトランザクションの実行を防げないためです。

android:apduServiceBanner 属性は、決済アプリのオフホスト サービスで、デフォルトの決済アプリとして選択可能にするために必要です。

オフホスト サービスの起動

実際のトランザクションは Android サービスではなくセキュア エレメントによって実行されるため、Android は「オフホスト」と宣言されたサービスを開始またはバインドすることはありません。サービスの宣言は、単にセキュア エレメント上にある AID の登録をアプリに許可しているだけです。

HCE とセキュリティ

HCE アーキテクチャは、セキュリティの中核部分の 1 つを提供します。サービスは BIND_NFC_SERVICE システム権限によって保護されているため、OS のみがサービスにバインドして通信できます。これにより、受信する APDU は実際に OS が NFC コントローラから受信した APDU であること、および、返信する APDU はすべて OS にのみ送信され、OS から NFC コントローラに APDU が直接転送されることが保証されます。

残りの懸念事項は、アプリから NFC リーダーへと送信されるデータを取得する部分です。HCE の設計ではこの部分が意図的に分離されています。HCE はデータがどこから送られてきたかに関係なく、単にデータを安全に NFC コントローラに転送して NFC リーダーに送るという作業を確実に処理します。

HCE サービスで送信するデータを安全に保管、取得するために、たとえば Android アプリ サンドボックスを利用できます。Android アプリ サンドボックスでは、自身のアプリのデータが他のアプリのデータから分離されます。Android のセキュリティについて詳しくは、セキュリティに関するヒントをご覧ください。

プロトコル パラメータと詳細

このセクションでは、NFC プロトコルの衝突防止フェーズと有効化フェーズで HCE デバイスが使用するプロトコル パラメータに関心のあるデベロッパー向けの内容を記載しています。このセクションを利用して、Android HCE デバイスと互換性のあるリーダー インフラストラクチャを構築できます。

NFC-A(ISO/IEC 14443 Type A)プロトコルの衝突防止と有効化

NFC-A プロトコルの有効化の一環として、複数のフレームが交換されます。

交換の最初の部分で、HCE デバイスが UID を提示します。HCE デバイスはランダムな UID を持つと想定する必要があります。つまり、デバイスをリーダーにかざすたびに、リーダーに提示される UID はランダムに生成された UID となります。このため、NFC リーダーは、認証や識別の方法として HCE デバイスの UID に依存すべきではありません。

その後、NFC リーダーは SEL_REQ コマンドを送信して HCE デバイスを選択できます。HCE デバイスの SEL_RES 応答では、少なくともビット 6(0x20)を設定して、デバイスが ISO-DEP をサポートしていることを示す必要があります。SEL_RES 内の他のビットも設定して、たとえば NFC-DEP(p2p)プロトコルのサポートを示すこともできます。他のビットが設定されている可能性があるため、HCE デバイスと通信するリーダーでは SEL_RES 全体を値 0x20 と比較せずに、ビット 6 のみを明示的に確認する必要があります。

ISO-DEP の有効化

NFC-A プロトコルがアクティブになると、NFC リーダーによって ISO-DEP プロトコルの有効化が開始されます。NFC リーダーは RATS(Request for Answer To Select)コマンドを送信します。RATS の応答である ATS は NFC コントローラによって生成されます。ATS は HCE サービスで設定することはできません。ただし、HCE の実装では ATS 応答に関する NFC フォーラムの要件を満たしている必要があるため、NFC リーダーは、あらゆる HFC デバイスでこうしたパラメータが NFC フォーラムの要件に沿って設定されていると当てにすることができます。

以下のセクションで、HCE デバイス上の NFC コントローラが提供する ATS 応答の個別のバイトについて詳しく説明します。

  • TL: ATS 応答の長さ。20 バイトを超える長さを示すことはできません。
  • T0: すべての HCE デバイスでビット 5、6、7 を設定して、ATS 応答に TA(1)、TB(1)、TC(1)が含まれていることを示す必要があります。ビット 1 ~ 4 は FSCI を示し、最大フレームサイズを符号化します。HCE デバイスでは、FSCI の値は 0h ~ 8h の間に設定する必要があります。
  • T(A)1: リーダーとエミュレータとの間のビットレート、および非対称にできるかどうかを定義します。HCE デバイスに対するビットレートの要件または保証はありません。
  • T(B)1: ビット 1~4 は、開始フレーム保護時間整数値(SFGI)を示します。HCE デバイスでは、SFGI は 8h 以下にする必要があります。ビット 5 ~ 8 はフレーム待ち時間整数値(FWI)を示し、フレーム待ち時間(FWT)を符号化します。HCE デバイスでは、FWI は 8h 以下にする必要があります。
  • T(C)1: ビット 5 は、「高度なプロトコル機能」のサポート状況を示します。HCE デバイスでは「高度なプロトコル機能」をサポートしている場合と、サポートしていない場合とがあります。ビット 2 は、DID のサポート状況を示します。HCE デバイスでは DID をサポートしている場合と、サポートしていない場合とがあります。ビット 1 は、NAD のサポート状況を示します。HCE デバイスでは NAD をサポートしてはならないため、ビット 1 はゼロに設定してください。
  • ヒストリカル バイト: HCE デバイスは、最大 15 バイトのヒストリカル バイトを返すことがあります。HFC サービスと通信する NFC リーダーは、ヒストリカル バイトの内容やその存在について一切想定しないようにする必要があります。

HCE デバイスの多くは、EMVCo を構成する決済ネットワークが「Contactless Communication Protocol」仕様で定めているプロトコルの要件に準拠していると考えられます。具体的には、次のとおりです。

  • T0 の FSCI は 2h~8h の間でなければならない。
  • T(A)1 は 0x80 に設定して、106 kbps のビットレートのみがサポートされていること、リーダーとエミュレータとの間で非対称のビットレートはサポートされていないことを示す必要がある。
  • T(B)1 の FWI は 7h 以下である必要がある。

APDU データの交換

前述のように、HCE の実装では単一の論理チャンネルのみをサポートしています。別の論理チャンネル上でアプリを選択しようとしても、HCE デバイスでは機能しません。