Manuseio hot plug no Composer HAL

Os recursos de exibição (como modos de exibição e tipos de HDR compatíveis) podem ser alterados dinamicamente em dispositivos que possuem monitores conectados externamente (via HDMI ou DisplayPort), como decodificadores de TV Android (STB) e over-the-top (OTT) dispositivos. Essa alteração pode ocorrer como resultado de um sinal HDMI hot plug, como quando o usuário alterna de um monitor para outro ou inicializa o dispositivo sem um monitor conectado. A partir do Android 12, foram feitas alterações na estrutura para lidar com hot plugging e recursos de exibição dinâmica.

Esta página aborda como lidar com hot plugs de exibição e alterações nos recursos de exibição na implementação do Composer HAL. Além disso, discute como gerenciar o framebuffer associado e evitar condições de corrida nessas situações.

Atualizando recursos de exibição

Esta seção descreve como a estrutura do Android lida com as alterações nos recursos de exibição iniciadas pelo Composer HAL.

Antes que o Android possa lidar com as alterações nos recursos de exibição corretamente, o OEM deve implementar o Composer HAL de forma que ele use um onHotplug(display, connection=CONNECTED) para notificar a estrutura sobre quaisquer alterações nos recursos de exibição. Depois que isso for implementado, o Android lidará com as alterações nos recursos de exibição da seguinte maneira:

  1. Ao detectar uma alteração nos recursos de exibição, a estrutura recebe uma onHotplug(display, connection=CONNECTED) .
  2. Ao receber a notificação, a estrutura descarta seu estado de exibição e o recria com os novos recursos do HAL usando os getActiveConfig , getDisplayConfigs , getDisplayAttribute , getColorModes , getHdrCapabilities e getDisplayCapabilities .
  3. Depois que a estrutura recria um novo estado de exibição, ela envia o retorno de chamada onDisplayChanged para os aplicativos que estão ouvindo esses eventos.

A estrutura realoca os framebuffers em onHotplug(display, connection=CONNECTED) subsequentes. Consulte Gerenciando a memória do framebuffer para obter mais informações sobre como lidar com isso.

Lidando com cenários de conexão comuns

Esta seção aborda como lidar adequadamente com vários cenários de conexão em suas implementações quando a tela principal está conectada e desconectada.

Tendo sido criado para dispositivos móveis, a estrutura do Android não possui suporte integrado para uma tela principal desconectada. Em vez disso, o HAL deve substituir a exibição principal por uma exibição de espaço reservado em suas interações com a estrutura no caso de uma exibição principal estar fisicamente desconectada.

Os cenários a seguir podem ocorrer em decodificadores e dongles de TV que possuem telas conectadas externamente que podem ser desconectadas. Para implementar o suporte para esses cenários, use as informações da tabela abaixo:

Cenário Manipulação
Nenhum monitor conectado no momento da inicialização
  • Envie um onHotplug(display, connection=CONNECTED) do Composer HAL para o framework.
  • Substitua o estado de exibição físico dentro do Composer HAL por um estado de exibição de espaço reservado.

    Observação: recomendamos que a exibição de espaço reservado tenha um único modo compatível com resolução de 1080 x 1920 e taxa de atualização de 60 hz, pois esse modo de exibição é compatível com a maioria dos aplicativos.

O monitor principal está fisicamente conectado
A tela principal está fisicamente desconectada
  • Envie outro onHotplug(display, connection=CONNECTED) do Composer HAL para o framework.
  • Substitua o estado de exibição físico dentro do Composer HAL por um estado de exibição de espaço reservado. A exibição do espaço reservado deve ter um único modo de exibição, para que a estrutura envie o retorno de chamada onDisplayChanged aos aplicativos (já que o conjunto de modos com suporte foi alterado). Esse modo de exibição única deve corresponder ao último modo ativo da exibição física antes da desconexão, para que os aplicativos não recebam eventos de alteração de configuração .

Gerenciando a memória do framebuffer

Quando um monitor já conectado recebe um evento de notificação onHotplug(display, connection=CONNECTED) subsequente, a estrutura realoca os framebuffers associados a esse monitor. As implementações de dispositivos devem antecipar esse comportamento e gerenciar adequadamente a memória do framebuffer. Use as seguintes diretrizes em sua implementação:

  • Antes de enviar eventos de notificação onHotplug(display, connection=CONNECTED) subsequentes, certifique-se de liberar handles para os framebuffers para que o sistema possa desalocá-los adequadamente, antes de realocá-los. Se a desalocação não for bem-sucedida, a realocação poderá falhar devido à falta de memória.

  • Recomendamos alocar um pool de memória dedicado para os framebuffers separados do restante do buffer de memória gráfica.

