Date de sortie :
Android 11 (niveau d'API 30) : API Thermal
Android 12 (niveau d'API 31) : API NDK
(Preview) Android 15 (DP1) – getThermalHeadroomThresholds()
Les performances potentielles de votre application sont limitées par l'état thermique de l'appareil, qui peut varier en fonction de caractéristiques telles que la météo, son utilisation récente et sa conception thermique. Les appareils ne peuvent maintenir un niveau de performances élevé que pendant une certaine durée avant de devoir faire face à des limites thermiques. L'un des buts ultimes de votre implémentation est d'atteindre les objectifs de performances sans dépasser les limites thermiques. L'API Thermal permet d'y parvenir sans avoir besoin d'optimisations spécifiques à l'appareil. En outre, lors du débogage des problèmes de performances, il est important de savoir si l'état thermique de votre appareil limite les performances.
Les moteurs de jeu disposent généralement de paramètres de performances d'exécution permettant d'ajuster la charge de travail qu'ils imposent à l'appareil. Par exemple, ces paramètres peuvent définir le nombre de threads de calcul, l'affinité entre les nœuds de calcul et les threads pour les cœurs de petite et de grande taille, les options de fidélité GPU et les résolutions de tampon de trame. Dans Unity Engine, les développeurs de jeux peuvent ajuster la charge de travail en modifiant les paramètres de qualité à l'aide du plug-in Adaptive Performance. Pour Unreal Engine, utilisez les paramètres d'évolutivité pour ajuster les niveaux de qualité de manière dynamique.
Lorsqu'un appareil se rapproche d'un état thermique qui n'est pas sûr, ces paramètres contribuent à réduire la charge de travail afin que votre jeu n'ait pas à en subir les conséquences. Pour éviter toute limitation, vous devez surveiller l'état thermique de l'appareil et ajuster de manière proactive la charge de travail du moteur de jeu.
Lorsque l'appareil est en surchauffe, la charge de travail doit descendre en dessous des niveaux de performances durables pour dissiper la chaleur. Une fois que la marge thermique est revenue à un niveau plus sûr, le jeu peut de nouveau augmenter les paramètres de qualité, mais assurez-vous de trouver un niveau de qualité durable pour une durée de jeu optimale.
Pour surveiller l'état thermique de l'appareil, interrogez la méthode getThermalHeadroom. Cette méthode prédit la durée pendant laquelle l'appareil peut maintenir le niveau de performances actuel sans surchauffe. Si cette durée est inférieure au temps nécessaire à l'exécution de la charge de travail, le jeu doit limiter la charge de travail à un niveau durable. Par exemple, il peut basculer sur des cœurs plus petits, diminuer la fréquence de frames ou réduire la fidélité.
Acquérir le gestionnaire thermique
Pour utiliser l'API thermique, vous devez d'abord acquérir le gestionnaire thermique.
C++
AThermalManager* thermal_manager = AThermal_acquireManager();
Java
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
Prévoir la marge thermique x secondes à l'avance pour un meilleur contrôle
Vous pouvez demander au système de prévoir la température dans x secondes avec la charge de travail actuelle. Cela vous permet de mieux contrôler la situation et de disposer de plus de temps pour réagir en réduisant la charge de travail afin d'éviter le déclenchement de la limitation thermique.
Le résultat est compris entre 0.0f (aucune limitation, THERMAL_STATUS_NONE)
à 1.0f (limitation importante, THERMAL_STATUS_SEVERE).
Si votre jeu propose différents niveaux de qualité graphique, vous pouvez suivre nos
Consignes relatives à la marge thermique.
C++
float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);
Java
float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + thermalHeadroom);
Vous pouvez également vous appuyer sur l'état thermique pour obtenir des précisions.
Chaque modèle d'appareil peut être conçu différemment. Certains appareils peuvent mieux répartir la chaleur et donc supporter une marge thermique plus élevée avant d'être limités. Si vous souhaitez lire un regroupement simplifié des plages de marge thermique, vous pouvez vérifier l'état thermique pour comprendre la valeur de la marge thermique sur l'appareil actuel.
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);
Recevoir une notification lorsque l'état thermique change
Vous pouvez également éviter d'interroger thermalHeadroom tant que thermalStatus n'a pas atteint un certain niveau (par exemple, THERMAL_STATUS_LIGHT). Pour ce faire, vous pouvez enregistrer un rappel pour que le système vous avertisse chaque fois que l'état a changé.
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);
N'oubliez pas de supprimer l'écouteur lorsque vous avez terminé.
C++
int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether the callback has been registered previously
}
Java
powerManager.removeThermalStatusListener(listener);
Effectuer un nettoyage
Une fois que vous avez terminé, vous devez nettoyer le thermal_manager que vous avez acquis. Si vous utilisez Java, la référence PowerManager peut être automatiquement collectée pour vous. Toutefois, si vous utilisez l'API Java via JNI et que vous avez conservé une référence, n'oubliez pas de la nettoyer.
C++
AThermal_releaseManager(thermal_manager);
Pour obtenir un guide complet sur l'implémentation de l'API Thermal dans un jeu C++ natif à l'aide de l'API C++ (API NDK) et de l'API Java (via JNI), consultez la section Intégrer l'API Thermal dans le atelier de programmation sur l'adaptabilité.
Consignes concernant la plage de température
Pour surveiller l'état thermique de l'appareil, interrogez la méthode getThermalHeadroom. Cette méthode prédit la durée pendant laquelle l'appareil peut maintenir le niveau de performances actuel avant d'atteindre THERMAL_STATUS_SEVERE.
Par exemple, si getThermalHeadroom(30) renvoie 0,8, cela signifie que dans 30 secondes, la marge de manœuvre devrait atteindre 0,8, ce qui correspond à une distance de 0,2 par rapport à la limitation sévère, ou 1,0. Si cette durée est inférieure au temps nécessaire à l'exécution de la charge de travail, le jeu doit limiter la charge de travail à un niveau durable. Par exemple, le jeu peut réduire la fréquence d'images, diminuer la fidélité ou réduire la charge de travail de la connectivité réseau.
États thermiques et leur signification
- Si l'appareil n'est pas soumis à une limitation thermique :
- L'appareil est soumis à quelques limitations, sans impact significatif sur les performances :
- L'appareil est soumis à des limitations significatives qui nuisent aux performances :
Limites de l'API Thermal liées aux appareils
En raison de l'implémentation de l'API thermique sur les anciens appareils, il existe certaines limites connues ou exigences supplémentaires concernant l'API thermique. Voici les limites et comment les contourner :
- N'appelez pas l'API
GetThermalHeadroom()trop souvent. Dans ce cas, l'API renvoieNaN. Vous ne devez pas l'appeler plus d'une fois toutes les 10 secondes. - Évitez d'appeler à partir de plusieurs threads. Il est plus difficile de garantir la fréquence d'appel et cela peut entraîner le renvoi de
NaNpar l'API. - Si la valeur initiale de
GetThermalHeadroom()est NaN, l'API n'est pas disponible sur l'appareil. - Si
GetThermalHeadroom()renvoie une valeur élevée (par exemple, 0,85 ou plus) et queGetCurrentThermalStatus()renvoie toujoursTHERMAL_STATUS_NONE, il est probable que l'état n'ait pas été mis à jour. Utilisez des heuristiques pour estimer l'état de limitation thermique correct ou utilisez simplementgetThermalHeadroom()sansgetCurrentThermalStatus().
Exemple d'heuristique :
- Vérifiez que l'API Thermal est compatible.
isAPISupported()vérifie la valeur du premier appel àgetThermalHeadroompour s'assurer qu'elle n'est pas égale à 0 ni à NaN, et évite d'utiliser l'API si la première valeur est égale à 0 ou à NaN. - Si
getCurrentThermalStatus()renvoie une valeur autre queTHERMAL_STATUS_NONE, cela signifie que l'appareil est limité thermiquement. - Si
getCurrentThermalStatus()renvoie toujoursTHERMAL_STATUS_NONE, cela ne signifie pas nécessairement que l'appareil n'est pas soumis à une limitation thermique. Cela peut signifier quegetCurrentThermalStatus()n'est pas compatible avec l'appareil. Vérifiez la valeur renvoyée degetThermalHeadroom()pour vous assurer de l'état de l'appareil. - Si
getThermalHeadroom()renvoie une valeur supérieure à 1, 0, l'état peut en fait êtreTHERMAL_STATUS_SEVEREou supérieur. Réduisez immédiatement la charge de travail et maintenez-la à un niveau inférieur jusqu'à ce quegetThermalHeadroom()renvoie une valeur inférieure. - Si
getThermalHeadroom()renvoie une valeur de 0, 95, l'état peut en fait êtreTHERMAL_STATUS_MODERATEou plus. Réduisez immédiatement la charge de travail et gardez un œil sur la situation pour éviter une lecture plus élevée. - Si
getThermalHeadroom()renvoie une valeur de 0, 85, l'état peut en fait êtreTHERMAL_STATUS_LIGHT. Restez vigilant et réduisez la charge de travail si possible.
Pseudo-code :
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.
}
}
}
Diagramme :