API Thermal

Lançamento:

Android 11 (API de nível 30): API Thermal

Android 12 (API de nível 31): API NDK

(Prévia) Android 15 (DP1): getThermalHeadroomThresholds()

A performance em potencial do app é limitada pelo estado térmico do dispositivo, que pode variar de acordo com características como clima, uso recente e o design térmico do aparelho. Os dispositivos só podem manter um alto nível de desempenho por um período limitado antes de serem limitados térmica. Um objetivo importante da implementação precisa ser atingir as metas de performance sem exceder as limitações térmicas. A API Thermal torna isso possível sem a necessidade de otimizações específicas do dispositivo. Além disso, ao depurar problemas de desempenho, é importante saber se o estado térmico do dispositivo está limitando o desempenho. Além disso, ao depurar problemas de desempenho, é importante saber se o estado térmico do dispositivo está limitando o desempenho.

Os mecanismos de jogo geralmente têm parâmetros de performance relacionados ao tempo de execução que podem ajustar o tanto de recursos do dispositivo usados pelo mecanismo. Por exemplo, esses parâmetros podem definir o número de linhas de execução de worker, afinidade entre linha de execução e worker para núcleos grandes e pequenos, opções de fidelidade de GPU e resoluções de framebuffer. No Unity Engine, os desenvolvedores de jogos podem ajustar a carga de trabalho mudando as Quality Settings usando o plug-in Adaptive Performance. No Unreal Engine, use as Configurações de escalonamento para ajustar os níveis de qualidade dinamicamente.

Quando um dispositivo se aproxima de um estado térmico não seguro, o jogo pode evitar a limitação, reduzindo a carga de trabalho por esses parâmetros. Para evitar a limitação, monitore o estado térmico do dispositivo e ajuste de forma proativa a carga de trabalho do mecanismo de jogo. Depois que o dispositivo superaquece, a carga de trabalho precisa ficar abaixo do nível de performance sustentável para dissipar o calor. Depois que a margem térmica diminui para níveis mais seguros, o jogo pode aumentar as configurações de qualidade novamente, mas é necessário encontrar um nível de qualidade sustentável para ter uma experiência ideal.

Para monitorar o estado térmico do dispositivo, pesquise o método getThermalHeadroom. Esse método prevê por quanto tempo o dispositivo pode manter o nível de desempenho atual sem superaquecer. Se o tempo for menor que a quantidade necessária para executar a carga de trabalho, o jogo vai precisar diminuir essa carga a um nível sustentável. Por exemplo, o jogo pode mudar para núcleos menores, reduzir o frame rate ou diminuir a fidelidade.

Pré-integração da API Thermal ADPF
Figura 1. Margem térmica sem monitorar ativamente o getThermalHeadroom
Pós-integração da API Thermal ADPF
Figura 2. Margem térmica com monitoramento ativo de "getThermalHeadroom"

Adquirir o gerenciador térmico

Para usar a API Thermal, primeiro é necessário adquirir o Gerenciador térmico

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);

Preveja a margem térmica x segundos à frente para ter mais controle

É possível pedir ao sistema para prever a temperatura x segundos à frente com a carga de trabalho atual. Isso oferece um controle mais refinado e mais tempo para reagir, reduzindo a carga de trabalho para evitar que a limitação térmica seja ativada.

O resultado varia de 0,0f (sem limitação, THERMAL_STATUS_NONE) a 1,0f (limitação pesada, THERMAL_STATUS_SEVERE). Se você tiver níveis de qualidade gráfica diferentes nos seus jogos, siga nossas Diretrizes de margem térmica.

C++

float thermal_headroom = AThermal_getThermalHeadroom(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);

Como alternativa, use o status térmico para esclarecimento

Cada modelo de dispositivo pode ser projetado de maneira diferente. Alguns dispositivos podem distribuir melhor o aquecimento e, portanto, suportar uma margem térmica maior antes de serem limitados. Se você quiser ler um agrupamento simplificado de intervalos de margem térmica, verifique o status térmico para entender o valor da margem térmica no dispositivo atual.

C++

AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);

Java

int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);

Receber notificações quando o status térmico mudar

Também é possível evitar pesquisar o thermalHeadroom até que thermalStatus atinja um determinado nível (por exemplo: THERMAL_STATUS_LIGHT). Para fazer isso, você pode registrar um callback para permitir que o sistema notifique você sempre que o status mudar.

.

C++

int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether you have previously registered callback that
  // hasn’t been unregistered
}

Java

// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = new
  PowerManager.OnThermalStatusChangedListener() {
    @Override
    public void onThermalStatusChanged(int status) {
        Log.d("ADPF", "ThermalStatus changed: " + status);
        // check the status and flip the flag to start/stop pooling when
        // applicable
    }
};
powerManager.addThermalStatusListener(listener);

Lembre-se de remover o listener quando terminar

C++

int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether the callback has been registered previously
}

Java

powerManager.removeThermalStatusListener(listener);

Limpeza

