实施 IMS

Android 9 引入了一个名为 ImsService 的 SystemApi 接口,以帮助您实施 IP 多媒体子系统 (IMS)。ImsService API 是 Android 平台与供应商或运营商提供的 IMS 实现之间的明确定义的接口。

ImsService overview

图 1. ImsService 概览

通过使用 ImsService 接口,IMS 实现者可以向平台提供重要的信令信息,例如 IMS 注册信息、IMS 集成短信以及 MmTel 功能集成(以提供语音和视频通话)。ImsService API 也是 Android System API,这意味着它可以直接针对 Android SDK 而不是针对源代码进行构建。在设备上预安装的 IMS 应用也可以配置为可从 Play 商店更新。

示例和源代码

Android 在 AOSP 上提供了一个应用,该应用实现了 ImsService API 的部分功能,用于测试和开发目的。您可以在 /testapps/ImsTestService 中找到该应用。

您可以在 ImsService 和 API 中的其他类中找到 ImsService API 的文档。

实现

ImsService API 是一个高级 API,允许您通过多种方式实现 IMS,具体取决于可用的硬件。例如,实现方式会因 IMS 实现是完全在应用处理器上,还是部分或完全卸载到调制解调器而异。Android 没有为卸载到基带处理器提供公共 HAL,因此任何卸载都必须使用您的 HAL 扩展到调制解调器来实现。

与旧版 IMS 实现的兼容性

虽然 Android 9 包含了 ImsService API,但使用旧版 IMS 实现的设备无法支持此 API。对于这些设备,旧的 AIDL 接口和包装类已移至 android.telephony.ims.compat 命名空间。升级到 Android 9 时,旧设备必须执行以下操作才能继续支持旧版 API。

  • 更改 ImsService 实现的命名空间,使其从 android.telephony.ims.compat 命名空间 API 扩展。
  • 修改 AndroidManifest.xml 中的 ImsService 服务定义,以使用 android.telephony.ims.compat.ImsService intent-filter action,而不是 android.telephony.ims.ImsService action。

框架随后将使用 Android 9 中提供的兼容性层绑定到 ImsService,以便与旧版 ImsService 实现协同工作。

ImsService 在框架中的注册

ImsService API 作为一项服务来实现,Android 框架会绑定到该服务,以便与 IMS 实现进行通信。要注册实现 ImsService 的应用到框架,需要执行三个步骤。首先,ImsService 实现必须使用应用的 AndroidManifest.xml 向平台注册自身;其次,它必须定义实现支持哪些 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.xml 中的 service 定义定义了以下属性,这些属性对于正确操作是必需的

  • directBootAware="true":允许 telephony 在用户解锁设备之前发现和运行该服务。在用户解锁设备之前,该服务无法访问设备加密存储空间。有关详细信息,请参阅支持直接启动模式基于文件的加密
  • persistent="true":允许此服务持久运行,并且不会被系统终止以回收内存。此属性仅在应用构建为系统应用时才有效。
  • permission="android.permission.BIND_IMS_SERVICE":确保只有被授予 BIND_IMS_SERVICE 权限的进程才能绑定到该应用。这可以防止恶意应用绑定到该服务,因为只有系统应用才能被框架授予该权限。

该服务还必须指定包含 action android.telephony.ims.ImsServiceintent-filter 元素。这允许框架找到 ImsService

IMS 功能规范

在 AndroidManifest.xml 中将 ImsService 定义为 Android 服务之后,ImsService 必须定义其支持的 IMS 功能。Android 目前支持 MmTel 和 RCS 功能,但只有 MmTel 集成到框架中。虽然框架中没有集成 RCS API,但将其声明为 ImsService 的一项功能仍然有优势。

以下是在 android.telephony.ims.ImsFeature 中定义的有效功能,ImsService 可以提供这些功能,以及 IMS 应用可能希望实现其中一项或所有功能的解释和示例。在定义每个功能之后,此页面概述了 ImsService 如何声明其为每个 SIM 卡槽定义的功能集。

FEATURE_MMTEL

ImsService 实现了 IMS MMTEL 功能,其中包含对除紧急呼叫的 IMS PDN 紧急连接之外的所有 IMS 媒体(IR.92 和 IR.94 规范)的支持。任何希望支持 MMTEL 功能的 ImsService 实现都应扩展 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 基类仍然很有用。当框架检测到软件包应提供 RCS 时,它会自动绑定到 ImsService 并调用 ImsService#createRcsFeature。如果与 RCS 服务关联的 SIM 卡被移除,框架会自动调用 RcsFeature#onFeatureRemoved,然后清理与 RCS 功能关联的 ImsService。此功能可以删除 RCS 功能原本必须提供的一些自定义检测或绑定逻辑。

注册受支持的功能

电话框架首先绑定到 ImsService,以使用 ImsService#querySupportedImsFeatures API 查询其支持的功能。在框架计算出 ImsService 将支持哪些功能后,它将为 ImsService 将负责的每个功能调用 ImsService#create[...]Feature。如果 IMS 应用支持的功能发生更改,您可以使用 ImsService#onUpdateSupportedImsFeatures 向框架发出信号,以重新计算受支持的功能。有关 ImsService 的初始化和绑定的更多信息,请参见下图。

