IMS を実装する

Android 9 では、IP マルチメディア サブシステム(IMS)の実装に役立つ、ImsService という新しい SystemApi インターフェースが導入されています。ImsService API は、Android プラットフォームとベンダーまたは携帯通信会社が提供する IMS 実装の間に介在する、明確に定義されたインターフェースです。

ImsService の概要

図 1:ImsService の概要

IMS の実装で ImsService インターフェースを使用すると、IMS 登録情報、SMS over IMS 統合、音声通話とビデオ通話を実現する MmTel 機能統合など、重要なシグナリング情報をプラットフォームに提供できます。ImsService API は Android システム API でもあります。つまり、ソースではなく Android SDK に対して直接ビルドできるということです。デバイスにプリインストールされている IMS アプリは、Google Play ストアで更新できるように設定することもできます。

例とソース

Android では、テストと開発を目的として ImsService API の一部を実装するアプリを AOSP で提供しています。このアプリは /testapps/ImsTestService にあります。

ImsService API のドキュメントは、ImsService と API の他のクラスで確認できます。

実装

ImsService API は、利用可能なハードウェアに応じてさまざまな方法で IMS を実装できるハイレベル API です。たとえば、IMS が完全にアプリ プロセッサ上に実装されるか、あるいはモデムに部分的または完全にオフロードされるかどうかによって実装は変わります。Android では、ベースバンド プロセッサにオフロードするための公開 HAL が提供されていないため、オフロードするにはモデムの HAL 拡張機能を使用する必要があります。

以前の IMS 実装との互換性

Android 9 には ImsService API が含まれていますが、IMS の以前の実装を使用しているデバイスはこの API に対応できません。これらのデバイスでは、以前の AIDL インターフェースとラッパークラスが android.telephony.ims.compat 名前空間に移動されています。Android 9 にアップグレードする場合は、デバイスで次の操作を行って以前の API のサポートを継続する必要があります。

  • android.telephony.ims.compat 名前空間 API から拡張するように ImsService 実装の名前空間を変更します。
  • android.telephony.ims.ImsService アクションではなく android.telephony.ims.compat.ImsService インテントフィルタ アクションを使用するように、AndroidManifest.xml の ImsService サービス定義を変更します。

これにより、フレームワークは Android 9 で提供されている互換性レイヤを使用して ImsService にバインドし、以前の ImsService 実装を利用するようになります。

ImsService のフレームワークへの登録

ImsService API は、IMS 実装と通信するために Android フレームワークがバインドするサービスとして実装されます。ImsService を実装するアプリをフレームワークに登録するには、3 つのステップが必要です。まず、アプリの AndroidManifest.xml を使用して ImsService 実装をプラットフォームに登録します。次に実装でサポートされる IMS 機能(MmTel または RCS)を定義し、最後は携帯通信会社の構成またはデバイス オーバーレイで、信頼できる IMS 実装であることを検証する必要があります。

サービス定義

IMS アプリは、次の形式で service エントリをマニフェストに追加して、フレームワークに ImsService を登録します。

<service
    android:name="com.egcorp.ims.EgImsService"
    android:directBootAware="true"
    Android:persistent="true"
    ...
    android:permission="android.permission.BIND_IMS_SERVICE" >
    ...
    <intent-filter>
        <action android:name="android.telephony.ims.ImsService" />
    </intent-filter>
</service>

AndroidManifest.xmlservice 定義で、正しい動作に必要な次の属性を定義します。

  • directBootAware="true": ユーザーがデバイスをロック解除する前に、telephony がサービスを検出して実行できるようにします。ユーザーがデバイスをロック解除するまで、サービスはデバイス暗号化ストレージにアクセスできません。詳細については、ダイレクト ブートモードのサポートファイルベースの暗号化をご覧ください。
  • persistent="true": このサービスを永続的に実行し、メモリの再利用を目的にシステムによって停止されないようにします。この属性は、アプリがシステムアプリとしてビルドされている場合にのみ有効です。
  • permission="android.permission.BIND_IMS_SERVICE": BIND_IMS_SERVICE 権限を付与されたプロセスのみがアプリにバインドできるようにします。フレームワークからこの権限を付与できるのはシステムアプリのみであるため、不正なアプリがサービスにバインドされるのを防止できます。

サービスでは、android.telephony.ims.ImsService アクションを含む intent-filter 要素も指定する必要があります。これにより、フレームワークが ImsService を検出できるようになります。

IMS 機能の仕様

AndroidManifest.xml で ImsService を Android サービスとして定義した後は、ImsService でサポートされる IMS 機能を定義する必要があります。現在、Android は MmTel 機能と RCS 機能をサポートしていますが、フレームワークに統合されているのは MmTel のみです。RCS API はフレームワークに統合されていませんが、ImsService の機能として宣言することにはメリットがあります。