Depois de fazer isso, limpe o Thermal_manager que você adquiriu. Se você estiver usando Java, a referência do PowerManager poderá ser coletada automaticamente como lixo. No entanto, se você estiver usando a API Java por meio do JNI e tiver uma referência retida, limpe a referência.

C++

AThermal_releaseManager(thermal_manager);

Para conferir um guia completo sobre como implementar a API Thermal em um jogo C++ nativo usando a API C++ (API NDK) e a API Java (pelo JNI), consulte a seção Integrar a API Thermal na seção Codelab de adaptabilidade.

Diretrizes de margem térmica

Para monitorar o estado térmico do dispositivo, pesquise o método getThermalHeadroom. Esse método prevê por quanto tempo o dispositivo pode manter o nível de performance atual antes de atingir THERMAL_STATUS_SEVERE. Por exemplo, se getThermalHeadroom(30) retornar 0,8, isso indica que, em 30 segundos, a margem precisa alcançar 0,8, onde há 0,2 distância da limitação intensa, ou 1,0. Se o tempo for menor que a quantidade necessária para executar a carga de trabalho, o jogo precisará diminuir a carga de trabalho a um nível sustentável. Por exemplo, o jogo pode reduzir o frame rate, diminuir a fidelidade ou reduzir o trabalho de conectividade de rede.

Status térmicos e significado

Limitações do dispositivo da API Thermal

Há algumas limitações conhecidas ou requisitos extras da API Thermal, devido a implementações dela em dispositivos mais antigos. As limitações e como resolvê-las são as seguintes:

  • Não chame a API GetThermalHeadroom() com muita frequência. Isso fará com que a API retorne NaN. Você deve chamá-lo no máximo uma vez por segundo.
  • Se o valor inicial de GetThermalHeadroom() for NaN, a API não está disponível no dispositivo.
  • Se GetThermalHeadroom() retornar um valor alto (por exemplo: 0,85 ou mais) e GetCurrentThermalStatus() ainda retornar THERMAL_STATUS_NONE, o status provavelmente não será atualizado. Use heurísticas para estimar o status correto da limitação térmica ou use getThermalHeadroom() sem getCurrentThermalStatus().

Exemplo de heurística:

  1. Verifique se há suporte para a API Thermal. isAPISupported() verifica o valor da primeira chamada para getThermalHeadroom para garantir que não seja 0 ou NaN e ignora o uso da API se o primeiro valor for 0 ou NaN.
  2. Se getCurrentThermalStatus() retornar um valor diferente de THERMAL_STATUS_NONE, o dispositivo está sendo limitado conforme a temperatura.
  3. Se getCurrentThermalStatus() continuar retornando THERMAL_STATUS_NONE, isso não significa necessariamente que o dispositivo não está sendo limitado térmico. Isso pode significar que getCurrentThermalStatus() não é compatível com o dispositivo. Confira o valor de retorno de getThermalHeadroom() para garantir a condição do dispositivo.
  4. Se getThermalHeadroom() retornar um valor maior que 1,0, o status poderá ser THERMAL_STATUS_SEVERE ou maior, reduzir a carga de trabalho imediatamente e manter uma carga de trabalho menor até que getThermalHeadroom() retorne um valor menor
  5. Se getThermalHeadroom() retornar um valor de 0, 95, o status poderá ser THERMAL_STATUS_MODERATE ou maior.Reduza a carga de trabalho imediatamente e fique atento para evitar maior leitura
  6. Se getThermalHeadroom() retornar um valor de 0,85, o status poderá ser THERMAL_STATUS_LIGHT.Mantenha a atenção e reduza a carga de trabalho, se possível

Pseudocódigo:

  bool isAPISupported() {
    float first_value_of_thermal_headroom = getThermalHeadroom();
    if ( first_value_of_thermal_headroom == 0 ||
      first_value_of_thermal_headroom == NaN ) {
        // Checked the thermal Headroom API's initial return value
        // it is NaN or 0,so, return false (not supported)
        return false;
    }
    return true;
  }
  
  if (!isAPISupported()) {
    // Checked the thermal Headroom API's initial return value, it is NaN or 0
    // Don’t use the API
  } else {
      // Use thermalStatus API to check if it returns valid values.
      if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {
          // The device IS being thermally throttled
      } else {
      // The device is not being thermally throttled currently. However, it
      // could also be an indicator that the ThermalStatus API may not be
      // supported in the device.
      // Currently this API uses predefined threshold values for thermal status
      // mapping. In the future  you may be able to query this directly.
      float thermal_headroom = getThermalHeadroom();
      if ( thermal_headroom > 1.0) {
            // The device COULD be severely throttled.
      } else  if ( thermal_headroom > 0.95) {
            // The device COULD be moderately throttled.
      } else if ( thermal_headroom > 0.85) {
            // The device COULD be experiencing light throttling.
      }
    }
  }

Diagrama:

Exemplo heurístico do ADPF
Figura 3. Exemplo de Heuristic para determinar o suporte à API Thermal em dispositivos mais antigos.