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:
- On detecting a change in display capabilities, the framework receives an
onHotplug(display, connection=CONNECTED)
notification. - 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
, andgetDisplayCapabilities
methods. - 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 |
|
Primary display is physically connected |
|
Primary display is physically disconnected |
|
Non-HDMI connection considerations
Android TV only supports the following resolutions:
- 720x1280
- 1080x1920
- 2160x3840
- 4320x7680
When an STB or TV dongle attempts to display an unsupported resolution, such as 480i over a CVBS connection, an error message is presented to the user.
If the STB or TV dongle has both HDMI and non-HDMI connections, the HDMI
connection is the primary display and the non-HDMI connection is
inactive. As a result, if the HDMI connection is disconnected while the non-HDMI
connection is still connected, an event is sent to SurfaceFlinger and the
capabilities of the non-HDMI display must be reflected through getDisplayAttribute
and other iComposerClient
APIs (such as getHdrCapabilities
).
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:
The supported display config IDs are:
- id=1, 1080x1920 60 Hz
- id=2, 1080x1920 50 Hz
The framework calls
setActiveConfig(display, config=1)
.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
Composer HAL sends an
onHotplug
event to the framework, to notify that the set of supported modes has changed.The Composer HAL receives
setActiveConfig(display, config=1)
(from step 2).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
orsetActiveConfigWithConstraints
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:
The supported display config IDs are:
- id=1, 1080x1920 60 Hz
- id=2, 1080x1920 50 Hz
The framework calls
setActiveConfig(display, config=1)
.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
The Composer HAL sends an
onHotplug
event to the framework, to notify that the set of supported modes has changed.The Composer HAL receives
setActiveConfig(display, config=1)
(from step 2).The Composer HAL ignores the call as the ID is no longer valid.
The framework receives and processes the
onHotplug
event from step 4. It calls into the Composer HAL using the functionsgetDisplayConfigs
andgetDisplayAttribute
. With these functions the framework identifies the new ID (5) for the desired resolution and refresh rate of 1080x1920 and 60 Hz.The framework sends another
setActiveConfig
event with an updated ID of 5.The Composer HAL receives
setActiveConfig(display, config=5)
from step 5.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.