Display capabilities (such as display modes and supported HDR types) can change dynamically on devices which have externally connected displays (via HDMI or DisplayPort), such as Android TV set-top-boxes (STB) and over-the-top (OTT) devices. This change can happen as a result of an HDMI hot plug signal, such as when the user switches from one display to another or boots the device without a connected display. From Android 12 on, changes have been made in the framework to handle hot plugging and dynamic display capabilities.
This page covers how to handle display hot plugs 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.
Updating 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 an onHotplug(display, connection=CONNECTED)
to notify the framework of any changes to display capabilities. Once that is
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
re-creates it with the new capabilities from the HAL by using the
getActiveConfig
,getDisplayConfigs
,getDisplayAttribute
,getColorModes
,getHdrCapabilities
andgetDisplayCapabilities
methods. - Once the framework recreates a new display state, it sends the
onDisplayChanged
callback to the apps which are listening for such events.
The framework reallocates the framebuffers on subsequent onHotplug(display, connection=CONNECTED)
events. See Managing framebuffer memory for more
information on how to handle this.
Handling 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 set-top boxes and TV dongles which have externally connected displays that can be disconnected. In order 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 |
|
Managing framebuffer memory
When an already connected display receives a subsequent onHotplug(display, connection=CONNECTED)
notification event, the framework reallocates the framebuffers associated with
this display. Device implementations must anticipate this behaviour and properly
manage the framebuffer memory. Use the following guidelines in your
implementation:
Before sending subsequent
onHotplug(display, connection=CONNECTED)
notification events, make sure to release handles to the framebuffers so that the system can properly deallocate them, before reallocating them. If the deallocation doesn’t succeed, the reallocation may fail due to lack of memory.We recommend allocating a dedicated memory pool for the framebuffers that is separate from the rest of the graphic memory buffer.
This is important because between deallocation and reallocation of the framebuffers, a third party process can attempt to allocate the graphics memory. If the same graphics memory pool is used by the framebuffer and if the graphics memory is full, the third party process can occupy the graphics memory previously allocated by a framebuffer, thus leaving insufficient memory for the framebuffer reallocation (or possibly fragmenting the memory space).
Using 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 60hz
- id=2, 1080x1920 50hz
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 60hz
- id=2, 2160x3840 50hz
- id=3, 1080x1920 60hz
- id=4, 1080x1920 50hz
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 60hz, although in reality 1080x1920 60hz was desired.
The process using non-sequential ID assignments ends here with a misinterpretation of the desired config change.
Configuring 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 60hz
- id=2, 1080x1920 50hz
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 60hz
id=4, 2160x3840 50hz
id=5, 1080x1920 60hz
id=6, 1080x1920 50hz
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 60Hz.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 60hz.
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.