Isso é importante porque entre a desalocação e a realocação dos framebuffers, um processo de terceiros pode tentar alocar a memória gráfica. Se o mesmo pool de memória gráfica for usado pelo framebuffer e se a memória gráfica estiver cheia, o processo de terceiros pode ocupar a memória gráfica previamente alocada por um framebuffer, deixando memória insuficiente para a realocação do framebuffer (ou possivelmente fragmentando o espaço de memória) .

Usando IDs de configuração sequenciais para evitar condições de corrida

As condições de corrida podem surgir se o Composer HAL atualizar as configurações de exibição suportadas simultaneamente com a estrutura que chama setActiveConfig ou setActiveConfigWithConstraints . A solução é implementar o Composer HAL para usar IDs sequenciais e evitar esse problema.

Esta seção descreve como as condições de corrida podem ocorrer, seguida de detalhes sobre como implementar o Composer HAL para que ele use IDs sequenciais para evitar tais condições.

Considere a seguinte sequência de eventos, quando novos IDs sequenciais NÃO são atribuídos às novas configurações de exibição, causando uma condição de corrida:

  1. Os IDs de configuração de exibição compatíveis são:

    • id=1 , 1080x1920 60hz
    • id=2 , 1080x1920 50hz
  2. A estrutura chama setActiveConfig(display, config=1) .

  3. Concomitantemente, o Composer HAL processa uma mudança nas configurações de exibição e atualiza seu estado interno para um novo conjunto de configurações de exibição, mostrado a seguir:

    • id=1 , 2160x3840 60hz
    • id=2 , 2160x3840 50hz
    • id=3 , 1080x1920 60hz
    • id=4 , 1080x1920 50hz
  4. O Composer HAL envia um evento onHotplug para o framework, para notificar que o conjunto de modos suportados foi alterado.

  5. O Composer HAL recebe setActiveConfig(display, config=1) (da etapa 2).

  6. O HAL interpreta que o framework solicitou uma alteração de configuração para 2160x3840 60hz , embora na realidade fosse desejado 1080x1920 60hz .

O processo usando atribuições de ID não sequenciais termina aqui com uma má interpretação da alteração de configuração desejada.

Configurando o Composer HAL para usar IDs sequenciais

Para evitar tais condições de corrida, o OEM deve implementar o Composer HAL da seguinte forma:

  • Quando o Composer HAL atualiza as configurações de exibição suportadas, ele atribui novos IDs sequenciais às novas configurações de exibição.
  • Quando a estrutura chama setActiveConfig ou setActiveConfigWithConstraints com um ID de configuração inválido, o Composer HAL ignora a chamada.

Essas etapas servem para evitar condições de corrida, conforme mostrado na discussão a seguir.

Considere a seguinte sequência de eventos, quando novos IDs sequenciais são atribuídos às novas configurações de exibição:

  1. Os IDs de configuração de exibição compatíveis são:

    • id=1 , 1080x1920 60hz
    • id=2 , 1080x1920 50hz
  2. A estrutura chama setActiveConfig(display, config=1) .

  3. Quando uma alteração das configurações de exibição é processada, o próximo conjunto de IDs de configuração é atribuído a partir do próximo inteiro não utilizado, mostrado a seguir:

    • id=3 , 2160x3840 60hz

    • id=4 , 2160x3840 50hz

    • id=5 , 1080x1920 60hz

    • id=6 , 1080x1920 50hz

  4. O Composer HAL envia um evento onHotplug para o framework, para notificar que o conjunto de modos suportados foi alterado.

  5. O Composer HAL recebe setActiveConfig(display, config=1) (da etapa 2).

  6. O Composer HAL ignora a chamada, pois o ID não é mais válido.

  7. O framework recebe e processa o evento onHotplug da etapa 4. Ele chama o Composer HAL usando as funções getDisplayConfigs e getDisplayAttribute . Com essas funções o framework identifica o novo ID (5) para a resolução desejada e taxa de atualização de 1080x1920 e 60Hz.

  8. A estrutura envia outro evento setActiveConfig com um ID atualizado de 5.

  9. O Composer HAL recebe setActiveConfig(display, config=5) da etapa 5.

  10. O HAL interpreta corretamente que a estrutura solicitou uma alteração de configuração para 1080x1920 60hz.

Conforme mostrado no exemplo acima, o processo usando atribuições de ID sequenciais garante que a condição de corrida seja evitada e que a alteração de configuração de exibição correta seja atualizada.