以下で、android.telephony.ims.ImsFeature に定義されている ImsService の有効な機能について説明し、IMS アプリがこれらの機能の 1 つまたはすべてを実装する必要がある理由を示します。各機能の定義の後に、SIM スロットごとに定義された一連の機能を ImsService が宣言する方法を説明します。

FEATURE_MMTEL

ImsService は、緊急通報用の IMS PDN への緊急接続を除くすべての IMS メディア(IR.92 仕様と IR.94 仕様)に対応した IMS MMTEL 機能を実装しています。ImsService の実装で MMTEL 機能をサポートするには、android.telephony.ims.MmTelFeature 基本クラスを拡張して、ImsService#createMmTelFeature でカスタム MmTelFeature 実装を返す必要があります。

FEATURE_EMERGENCY_MMTEL

この機能を宣言すると、緊急サービス用の IMS PDN に緊急接続できることのみをプラットフォームに通知します。ImsService でこの機能が宣言されていない場合、プラットフォームは緊急サービスにデフォルトで常に回線交換フォールバックを使用します。この機能を定義するには、FEATURE_MMTEL 機能を定義する必要があります。

FEATURE_RCS

ImsService API で IMS RCS 機能は実装されませんが、android.telephony.ims.RcsFeature 基本クラスは役に立ちます。フレームワークは自動的に ImsService にバインドし、パッケージが RCS を提供することを検出すると ImsService#createRcsFeature を呼び出します。RCS サービスに関連付けられた SIM カードを取り外すと、フレームワークによって自動的に RcsFeature#onFeatureRemoved が呼び出された後、RCS 機能に関連付けられた ImsService がクリーンアップされます。この機能によってカスタム検出またはバインディング ロジックの一部が削除され、RCS 機能で提供する必要がなくなります。

サポートされる機能の登録

電話通信フレームワークは最初に ImsService にバインドし、ImsService#querySupportedImsFeatures API を使用してサポート対象機能を照会します。フレームワークは ImsService でサポートされる機能を特定した後、ImsService が関与する機能ごとに ImsService#create[...]Feature を呼び出します。IMS アプリでサポートされる機能が変わった場合は、ImsService#onUpdateSupportedImsFeatures を使用して、サポートされる機能の再特定をフレームワークに通知できます。ImsService の初期化とバインディングの詳細を以下の図に示します。

ImsService の初期化とバインディング

図 2: ImsService の初期化とバインディング

フレームワークによる ImsService 実装の検出と検証

AndroidManifest.xml で ImsService を正しく定義したら、プラットフォームが必要に応じて ImsService に安全にバインドするように構成する必要があります。フレームワークがバインドする ImsService は次の 2 種類です。

  1. 携帯通信会社の「優先」ImsService: これらの ImsService はデバイスにプリロードされていますが、1 つ以上の携帯通信会社に関連付けられており、一致する SIM カードが挿入された場合にのみバインドされます。これは以下のコードを使用して構成されます。
  2. デバイスの「デフォルト」ImsService: OEM によってデバイスに読み込まれるデフォルトの ImsService で、携帯通信会社の ImsService を利用できないすべての状況で IMS サービスを提供するように設計します。デバイスに SIM カードが挿入されていない場合や、挿入された SIM カードに携帯通信会社の ImsService がインストールされていない場合に便利です。これは、以下の構成を使用してデバイス オーバーレイで定義されます。

Android は、ダウンロード可能なサードパーティの ImsService 実装を使用するアプリをサポートしていないため、ここで定義する ImsService 実装はシステムアプリであり、適切な権限(電話、マイク、位置情報、カメラ、連絡先の権限)を付与するために、/system/priv-app/ フォルダまたは /product/priv-app/ フォルダに配置されている必要があります。上で定義した CarrierConfig またはデバイス オーバーレイの値と IMS 実装のパッケージ名が一致するかどうかが確認され、信頼できるプリインストールされているアプリのみがバインドされます。

カスタマイズ

ImsService を実装するアプリは、携帯通信会社の「オーバーライド」ImsService として構成されているデバイス、または MMTEL 機能あるいは RCS 機能用のデバイスの「デフォルト」の ImsService 構成にのみバインドされます。ImsService では、ImsService#onUpdateSupportedImsFeatures メソッドを使用したアップデートによって、サポートしている IMS 機能(MMTEL と RCS)を動的に有効または無効にすることもできます。この場合は、バインドされている ImsService とサポートされている機能がフレームワークによって再度特定されます。IMS アプリがサポートする機能なしでフレームワークをアップデートした場合、スマートフォンが再起動されるか、IMS アプリに一致する新しい SIM カードが挿入されるまで、ImsService はバインドを解除します。

複数の ImsService のバインディング優先度

