API térmica

Lanzamiento:

Android 11 (nivel de API 30): API térmica

Android 12 (nivel de API 31) - API de NDK

(versión preliminar) Android 15 (DP1): getThermalHeadroomThresholds()

El rendimiento potencial de tu app está limitado por el estado térmico del dispositivo, que puede variar según las características, como el clima, el uso reciente y el diseño térmico del dispositivo. Los dispositivos solo pueden mantener un alto nivel de el rendimiento por un tiempo limitado antes de que se limite térmicamente. Un objetivo clave de la implementación debe ser alcanzar los objetivos de rendimiento sin exceder las limitaciones térmicas. Thermal API hace que sea posible sin la necesidad para realizar optimizaciones específicas en función del dispositivo. Además, cuando se depura el rendimiento saber si el estado térmico de tu dispositivo limita el rendimiento importante.

Por lo general, los motores de juegos tienen parámetros de rendimiento del entorno de ejecución que pueden ajustar la carga de trabajo que el motor coloca en el dispositivo. Por ejemplo, estos parámetros pueden establecer la cantidad de subprocesos de trabajo, afinidad de subprocesos de trabajo para núcleos grandes y pequeños, opciones de fidelidad de GPU y resoluciones de búfer de fotogramas. En Unity Engine, el juego los desarrolladores pueden ajustar la carga de trabajo cambiando la calidad Configuración con el complemento de Adaptive Performance. En Unreal Engine, usa la Configuración de escalabilidad para ajustar niveles de calidad de forma dinámica.

Cuando un dispositivo se acerca a un estado térmico inseguro, el juego puede evitar ser limitado al disminuir la carga de trabajo a través de estos parámetros. Para evitar la limitación, se debe supervisar el estado térmico del dispositivo y ajustar la carga de trabajo del motor de juego de forma proactiva. Una vez que el dispositivo se sobrecalienta, la carga de trabajo debe caer por debajo del nivel de rendimiento sostenible para disipar el calor. Después del el margen térmico se reduce a niveles más seguros, el juego puede aumentar los parámetros de configuración de calidad nuevamente, pero asegúrate de encontrar un nivel de calidad sostenible para un tiempo de juego óptimo.

Puedes supervisar el estado térmico del dispositivo mediante un sondeo del método getThermalHeadroom. Este método predice cuánto tiempo el dispositivo puede mantener el valor el nivel de rendimiento sin sobrecalentarlo. Si el tiempo es menor que la cantidad necesaria para ejecutar la carga de trabajo, el juego debe disminuirla a un nivel sostenible. Por ejemplo, el juego puede cambiar a núcleos más pequeños, reducir la velocidad de fotogramas o reducir la fidelidad.

Integración previa de la API de ADPF Thermal
Figura 1: Margen térmico sin supervisar activamente getThermalHeadroom
Posintegración de la API de ADPF Thermal
Figura 2: Margen térmico con supervisión activa de “getThermalHeadroom”

Adquirir un administrador térmico

Para usar la API de Thermal, primero debes adquirir el administrador de Thermal

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

Prevé el margen térmico x segundos de anticipación para tener un mayor control

Puedes pedirle al sistema que prevea la temperatura x segundos con la carga de trabajo actual. Esto te da un control más preciso y más tiempo para y reacciona reduciendo la carga de trabajo para evitar que se active la limitación térmica.

El resultado varía de 0.0f (sin limitación, THERMAL_STATUS_NONE) a 1.0f (alta limitación, THERMAL_STATUS_SEVERE). Si tienes diferentes niveles de calidad de gráficos en tus juegos, puedes seguir nuestra Lineamientos del margen térmico.

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, usa el estado térmico para una aclaración

Cada modelo de dispositivo puede diseñarse de manera diferente. Es posible que algunos dispositivos puedan hacer lo siguiente: distribuir mejor el calor y, por lo tanto, poder soportar un margen térmico mayor antes de que se limiten. Si quieres leer una agrupación simplificada de rangos de margen térmico, puedes comprobar el estado térmico para comprender el valor de margen térmico en el dispositivo actual.

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);

Recibe notificaciones cuando cambie el estado térmico