ImsService initializing and binding

图 2. ImsService 初始化和绑定

框架检测和验证 ImsService 实现

在 AndroidManifest.xml 中正确定义 ImsService 后,必须配置平台以在适当的时候(安全地)绑定到 ImsService。框架绑定到两种类型的 ImsService

  1. 运营商“覆盖”ImsService:这些 ImsService 预加载到设备上,但附加到一个或多个蜂窝运营商,并且仅在插入匹配的 SIM 卡时才会被绑定。这是使用
  2. 设备“默认”ImsService:这是 OEM 加载到设备上的默认 ImsService,应设计为在运营商 ImsService 不可用时在所有情况下提供 IMS 服务,并且在设备未插入 SIM 卡或插入的 SIM 卡未安装运营商 ImsService 的情况下非常有用。这在设备叠加层中使用以下配置定义

Android 不支持具有第三方可下载 ImsService 实现的应用,因此此处定义的任何 ImsService 实现都必须是系统应用,并且必须驻留在 /system/priv-app/ 或 /product/priv-app/ 文件夹中,才能授予相应的权限(即电话、麦克风、位置信息、相机和联系人权限)。通过验证 IMS 实现的软件包名称是否与上面定义的 CarrierConfig 或设备叠加层值匹配,只有受信任的预安装应用才会被绑定。

自定义

实现 ImsService 的应用仅在设备上配置为运营商“覆盖”ImsService 或设备“默认”ImsService 配置以用于 MMTEL 或 RCS 功能时才会被绑定。ImsService 还允许使用 ImsService#onUpdateSupportedImsFeatures 方法,通过更新动态启用或禁用其支持的 IMS 功能(MMTEL 和 RCS)。这会触发框架重新计算哪些 ImsService 已绑定以及它们支持哪些功能。如果 IMS 应用更新框架时未支持任何功能,则 ImsService 将保持未绑定状态,直到手机重启或插入与 IMS 应用匹配的新 SIM 卡。

多个 ImsService 的绑定优先级

框架无法支持绑定到设备上预加载的所有可能的 ImsService,并且每个 SIM 卡槽最多绑定到两个 ImsService(每个功能一个 ImsService),按每个功能的以下顺序绑定

  1. 当插入 SIM 卡时,由 CarrierConfig 值 config_ims_[mmtel/rcs]_package_override_string 定义的 ImsService 软件包名称。
  2. 设备叠加层值中为 config_ims_[mmtel/rcs]_package 定义的 ImsService 软件包名称,包括未插入 SIM 卡的情况。此 ImsService 必须支持紧急 MmTel 功能。

您必须将 ImsService 的软件包名称定义在每个将使用该软件包的运营商的 CarrierConfig 中,或者如果您的 ImsService 将是默认的,则定义在设备叠加层中,如上所述。

让我们为每个功能分解一下。对于具有单张 SIM 卡的设备(单 SIM 卡或多 SIM 卡),有两种可能的 IMS 功能:MMTel 和 RCS。框架将尝试按上述定义的顺序为每个功能进行绑定,如果 Carrier Configuration 覆盖中定义的 ImsService 不提供该功能,框架将回退到您的默认 ImsService。因此,例如,下表描述了在具有以下功能的三款安装了实现 ImsService 的 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 类来获取 ImsMmTelManagerImsRcsManager 或 IMS 特定的 ProvisioningManager 类的实例。然后,应用可以侦听 IMS 特定的服务和配置状态,例如

  • 已启用且可用的 MMTEL 或 RCS 功能
  • IMS 注册状态更改时的更新
  • IMS 功能的配置状态
  • 用户已启用的 IMS 功能

使用 ImsStateCallback

虽然 ImsService 是一种持久绑定的服务,但当新的 SIM 卡或嵌入式订阅变为活动状态或运营商配置更改时,绑定的服务可能会更改。由于 ImsService 不是电话进程的一部分,因此如果 ImsService 无形崩溃或由于订阅或配置更改而解除绑定,则应用在尝试访问 IMS API 时可能会遇到意外异常。

在运行 Android 13 或更高版本的设备上,要监视关联订阅的 ImsService 实例是否可用或不可用,应用可以使用 ImsStateCallback 类。在获取 ImsMmTelManagerImsRcsManager 的实例时,我们建议应用首先使用 ImsMmTelManager#registerImsStateCallbackImsRcsManager#registerImsStateCallback 注册 IMS 状态回调。要继续接收有关特定订阅的回调更新(当 ImsService 再次可用时),应用必须取消注册或放弃通过 ImsMmTelManagerImsRcsManagerProvisioningManager 注册的现有回调;并注册新的回调。

如果某个订阅不支持 IMS,则框架会使用原因 REASON_NO_IMS_SERVICE_CONFIGURED 调用 ImsStateCallback#onUnavailable。这意味着 ImsService 和 IMS 相关 API 不适用于该订阅。

在不太可能发生的电话进程崩溃事件中,应用会收到 ImsStateCallback#onError,并且不再收到有关已注册 ImsStateCallback 实例的更新。要从此情况中恢复,请通过调用 ImsMmTelManager#registerImsStateCallbackImsRcsManager#registerImsStateCallback 为关联的订阅重新注册 ImsStateCallback 实例。