Android 7.0 使用一组功能重构了无线接口层 (RIL),以改进 RIL 功能。需要合作伙伴代码更改来实现这些功能,这些功能是可选的,但建议使用。重构更改向后兼容,因此先前重构功能的实现继续有效。
RIL 重构包括以下改进
- RIL 错误代码。 除了现有的
GENERIC_FAILURE
代码外,还启用特定错误代码。这通过提供有关错误原因的更具体信息来帮助进行错误故障排除。 - RIL 版本控制。 提供更准确且更易于配置的版本信息。
- 使用唤醒锁的 RIL 通信。 提高设备电池性能。
您可以实施上述任何或所有改进。有关更多详细信息,请参阅 https://android.googlesource.com/platform/hardware/ril/+/main/include/telephony/ril.h
中关于 RIL 版本控制的代码注释。
实施增强的 RIL 错误代码
几乎所有 RIL 请求调用都可能返回 GENERIC_FAILURE
错误代码以响应错误。对于 OEM 返回的所有请求响应,这都是一个问题;如果 RIL 调用因不同原因而返回相同的 GENERIC_FAILURE
错误代码,则这可能会使调试错误报告中的问题变得困难。供应商甚至需要花费大量时间才能确定代码的哪个部分可能返回了 GENERIC_FAILURE
代码。
在 Android 7.x 及更高版本中,OEM 可以返回与当前归类为 GENERIC_FAILURE
的每种不同错误相关的不同错误代码值。不想公开其自定义错误代码的 OEM 可以将错误作为一组不同的整数(例如 1 到 x)返回,这些整数映射为 OEM_ERROR_1
到 OEM_ERROR_X
。供应商应确保返回的每个此类屏蔽错误代码都映射到代码中的唯一错误原因。使用特定错误代码可以加快 RIL 调试速度,尤其是在 OEM 返回通用错误时,因为通常需要花费太多时间来确定 GENERIC_FAILURE
错误代码的确切原因(有时甚至不可能找出原因)。
此外,ril.h
为枚举 RIL_LastCallFailCause
和 RIL_DataCallFailCause
添加了更多错误代码,以便供应商代码可以避免返回 CALL_FAIL_ERROR_UNSPECIFIED
和 PDP_FAIL_ERROR_UNSPECIFIED
等通用错误。
验证增强型 RIL 错误代码
在添加新错误代码以替换 GENERIC_FAILURE
代码后,验证 RIL 调用是否返回新错误代码,而不是 GENERIC_FAILURE
。
实施增强型 RIL 版本控制
旧版 Android 版本中的 RIL 版本控制存在问题:版本本身不精确,报告 RIL 版本的机制不明确(导致某些供应商报告的版本不正确),并且用于估算版本的解决方法容易出现不准确的情况。
在 Android 7.x 及更高版本中,ril.h
文档记录了所有 RIL 版本值,描述了相应的 RIL 版本,并列出了该版本的所有更改。当进行与 RIL 版本对应的更改时,供应商必须在代码中更新其版本,并在 RIL_REGISTER
中返回该版本。
验证增强型 RIL 版本控制
验证在 RIL_REGISTER
期间是否返回与您的 RIL 代码对应的 RIL 版本(而不是 ril.h
中定义的 RIL_VERSION
)。
使用唤醒锁实施 RIL 通信
在 RIL 通信中,定时唤醒锁的使用方式不够精确,这会对电池性能产生负面影响。在 Android 7.x 及更高版本中,您可以通过对 RIL 请求进行分类并更新代码来针对不同的请求类型以不同的方式处理唤醒锁,从而提高性能。
对 RIL 请求进行分类
RIL 请求可以是请求响应型或主动上报型。供应商应将请求响应型请求进一步分类为以下类型之一
- 同步。不需要花费大量时间来响应的请求。例如,
RIL_REQUEST_GET_SIM_STATUS
。 - 异步。需要花费大量时间来响应的请求。例如,
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
。
异步请求响应型 RIL 请求可能需要花费大量时间。从供应商代码收到确认后,RIL Java 会释放唤醒锁,这可能会导致应用处理器从空闲状态转为挂起状态。当响应可从供应商代码获得时,RIL Java(应用处理器)会重新获取唤醒锁,处理响应,然后返回到空闲状态。这种从空闲状态到挂起状态再到空闲状态的转换可能会消耗大量电量。
如果响应时间不够长,则在整个响应时间内保持唤醒锁并保持空闲状态可能比通过释放唤醒锁并唤醒以等待响应到达而进入挂起状态更节能。供应商应使用特定于平台的功耗测量来确定时间 T 的阈值,当在整个时间 T 内保持空闲状态所消耗的电量大于在相同时间 T 内从空闲状态移动到挂起状态再到空闲状态所消耗的电量时,即达到阈值。当时间 T 已知时,可以将花费时间超过时间 T 的 RIL 命令分类为异步命令,其余命令分类为同步命令。
RIL 通信场景
以下图表说明了常见的 RIL 通信场景,并提供了用于修改代码以处理 RIL 请求响应型和主动上报型请求的解决方案。
注意: 有关以下图表中使用的函数的实现详细信息,请参阅 ril.cpp
中的 acquireWakeLock()
、decrementWakeLock()
和 clearWakeLock(
) 方法。
场景:RIL 请求和请求响应型异步响应
在此场景中,如果 RIL 请求响应型响应预计需要花费大量时间(即对 RIL_REQUEST_GET_AVAILABLE_NETWORKS
的响应),则唤醒锁将在应用处理器端保持很长时间。调制解调器问题也可能导致长时间等待。
解决方案 1: 调制解调器为 RIL 请求和异步响应保持唤醒锁。
- RIL 请求已发送,调制解调器获取唤醒锁以处理该请求。
- 调制解调器发送确认,导致 Java 端递减唤醒锁计数器,并在计数器值变为 0 时释放唤醒锁。
注意: 请求-确认序列的唤醒锁超时时长将小于当前使用的超时时长,因为应相当快地收到确认。
- 处理请求后,调制解调器向供应商代码发送中断,供应商代码获取唤醒锁并向 ril.cpp 发送响应,而 ril.cpp 又获取唤醒锁并向 Java 端发送响应。
- 当响应到达 Java 端时,会获取唤醒锁,并将响应返回给调用方。
- 在所有模块处理完响应后,会(通过套接字)将确认发送回
ril.cpp
,然后ril.cpp
释放在步骤 3 中获取的唤醒锁。
解决方案 2: 调制解调器不保持唤醒锁,并且响应速度很快(同步 RIL 请求和响应)。对于特定的 RIL 命令,同步与异步行为是硬编码的,并且是按每次调用确定的。
- RIL 请求通过在 Java 端调用
acquireWakeLock()
发送。 - 供应商代码不需要获取唤醒锁,可以处理请求并快速响应。
- 当 Java 端收到响应时,会调用
decrementWakeLock()
,这将递减唤醒锁计数器,并在计数器值变为 0 时释放唤醒锁。
场景:RIL 主动上报型响应
在此场景中,RIL 主动上报型响应在其中具有唤醒锁类型标志,指示是否需要为供应商响应获取唤醒锁。如果设置了该标志,则会设置定时唤醒锁,并通过套接字将响应发送到 Java 端。当计时器到期时,将释放唤醒锁。对于不同的 RIL 主动上报型响应,定时唤醒锁可能过长或过短。
解决方案: 确认从 Java 代码发送到原生端 (ril.cpp
),而不是在原生端保持定时唤醒锁的同时发送主动上报型响应。
验证重新设计的唤醒锁
验证 RIL 调用是否被识别为同步或异步。由于电池功耗可能取决于硬件/平台,因此供应商应进行一些内部测试,以了解对异步调用使用新的唤醒锁语义是否可以节省电池电量。