显示屏功能(例如显示模式和受支持的 HDR 类型)在具有外部连接显示屏(使用 HDMI 或 DisplayPort)的设备(例如 Android 电视机顶盒 (STB) 和 OTT 设备)上可能会动态变化。当用户从一个显示屏切换到另一个显示屏或在未连接显示屏的情况下启动设备时,可能会因 HDMI 热插拔信号而发生此变化。Android 12 及更高版本包含框架中的更改,以处理热插拔和动态显示屏功能。
本页面介绍了 Composer HAL 实现中显示屏热插拔和显示屏功能更改的处理方式。此外,还讨论了如何管理相关的帧缓冲区,以及如何在这些情况下防止出现竞态条件。
更新显示屏功能
本部分介绍了 Android 框架如何处理由 Composer HAL 发起的显示屏功能更改。
在 Android 能够正确处理显示屏功能更改之前,OEM 必须实现 Composer HAL,使其使用 onHotplug(display, connection=CONNECTED)
以将显示屏功能的任何更改通知框架。在此实现之后,Android 会按如下方式处理显示屏功能更改:
- 检测到显示屏功能更改时,框架会收到
onHotplug(display, connection=CONNECTED)
通知。 - 收到通知后,框架会丢弃其显示状态,并使用来自 HAL 的新功能重新创建它,方法是使用
getActiveConfig
、getDisplayConfigs
、getDisplayAttribute
、getColorModes
、getHdrCapabilities
和getDisplayCapabilities
方法。 - 框架重新创建新的显示状态后,会将
onDisplayChanged
回调发送到正在监听此类事件的应用。
框架会在后续的 onHotplug(display, connection=CONNECTED)
事件中重新分配帧缓冲区。有关如何正确管理帧缓冲区内存以避免在新帧缓冲区分配期间发生故障的更多信息,请参阅客户端帧缓冲区管理。
处理常见的连接场景
本节介绍如何在主显示屏连接和断开连接时,在您的实现中正确处理各种连接场景。
Android 框架专为移动设备而构建,没有内置的断开连接的主显示屏支持。相反,在主显示屏物理断开连接的情况下,HAL 必须在其与框架的交互中用占位符显示屏替换主显示屏。
以下场景可能发生在具有可以断开连接的外部连接显示屏的 STB 和电视盒中。要实现对这些场景的支持,请使用下表中的信息
场景 | 处理 |
---|---|
启动时未连接显示屏 |
|
主显示屏已物理连接 |
|
主显示屏已物理断开连接 |
|
非 HDMI 连接注意事项
Android TV 仅支持以下分辨率
- 720x1280
- 1080x1920
- 2160x3840
- 4320x7680
当 STB 或电视盒尝试通过 CVBS 连接显示不受支持的分辨率(例如 480i)时,会向用户显示错误消息。
如果 STB 或电视盒同时具有 HDMI 和非 HDMI 连接,则 HDMI 连接是主显示屏,而非 HDMI 连接处于非活动状态。因此,如果在非 HDMI 连接仍然连接的情况下 HDMI 连接断开连接,则会向 SurfaceFlinger 发送一个事件,并且非 HDMI 显示屏的功能必须通过 getDisplayAttribute
和其他 iComposerClient
API(例如 getHdrCapabilities
)反映出来。
使用顺序配置 ID 以防止出现竞态条件
如果 Composer HAL 在框架调用 setActiveConfig
或 setActiveConfigWithConstraints
的同时并发更新受支持的显示屏配置,则可能会出现竞态条件。解决方案是实现 Composer HAL 以使用顺序 ID 并防止此问题。
本节介绍竞态条件可能如何发生,然后详细介绍如何实现 Composer HAL,使其使用顺序 ID 以防止出现此类条件。
考虑以下事件序列,当未为新的显示屏配置分配新的顺序 ID 时,会导致竞态条件
受支持的显示屏配置 ID 为
- id=1,1080x1920 60 Hz
- id=2,1080x1920 50 Hz
同时,Composer HAL 处理显示屏配置的更改,并将其内部状态更新为一组新的显示屏配置,如下所示
- id=1,2160x3840 60 Hz
- id=2,2160x3840 50 Hz
- id=3,1080x1920 60 Hz
- id=4,1080x1920 50 Hz
Composer HAL 向框架发送
onHotplug
事件,以通知受支持的模式集已更改。Composer HAL 接收
setActiveConfig(display, config=1)
(来自步骤 2)。HAL 将框架请求的配置更改解释为2160x3840 60 Hz,但实际上需要的是1080x1920 60 Hz。
使用非顺序 ID 分配的过程在此处结束,并对所需的配置更改产生误解。
配置 Composer HAL 以使用顺序 ID
为避免此类竞态条件,OEM 必须按如下方式实现 Composer HAL
- 当 Composer HAL 更新受支持的显示屏配置时,它会为新的显示屏配置分配新的顺序 ID。
- 当框架使用无效的配置 ID 调用
setActiveConfig
或setActiveConfigWithConstraints
时,Composer HAL 会忽略该调用。
这些步骤用于防止竞态条件,如下面的讨论所示。
考虑以下事件序列,当为新的显示屏配置分配新的顺序 ID 时
受支持的显示屏配置 ID 为
- id=1,1080x1920 60 Hz
- id=2,1080x1920 50 Hz
当处理显示屏配置的更改时,下一组配置 ID 从下一个未使用的整数开始分配,如下所示
id=3,2160x3840 60 Hz
id=4,2160x3840 50 Hz
id=5,1080x1920 60 Hz
id=6,1080x1920 50 Hz
Composer HAL 向框架发送
onHotplug
事件,以通知受支持的模式集已更改。Composer HAL 接收
setActiveConfig(display, config=1)
(来自步骤 2)。由于 ID 不再有效,Composer HAL 会忽略该调用。
框架接收并处理来自步骤 4 的
onHotplug
事件。它使用函数getDisplayConfigs
和getDisplayAttribute
调用 Composer HAL。通过这些函数,框架可以识别所需分辨率和刷新率(1080x1920 和 60 Hz)的新 ID (5)。框架发送另一个
setActiveConfig
事件,其中包含更新后的 ID 5。Composer HAL 从步骤 5 接收
setActiveConfig(display, config=5)
。HAL 正确地将框架请求的配置更改解释为 1080x1920 60 Hz。
如上面的示例所示,使用顺序 ID 分配的过程可确保防止竞态条件,并更新正确的显示屏配置更改。