Lanzamiento:
Android 11 (nivel de API 30): API de Thermal
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 rendimiento durante un tiempo limitado antes de que se los limite térmicamente. Un objetivo clave de la implementación debe ser alcanzar los objetivos de rendimiento sin exceder las limitaciones térmicas. La API térmica permite hacerlo sin la necesidad de realizar optimizaciones específicas para el dispositivo. Además, cuando depuras problemas de rendimiento, es importante saber si el estado térmico del dispositivo limita el rendimiento. Además, cuando depuras problemas de rendimiento, es importante saber si el estado térmico del dispositivo limita el rendimiento.
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, los desarrolladores de juegos pueden ajustar la carga de trabajo cambiando la Configuración de calidad con el complemento de rendimiento adaptable. En el caso de Unreal Engine, usa la Configuración de escalabilidad para ajustar los 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 de que el margen térmico disminuye a niveles más seguros, el juego puede volver a aumentar la configuración de calidad, 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
. Con este método, se predice cuánto tiempo el dispositivo puede mantener el nivel de rendimiento actual sin sobrecalentarse. 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.
Adquisición de administrador térmico
Para usar la API de Thermal, primero deberás adquirir el administrador de la temperatura
C++
AThermalManager* thermal_manager = AThermal_acquireManager();
Java
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
Prevé el margen térmico x segundos más adelante para tener más control
Puedes pedirle al sistema que pronostica la temperatura x segundos más adelante con la carga de trabajo actual. Esto te brinda un control más detallado y más tiempo para reaccionar, ya que se reduce la carga de trabajo para evitar que se active una limitación térmica.
El resultado varía de 0.0f (sin limitación, THERMAL_STATUS_NONE
) a 1.0f (regulación excesiva, THERMAL_STATUS_SEVERE
). Si tienes diferentes niveles de calidad de gráficos en tus juegos, puedes seguir nuestros 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, puedes usar el estado térmico para aclararlo.
Cada modelo de dispositivo puede diseñarse de manera diferente. Algunos dispositivos pueden distribuir mejor el calor y, por lo tanto, ser capaces de soportar un mayor margen térmico antes de limitarse. Si deseas leer una agrupación simplificada de rangos del margen térmico, puedes verificar el estado térmico para comprender su valor 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 thermalStatus
alcance un nivel determinado (por ejemplo, THERMAL_STATUS_LIGHT
). Para hacerlo, puedes registrar una devolución de llamada y permitir que el sistema te notifique cuando cambie el 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 Thermostat_manager que adquiriste. Si usas Java, la referencia de PowerManager se puede recolectar automáticamente como elemento no utilizado. Pero si usas la API de Java a través de JNI y conservas una referencia, recuerda limpiar la referencia.
C++
AThermal_releaseManager(thermal_manager);
Para obtener una guía completa sobre cómo implementar la API térmica en un juego nativo de C++ con la API de C++ (API de NDK) y la API de Java (a través de JNI), consulta la sección Cómo integrar la API térmica en la sección Codelab de adaptabilidad.
Lineamientos del margen térmico
Puedes supervisar el estado térmico del dispositivo mediante un sondeo del método getThermalHeadroom
. Con este método, se predice cuánto tiempo el dispositivo puede mantener el nivel de rendimiento actual antes de alcanzar THERMAL_STATUS_SEVERE
.
Por ejemplo, si getThermalHeadroom(30)
muestra 0.8, significa que, en 30 segundos, se espera que el margen alcance 0.8, donde hay una distancia de 0.2 de una limitación severa, o 1.0. Si el tiempo es inferior a la cantidad necesaria para ejecutar la carga de trabajo, el juego debe disminuirla a un nivel sostenible. Por ejemplo, el juego puede reducir la velocidad de fotogramas, reducir la fidelidad o reducir el trabajo de conectividad de red.
Significado y estados térmicos
- Si el dispositivo no se regula térmicamente, haz lo siguiente:
- Algunas limitaciones, pero sin un impacto significativo en el rendimiento:
- Limitación significativa que afecta el rendimiento:
Limitaciones del dispositivo de la API de Thermal
Existen algunas limitaciones conocidas o requisitos adicionales de la API térmica debido a las implementaciones de la API térmica en dispositivos más antiguos. Estas son las limitaciones y cómo solucionarlos:
- No llames a la API de
GetThermalHeadroom()
con demasiada frecuencia. Si lo haces, la API mostrará NaN. Debes llamarlo, como máximo, una vez por segundo. - Si el valor inicial de
GetThermalHeadroom()
es NaN, la API no estará disponible en el dispositivo. - Si
GetThermalHeadroom()
muestra un valor alto (p. ej., 0.85 o más) yGetCurrentThermalStatus()
aún muestraTHERMAL_STATUS_NONE
, es probable que el estado no se actualice. Usa heurísticas para calcular el estado correcto de limitación térmica o solo usagetThermalHeadroom()
singetCurrentThermalStatus()
.
Ejemplo de heurística:
- Verifica que la API de Thermal sea compatible.
isAPISupported()
verifica el valor de la primera llamada agetThermalHeadroom
para asegurarse de que no sea 0 ni NaN y se omite si se usa la API si el primer valor es 0 o NaN. - Si
getCurrentThermalStatus()
muestra un valor distinto deTHERMAL_STATUS_NONE
, se limitará térmicamente el dispositivo. - Si
getCurrentThermalStatus()
sigue mostrandoTHERMAL_STATUS_NONE
, no necesariamente significa que no se limite térmicamente el dispositivo. Podría significar quegetCurrentThermalStatus()
no es compatible con el dispositivo. Verifica el valor que muestragetThermalHeadroom()
para garantizar el estado del dispositivo. - Si
getThermalHeadroom()
muestra un valor > 1.0, el estado en realidad podría serTHERMAL_STATUS_SEVERE
o superior, reducir la carga de trabajo de inmediato y mantener una carga de trabajo menor hasta quegetThermalHeadroom()
muestre un valor más bajo. - Si
getThermalHeadroom()
muestra un valor de 0.95, el estado en realidad podría serTHERMAL_STATUS_MODERATE
o superior, reduce la carga de trabajo de inmediato y mantén la precaución para evitar una lectura mayor. - Si
getThermalHeadroom()
muestra un valor de 0.85, el estado en realidad podría serTHERMAL_STATUS_LIGHT
. Mantén la alerta 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: