Composer HAL 中的热插拔处理

显示功能(例如显示模式和支持的 HDR 类型)可以在具有外部连接显示器(通过 HDMI 或 DisplayPort)的设备上动态更改,例如 Android 电视机顶盒 (STB) 和机顶盒 (OTT)设备。这种变化可能是 HDMI 热插拔信号的结果,例如当用户从一个显示器切换到另一个显示器或在没有连接显示器的情况下启动设备时。从 Android 12 开始,在框架中进行了更改以处理热插拔和动态显示功能。

本页介绍如何处理 Composer HAL 实现中的显示热插拔和显示功能更改。此外,它还讨论了如何管理相关的帧缓冲区并防止在这些情况下出现竞争条件。

更新显示功能

本节介绍 Android 框架如何处理由 Composer HAL 发起的显示功能更改。

在 Android 可以正确处理显示功能的更改之前,OEM 必须实现 Composer HAL,以便它使用onHotplug(display, connection=CONNECTED)来通知框架显示功能的任何更改。一旦实现,Android 会按如下方式处理对显示功能的更改:

  1. 在检测到显示功能的变化时,框架会收到onHotplug(display, connection=CONNECTED)通知。
  2. 收到通知后,框架会删除其显示状态,并通过使用getActiveConfiggetDisplayConfigsgetDisplayAttributegetColorModesgetHdrCapabilitiesgetDisplayCapabilities方法从 HAL 重新创建它。
  3. 一旦框架重新创建了新的显示状态,它就会将onDisplayChanged回调发送到正在侦听此类事件的应用程序。

框架在后续的onHotplug(display, connection=CONNECTED)事件上重新分配帧缓冲区。有关如何处理此问题的更多信息,请参阅管理帧缓冲内存

处理常见的连接场景

本节介绍如何在主显示器连接和断开连接时正确处理实施中的各种连接场景。

Android 框架是为移动设备构建的,它没有内置对断开连接的主显示器的支持。相反,在主显示器物理断开的情况下,HAL 在与框架的交互中必须用占位符显示器替换主显示器。

在具有可断开连接的外接显示器的机顶盒和电视棒中可能会出现以下情况。为了实现对这些方案的支持,请使用下表中的信息:

设想处理
开机时没有连接显示器
  • 从 Composer HAL 向框架发送onHotplug(display, connection=CONNECTED)信号。
  • 将 Composer HAL 内的物理显示状态替换为占位符显示状态。

    注意:我们建议占位符显示具有单一支持的模式,分辨率为 1080x1920,刷新率为 60hz,因为大多数应用程序都支持此显示模式。

主显示器物理连接
主显示器物理断开
  • 从 Composer HAL 向框架发送另一个onHotplug(display, connection=CONNECTED)事件。
  • 将 Composer HAL 内的物理显示状态替换为占位符显示状态。占位符显示必须具有单一显示模式,以便框架将onDisplayChanged回调发送到应用程序(因为支持的模式集已更改)。这种单一显示模式必须与断开前物理显示的最后一个活动模式匹配,以便应用程序不会收到配置更改事件

管理帧缓冲内存

当已连接的显示器收到后续的onHotplug(display, connection=CONNECTED)通知事件时,框架会重新分配与此显示器关联的帧缓冲区。设备实现必须预见到这种行为并正确管理帧缓冲内存。在您的实施中使用以下准则:

  • 在发送后续onHotplug(display, connection=CONNECTED)通知事件之前,请确保释放帧缓冲区的句柄,以便系统可以在重新分配它们之前正确地释放它们。如果释放不成功,则重新分配可能由于内存不足而失败。

  • 我们建议为独立于图形内存缓冲区的其余部分的帧缓冲区分配一个专用内存池。

这很重要,因为在帧缓冲区的重新分配和重新分配之间,第三方进程可以尝试分配图形内存。如果帧缓冲区使用相同的显存池并且显存已满,则第三方进程可以占用帧缓冲区先前分配的显存,从而为帧缓冲区重新分配留下足够的内存(或可能将内存空间碎片化) .

使用顺序配置 ID 来防止竞争条件

如果 Composer HAL 与调用setActiveConfigsetActiveConfigWithConstraints的框架同时更新支持的显示配置,则可能会出现竞争条件。解决方案是实现 Composer HAL 以使用顺序 ID 并防止此问题。

本节描述了竞争条件可能如何发生,随后详细介绍了如何实现 Composer HAL 以便它使用顺序 ID 来防止这种情况。

考虑以下事件序列,当新的顺序 ID 未分配给新的显示配置时,会导致竞争条件:

  1. 支持的显示配置 ID 为:

    • id=1 , 1080x1920 60hz
    • id=2 , 1080x1920 50hz
  2. 框架调用setActiveConfig(display, config=1)

  3. 同时,Composer HAL 处理显示配置的更改并将其内部状态更新为一组新的显示配置,如下所示:

    • id=1 , 2160x3840 60hz
    • id=2 , 2160x3840 50hz
    • id=3 , 1080x1920 60hz
    • id=4 , 1080x1920 50hz
  4. Composer HAL 向框架发送一个onHotplug事件,以通知支持的模式集已更改。

  5. Composer HAL 接收setActiveConfig(display, config=1) (来自步骤 2)。

  6. HAL 解释说框架已请求将配置更改为2160x3840 60hz ,尽管实际上需要1080x1920 60hz

使用非顺序 ID 分配的过程以对所需配置更改的误解结束。

将 Composer HAL 配置为使用顺序 ID

为避免此类竞争条件,OEM 必须按如下方式实施 Composer HAL:

  • 当 Composer HAL 更新支持的显示配置时,它会为新的显示配置分配新的连续 ID。
  • 当框架使用无效的配置 ID 调用setActiveConfigsetActiveConfigWithConstraints时,Composer HAL 会忽略该调用。

这些步骤用于防止竞争条件,如下面的讨论所示。

考虑以下事件序列,当新的顺序 ID 分配给新的显示配置时:

  1. 支持的显示配置 ID 为:

    • id=1 , 1080x1920 60hz
    • id=2 , 1080x1920 50hz
  2. 框架调用setActiveConfig(display, config=1)

  3. 当处理显示配置的更改时,将从下一个未使用的整数开始分配下一组配置 ID,如下所示:

    • id=3 , 2160x3840 60hz

    • id=4 , 2160x3840 50hz

    • id=5 , 1080x1920 60hz

    • id=6 , 1080x1920 50hz

  4. Composer HAL 向框架发送onHotplug事件,以通知支持的模式集已更改。

  5. Composer HAL 接收setActiveConfig(display, config=1) (来自步骤 2)。

  6. Composer HAL 忽略调用,因为 ID 不再有效。

  7. 框架接收并处理来自步骤 4 的onHotplug事件。它使用函数getDisplayConfigsgetDisplayAttribute调用 Composer HAL。借助这些功能,框架可以识别新 ID (5),以获得 1080x1920 和 60Hz 的所需分辨率和刷新率。

  8. 框架发送另一个setActiveConfig事件,更新后的 ID 为 5。

  9. Composer HAL 从第 5 步接收setActiveConfig(display, config=5)

  10. HAL 正确解释框架已请求将配置更改为 1080x1920 60hz。

如上例所示,使用顺序 ID 分配的过程可确保防止竞争条件并更新正确的显示配置更改。