Android 9 引入了一个名为 ImsService 的新 SystemApi 接口,可帮助您实现 IP 多媒体子系统 (IMS)。ImsService API 是在 Android 平台与供应商或运营商提供的 IMS 实现之间明确定义的接口。
图 1. ImsService 概览
通过使用 ImsService 接口,IMS 实现者可以向平台提供重要的信号信息(例如 IMS 注册信息、基于 IMS 集成的短信以及 MmTel 功能集成),以提供语音通话和视频通话功能。ImsService API 也是一种 Android System API,这意味着您可以直接针对 Android SDK(而不是来源)构建这种 API。预安装在设备上的 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 过滤器操作,而不是android.telephony.ims.ImsService
操作。
随后,框架将使用 Android 9 中提供的兼容性层绑定到 ImsService,以支持旧版 ImsService
实现。
向框架注册 ImsService
ImsService API 是作为服务实现的,Android 框架会绑定到该服务,以便与 IMS 实现进行通信。如需向框架注册实现了 ImsService 的应用,您必须执行以下 3 个步骤:首先,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
权限的进程才能绑定到相应的应用。这样可以防止恶意应用绑定到该服务,因为框架只会向系统应用授予这项权限。
此外,该服务还必须指定具有 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 应用希望实现所有这些功能或其中某个功能。在对各个功能进行定义后,本页还概述了 ImsService
如何声明它为每个 SIM 卡插槽定义的功能集。
FEATURE_MMTEL
ImsService
可实现 IMS MMTEL 功能,该功能包含对所有 IMS 媒体(IR.92 和 IR.94 规范)的支持(紧急连接到 IMS PDN 以进行紧急呼叫的情况除外)。任何希望支持 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 将负责的各项功能调用 ImsService#create[...]Feature
。如果 IMS 应用支持的功能发生更改,您可以使用 ImsService#onUpdateSupportedImsFeatures
向框架发出信号,以重新计算支持的功能。如需详细了解 ImsService 的初始化和绑定,请参见下图。
图 2:ImsService 初始化和绑定
ImsService 实现的框架检测和验证
在 AndroidManifest.xml 中对 ImsService 进行正确定义后,必须将平台配置为适时(安全地)绑定到 ImsService。框架可绑定到以下两种 ImsService:
- 运营商“替换”ImsService:这类 ImsService 会预先加载到设备上,但与一个或多个手机运营商相关联,并且只有在插入匹配的 SIM 卡时才会绑定。它使用以下项进行配置:
config_ims_mmtel_package_override_string
适用于实现 MMTEL 功能的 ImsService 的 CarrierConfig 键。config_ims_rcs_package_override_string
适用于实现 RCS 功能的 ImsService。
- 设备“默认”ImsService:这是由原始设备制造商 (OEM) 加载到设备上的默认 ImsService。当运营商 ImsService 不可用时,它应该能够在任何情况下提供 IMS 服务。在设备没有插入 SIM 卡或插入的 SIM 卡没有安装运营商 ImsService 的情况下,这种 ImsService 非常有用。它使用以下配置在设备叠加层中定义:
config_ims_mmtel_package
:用于实现 MMTEL 功能config_ims_rcs_package
:用于实现 RCS 功能
Android 不支持采用第三方可下载 ImsService 实现的应用,因此在此处定义的任何 ImsService 实现必须是系统应用,并且必须位于 /system/priv-app/ 或 /product/中 priv-app/ 文件夹中,以授予相应的权限(即电话、麦克风、位置信息、相机和通讯录权限)。通过验证 IMS 实现的软件包名称是否与上文定义的 CarrierConfig 或设备叠加层值匹配,可以仅绑定受信任的预安装应用。
自定义
实现 ImsService 的应用只能绑定到以下设备:此设备上已将该应用配置为运营商“替换”ImsService 或设备“默认”ImsService 配置以实现 MMTEL 或 RCS 功能。ImsService 还允许通过更新(使用 ImsService#onUpdateSupportedImsFeatures
方法)以动态的形式启用或停用它支持的 IMS 功能(MMTEL 和 RCS)。这样会触发框架重新计算要绑定哪些 ImsService 以及它们支持哪些功能。如果 IMS 应用在没有任何受支持的功能的情况下更新框架,则在手机重新启动或插入与 IMS 应用匹配的新 SIM 卡之前,ImsService 将处于未绑定状态。
多个 ImsService 的绑定优先级
框架不支持绑定到预加载到设备上的所有可能的 ImsService,它将按以下顺序按功能绑定到 ImsService(每个 SIM 卡插槽最多可绑定两个 ImsService,每个功能一个 ImsService):
- 由 CarrierConfig 的
config_ims_[mmtel/rcs]_package_override_string
值定义的 ImsService 软件包名称(在插入了 SIM 卡的情况下)。 - 在设备叠加层的
config_ims_[mmtel/rcs]_package
值中定义的 ImsService 软件包名称(包括未插入 SIM 卡的情况)。此 ImsService 必须支持 Emergency MmTel 功能。
您必须在 CarrierConfig 中为每个将使用 ImsService 软件包的运营商定义您 ImsService 的软件包名称;如果您的 ImsService 是默认类型,应在设备叠加层中定义(如上所述)。
下面我们针对每种功能进行详细介绍。对于已加载单个 SIM 卡的设备(单 SIM 卡或多 SIM 卡),可以使用两种 CMS 功能:MMTel 和 RCS。 框架将尝试按照上文中所述的顺序为每种功能进行绑定;如果相应功能不适用于运营商配置替换中定义的 ImsService,则框架将回退到您的默认 ImsService。例如,下表说明了框架将使用哪种 IMS 功能(假设系统上安装了三个 IMS 应用,它们实现的 ImsService 具有以下功能):
- 运营商 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 再次可用时继续接收特定订阅的回调更新,应用需要取消注册或舍弃通过 ImsMmTelManager
、ImsRcsManager
或 ProvisioningManager
注册的现有回调,并注册新的回调。
如果存在不支持 IMS 的订阅,则框架会以 REASON_NO_IMS_SERVICE_CONFIGURED
为原因调用 ImsStateCallback#onUnavailable
。这意味着 ImsService 以及 IMS 相关的 API 不适用于订阅。
在极少数情况下,电话进程会发生崩溃,应用会收到 ImsStateCallback#onError
,并且不会再收到已注册的 ImsStateCallback
实例的更新。如需从此状况中恢复,请调用 ImsMmTelManager#registerImsStateCallback
或 ImsRcsManager#registerImsStateCallback
,重新注册关联订阅的 ImsStateCallback
实例。