Hotplug handling

Display capabilities (such as display modes and supported HDR types) can change dynamically on devices that have externally connected displays (with HDMI or DisplayPort), such as Android TV set-top-boxes (STBs) and over-the-top (OTT) devices. This change can happen as a result of an HDMI hotplug signal, such as when the user switches from one display to another or boots the device without a connected display. Android 12 and higher includes changes in the framework to handle hotplugging and dynamic display capabilities.

This page describes the handling of display hotplugs and changes in display capabilities in the Composer HAL implementation. Additionally it discusses how to manage the associated framebuffer and prevent race conditions in these situations.

Update display capabilities

This section describes how the Android framework handles changes in display capabilities initiated by Composer HAL.

Before Android can handle changes in display capabilities properly, the OEM must implement Composer HAL such that it uses onHotplug(display, connection=CONNECTED) to notify the framework of any changes to display capabilities. After that's implemented, Android handles changes to display capabilities as follows:

  1. On detecting a change in display capabilities, the framework receives an onHotplug(display, connection=CONNECTED) notification.
  2. On receiving the notification, the framework drops its display state and recreates it with the new capabilities from the HAL by using the getActiveConfig, getDisplayConfigs, getDisplayAttribute, getColorModes, getHdrCapabilities, and getDisplayCapabilities methods.
  3. After the framework recreates a new display state, it sends the onDisplayChanged callback to the apps that are listening for such events.

The framework reallocates the framebuffers on subsequent onHotplug(display, connection=CONNECTED) events. See Client framebuffer management for more information on how to properly manage framebuffer memory to avoid failures during allocation of new framebuffers.

Handle common connection scenarios

This section covers how to properly handle various connection scenarios in your implementations when the primary display is connected and disconnected.

Having been built for mobile devices, the Android framework doesn't have built-in support for a disconnected primary display. Instead the HAL must replace the primary display with a placeholder display in its interactions with the framework in the case when a primary display is physically disconnected.

The following scenarios can occur in STBs and TV dongles that have externally connected displays that can be disconnected. To implement support for these scenarios, use the information in the table below:

Scenario Handling
No connected display at boot time
  • Send an onHotplug(display, connection=CONNECTED) signal from the Composer HAL to the framework.
  • Replace the physical display state inside the Composer HAL with a placeholder display state.
Primary display is physically connected
Primary display is physically disconnected
  • Send another onHotplug(display, connection=CONNECTED) event from the Composer HAL to the framework.
  • Replace the physical display state inside the Composer HAL with a placeholder display state. The placeholder display must have a single display mode, so that the framework sends the onDisplayChanged callback to apps (because the set of supported modes have changed). This single display mode must match the last active mode of the physical display before disconnection, so that apps don’t receive configuration change events.

Use sequential config IDs to prevent race conditions

Race conditions can arise if the Composer HAL updates the supported display configs concurrently with the framework calling setActiveConfig or setActiveConfigWithConstraints. The solution is to implement Composer HAL to use sequential IDs and prevent this problem.

This section describes how the race conditions might occur, followed by details on how to implement Composer HAL so that it uses sequential IDs to prevent such conditions.

Consider the following sequence of events, when new, sequential IDs are NOT assigned to the new display configs, causing a race condition:

  1. The supported display config IDs are:

    • id=1, 1080x1920 60 Hz
    • id=2, 1080x1920 50 Hz
  2. The framework calls setActiveConfig(display, config=1).

  3. Concurrently, the Composer HAL processes a change of display configs and updates its internal state to a new set of display configs, shown as follows:

    • id=1, 2160x3840 60 Hz
    • id=2, 2160x3840 50 Hz
    • id=3, 1080x1920 60 Hz
    • id=4, 1080x1920 50 Hz
  4. Composer HAL sends an onHotplug event to the framework, to notify that the set of supported modes has changed.

  5. The Composer HAL receives setActiveConfig(display, config=1) (from step 2).

  6. The HAL interprets that the framework has requested a config change to 2160x3840 60 Hz, although in reality 1080x1920 60 Hz was desired.

The process using nonsequential ID assignments ends here with a misinterpretation of the desired config change.

Configure Composer HAL to use sequential IDs

To avoid such race conditions, the OEM must implement the Composer HAL as follows:

  • When the Composer HAL updates the supported display configs, it assigns new, sequential IDs to the new display configs.
  • When the framework calls setActiveConfig or setActiveConfigWithConstraints with an invalid config ID, the Composer HAL ignores the call.

These steps serve to prevent race conditions as shown in the following discussion.

Consider the following sequence of events, when new, sequential IDs are assigned to the new display configs:

  1. The supported display config IDs are:

    • id=1, 1080x1920 60 Hz
    • id=2, 1080x1920 50 Hz
  2. The framework calls setActiveConfig(display, config=1).

  3. When a change of display configs is processed, the next set of config IDs are assigned starting from the next unused integer, shown as follows:

    • id=3, 2160x3840 60 Hz

    • id=4, 2160x3840 50 Hz

    • id=5, 1080x1920 60 Hz

    • id=6, 1080x1920 50 Hz

  4. The Composer HAL sends an onHotplug event to the framework, to notify that the set of supported modes has changed.

  5. The Composer HAL receives setActiveConfig(display, config=1) (from step 2).

  6. The Composer HAL ignores the call as the ID is no longer valid.

  7. The framework receives and processes the onHotplug event from step 4. It calls into the Composer HAL using the functions getDisplayConfigs and getDisplayAttribute. With these functions the framework identifies the new ID (5) for the desired resolution and refresh rate of 1080x1920 and 60 Hz.

  8. The framework sends another setActiveConfig event with an updated ID of 5.

  9. The Composer HAL receives setActiveConfig(display, config=5) from step 5.

  10. The HAL correctly interprets that the framework has requested a config change to 1080x1920 60 Hz.

As shown in the example above, the process using sequential ID assignments ensures that the race condition is prevented and the correct display config change is updated.