También puedes evitar sondear el thermalHeadroom hasta que llegue el thermalStatus un nivel determinado (por ejemplo: THERMAL_STATUS_LIGHT). Para ello, puedes registrar una devolución de llamada para que el sistema te notifique cuando cambió su estado.

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);

Recuerda quitar el objeto de escucha cuando hayas terminado.

C++

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

Java

powerManager.removeThermalStatusListener(listener);

Limpieza

Una vez que hayas terminado, deberás limpiar el thermal_manager que adquiriste. Si utilizas Java, la referencia de PowerManager puede ser automáticamente basura recopilados para ti. Pero si usas la API de Java a través de JNI y tienes retuviste una referencia, recuerda limpiarla.

C++

AThermal_releaseManager(thermal_manager);

Para obtener una guía completa sobre cómo implementar la API de Thermal en un juego nativo de C++ usando la API de C++ (API de NDK) y la API de Java (a través de JNI), consulta el artículo Integra Sección API térmica del codelab de adaptabilidad sección.

Lineamientos del margen térmico

Puedes supervisar el estado térmico del dispositivo mediante un sondeo del método getThermalHeadroom. Este método predice cuánto tiempo el dispositivo puede mantener el valor el nivel de rendimiento antes de alcanzar el THERMAL_STATUS_SEVERE. Por ejemplo, si getThermalHeadroom(30) devuelve 0.8, indica que en 30 segundos, se espera que el margen alcance 0.8, cuando hay una distancia de 0.2 de una limitación grave o 1.0. Si el tiempo es menor que la cantidad necesaria para que ejecutan la carga de trabajo, el juego debería disminuirla a una a nivel de organización. Por ejemplo, el juego puede reducir la velocidad de fotogramas, la fidelidad reducir el trabajo de conectividad de red.

Estados térmicos y significado

Limitaciones de la API de Thermal

Existen algunas limitaciones o requisitos adicionales conocidos de la API de Thermal debido a implementaciones de la API térmica en dispositivos más antiguos. Las limitaciones y cómo para solucionarlos son los siguientes:

  • No llames a la API de GetThermalHeadroom() con demasiada frecuencia. Si lo haces, puede dar como resultado que la API muestre NaN. Debes llamarlo una vez por segundo como máximo.
  • Si el valor inicial de GetThermalHeadroom() es NaN, la API no es disponible en el dispositivo
  • Si GetThermalHeadroom() muestra un valor alto (p. ej.: 0.85 o más) GetCurrentThermalStatus() aún muestra THERMAL_STATUS_NONE; el estado es probablemente no se hayan actualizado. Usa una heurística para estimar el límite térmico correcto o solo usa getThermalHeadroom() sin getCurrentThermalStatus().

Ejemplo de heurística:

  1. Comprueba que la API de Thermal sea compatible. isAPISupported() verifica el valor de la primera llamada a getThermalHeadroom para asegurarte de que no sea 0 o NaN, y omite el uso de la API si el primer valor es 0 o NaN.
  2. Si getCurrentThermalStatus() muestra un valor distinto de THERMAL_STATUS_NONE, el dispositivo se está limitando térmicamente.
  3. Si getCurrentThermalStatus() sigue mostrando THERMAL_STATUS_NONE, no significa necesariamente que no se limite térmicamente al dispositivo. Podría significa que el dispositivo no admite getCurrentThermalStatus(). Comprueba el valor que se muestra de getThermalHeadroom() para asegurarte de que la condición sea el dispositivo.
  4. Si getThermalHeadroom() devuelve un valor > 1.0, el estado podría en realidad sea de THERMAL_STATUS_SEVERE o más, reduce la carga de trabajo de inmediato y mantener una carga de trabajo más baja hasta que getThermalHeadroom() devuelva un valor más bajo
  5. Si getThermalHeadroom() devuelve un valor de 0.95, el estado podría en realidad sea de THERMAL_STATUS_MODERATE o más, reduce la carga de trabajo de inmediato y presta atención para evitar que las lecturas sean mayores
  6. Si getThermalHeadroom() devuelve un valor de 0.85, el estado podría en realidad sea THERMAL_STATUS_LIGHT, ten cuidado y reduce la carga de trabajo si es posible

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:

Ejemplo heurístico de ADPF
Figura 3: Ejemplo de una heurística para determinar la compatibilidad de la API de Thermal en dispositivos más antiguos