フレームワークは、デバイスにプリロードされているすべての ImsService へのバインドをサポートできるわけではなく、SIM スロットあたり最大 2 つ(機能ごとに 1 つ)の ImsService に、機能ごとに次の順序でバインドできます。

  1. CarrierConfig 値 config_ims_[mmtel/rcs]_package_override_string で定義された ImsService パッケージ名(SIM カードが挿入されている場合)。
  2. config_ims_[mmtel/rcs]_package のデバイス オーバーレイ値で定義された ImsService パッケージ名(SIM カードが挿入されていない場合も含む)。この ImsService は Emergency MmTel 機能をサポートしている必要があります。

ImsService のパッケージ名は、パッケージを使用する携帯通信会社ごとに CarrierConfig で定義するか、デバイス オーバーレイで(前述したデフォルト ImsService の場合)定義する必要があります。

各機能について詳しく説明します。シングル SIM カードが読み込まれた 1 つのデバイス(シングル SIM またはマルチ SIM)につき、MMTel と RCS の 2 つの IMS 機能をサポートできます。フレームワークは、上で定義した順序で機能ごとにバインドしようとしますが、携帯通信会社の構成オーバーライドに定義された ImsService でその機能を使用できない場合、デフォルトの ImsService にフォールバックします。例として、ImsService を実装する 3 つの IMS アプリが次の機能を持つシステムにインストールされた場合に、フレームワークが使用する IMS 機能を下の表に示します。

  • 携帯通信会社 A の ImsService は RCS をサポートしています
  • 携帯通信会社 B の ImsService は RCS と MMTel をサポートしています
  • OEM の ImsService は RCS と MMTel をサポートしています
挿入されている SIM カード RCS 機能 MMTel 機能
携帯通信会社 A 携帯通信会社 A OEM
携帯通信会社 B 携帯通信会社 B 携帯通信会社 B
SIM なし OEM OEM

検証

IMS 仕様は非常に大きく、特殊な検証装置が使用されるため、IMS 実装自体を検証するためのツールは含まれていません。テストで検証できるのは、電話通信フレームワークが ImsService API に適切に応答するかどうかのみです。

IMS アプリの開発

Android テレフォニー スタックとやり取りする IMS アプリを開発する際は、アプリが特定の携帯通信会社サブスクリプションに付随する ImsService インスタンスの状態をリッスンまたは変更できるように指定することをおすすめします。

MMTEL 機能と RCS 機能に関する ImsService の状態をリッスンまたは変更するには、ImsManager クラスを使用して、ImsMmTelManager クラス、ImsRcsManager クラス、または IMS 固有の ProvisioningManager クラスのインスタンスを取得します。これにより、アプリは IMS 固有のサービスとプロビジョニングの状態について次のような情報をリッスンできます。

  • 有効化されて利用可能になっている MMTEL 機能または RCS 機能
  • IMS 登録の状態が変更されたときの更新
  • IMS 機能のプロビジョニング ステータス
  • ユーザーが有効化した IMS 機能

ImsStateCallback の使用

ImsService は永続的にバインドされるサービスですが、新しい SIM カードまたは埋め込みサブスクリプションがアクティブになったときや、携帯通信会社の構成が変更されたときに、バインドされるサービスが変更されることがあります。ImsService はテレフォニー プロセスの一部ではないため、サブスクリプションまたは構成の変更により ImsService が目に見えない形でクラッシュした場合またはバインドが解除された場合、IMS API にアクセスしようとするとアプリで予期しない例外が発生する可能性があります。

Android 13 以降を搭載したデバイスでは、関連付けられたサブスクリプションの ImsService インスタンスが利用可能かどうかをモニタリングするために、アプリで ImsStateCallback クラスを使用できます。ImsMmTelManager または ImsRcsManager のインスタンスを取得する際は、ImsMmTelManager#registerImsStateCallback または ImsRcsManager#registerImsStateCallback を使用して、あらかじめアプリで IMS 状態コールバックを登録することをおすすめします。ImsService が再び利用可能になったときに特定のサブスクリプションのコールバック更新をアプリが引き続き受信するには、ImsMmTelManagerImsRcsManagerProvisioningManager のいずれかを使用して、登録されている既存のコールバックを登録解除または破棄し、新しいコールバックを登録する必要があります。

IMS をサポートしていないサブスクリプションが存在する場合、フレームワークは理由 REASON_NO_IMS_SERVICE_CONFIGUREDImsStateCallback#onUnavailable を呼び出します。これは、そのサブスクリプションでは ImsService と IMS 関連の API を使用できないことを意味します。

万が一テレフォニー プロセスがクラッシュした場合、アプリは ImsStateCallback#onError を受信し、登録されている ImsStateCallback インスタンスの更新を受信しなくなります。この状態から回復するには、ImsMmTelManager#registerImsStateCallback または ImsRcsManager#registerImsStateCallback を呼び出して、関連付けられたサブスクリプションの ImsStateCallback インスタンスを再登録します。