Data di uscita:
Android 11 (livello API 30) - API Thermal
Android 12 (livello API 31) - API NDK
(Anteprima) Android 15 (DP1) - getThermalHeadroomThresholds()
Le potenziali prestazioni della tua app sono limitate dallo stato termico del dispositivo, che può variare in base a caratteristiche quali condizioni meteo, utilizzo recente e design termico del dispositivo. I dispositivi possono mantenere un livello elevato di prestazioni per un periodo di tempo limitato prima di essere limitati termicamente. Un obiettivo fondamentale dell'implementazione deve essere il raggiungimento degli obiettivi di rendimento senza superare i limiti termici. L'API Thermal lo rende possibile senza la necessità di ottimizzazioni specifiche per il dispositivo. Inoltre, quando si esegue il debug dei problemi di rendimento, è importante sapere se lo stato termico del dispositivo sta limitando il rendimento.
I motori di gioco in genere hanno parametri di prestazioni di runtime che possono regolare il carico di lavoro che il motore impone al dispositivo. Ad esempio, questi parametri possono impostare il numero di thread worker, l'affinità dei thread worker per i core grandi e piccoli, le opzioni di fedeltà della GPU e le risoluzioni del framebuffer. Nel motore Unity, gli sviluppatori di giochi possono regolare il carico di lavoro modificando le impostazioni di qualità utilizzando il plug-in Adaptive Performance. Per Unreal Engine, utilizza le impostazioni di scalabilità per regolare dinamicamente i livelli di qualità.
Quando un dispositivo si avvicina a uno stato termico non sicuro, il gioco può evitare di essere limitato riducendo il carico di lavoro tramite questi parametri. Per evitare la limitazione, devi monitorare lo stato termico del dispositivo e regolare in modo proattivo il carico di lavoro del motore di gioco.
Una volta che il dispositivo si surriscalda, il carico di lavoro deve scendere al di sotto del livello di prestazioni sostenibile per dissipare il calore. Dopo che il margine termico scende a livelli più sicuri, il gioco può aumentare di nuovo le impostazioni di qualità, ma assicurati di trovare un livello di qualità sostenibile per un tempo di gioco ottimale.
Puoi monitorare lo stato termico del dispositivo eseguendo il polling del metodo
getThermalHeadroom. Questo metodo prevede per quanto tempo il dispositivo può
mantenere il livello di prestazioni attuale senza surriscaldarsi. Se il tempo è inferiore
alla quantità necessaria per eseguire il workload, il gioco deve ridurre il
workload a un livello sostenibile. Ad esempio, il gioco può passare a core più piccoli, ridurre il frame rate o diminuire la fedeltà.
Acquisire Thermal Manager
Per utilizzare l'API Thermal, devi prima acquisire Thermal Manager
C++
AThermalManager* thermal_manager = AThermal_acquireManager();
Java
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
Prevedi il margine termico x secondi in anticipo per un maggiore controllo
Puoi chiedere al sistema di prevedere la temperatura x secondi in anticipo con il carico di lavoro attuale. In questo modo hai un controllo più granulare e più tempo per reagire riducendo il carico di lavoro per evitare l'attivazione della limitazione termica.
Il risultato varia da 0,0f (nessuna limitazione,
THERMAL_STATUS_NONE)
a 1.0f (limitazione pesante,
THERMAL_STATUS_SEVERE).
Se nei tuoi giochi sono presenti diversi livelli di qualità grafica, puoi seguire le nostre
linee guida sul margine termico.
C++
float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);
Java
float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + thermalHeadroom);
In alternativa, fai affidamento sullo stato termico per chiarimenti
Ogni modello di dispositivo può essere progettato in modo diverso. Alcuni dispositivi potrebbero essere in grado di distribuire meglio il calore e quindi essere in grado di sopportare un headroom termico più elevato prima di essere limitati. Se vuoi leggere un raggruppamento semplificato di intervalli di margine termico, puoi controllare lo stato termico per comprendere il valore del margine termico sul dispositivo attuale.
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);
Ricevere notifiche quando lo stato termico cambia
Puoi anche evitare di eseguire il polling di thermalHeadroom finché thermalStatus non raggiunge
un determinato livello (ad esempio:
THERMAL_STATUS_LIGHT).
A questo scopo, puoi registrare un callback per consentire al sistema di inviarti una notifica ogni volta che lo stato cambia.
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);
Ricordati di rimuovere l'ascoltatore al termine
C++
int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether the callback has been registered previously
}
Java
powerManager.removeThermalStatusListener(listener);
Pulizia
Al termine, dovrai pulire thermal_manager che hai acquisito. Se utilizzi Java, il riferimento PowerManager può essere raccolto automaticamente per te. Tuttavia, se utilizzi l'API Java tramite JNI e hai mantenuto un riferimento, ricordati di pulirlo.
C++
AThermal_releaseManager(thermal_manager);
Per una guida completa su come implementare l'API Thermal in un gioco C++ nativo utilizzando sia l'API C++ (API NDK) sia l'API Java (tramite JNI), consulta la sezione Integra l'API Thermal nella sezione Codelab sull'adattabilità.
Linee guida per il margine termico
Puoi monitorare lo stato termico del dispositivo eseguendo il polling del metodo
getThermalHeadroom. Questo metodo prevede per quanto tempo il dispositivo può mantenere il livello di prestazioni attuale prima di raggiungere
THERMAL_STATUS_SEVERE.
Ad esempio, se getThermalHeadroom(30) restituisce 0,8, significa che in 30 secondi l'headroom dovrebbe raggiungere 0,8, dove la distanza dal throttling grave o 1,0 è pari a 0,2. Se il tempo è inferiore alla quantità necessaria per eseguire il workload, il gioco deve ridurre il workload a un livello sostenibile. Ad esempio, il gioco può ridurre il frame rate, la fedeltà o
la connettività di rete.
Stati termici e significato
- Se il dispositivo non è soggetto a limitazione termica:
- Limitazione della velocità, ma nessun impatto significativo sul rendimento:
- Limitazione significativa che influisce sulle prestazioni:
Limitazioni dei dispositivi dell'API Thermal
Esistono alcune limitazioni note o requisiti aggiuntivi dell'API Thermal, dovuti alle implementazioni dell'API Thermal su dispositivi meno recenti. I limiti e come aggirarli sono i seguenti:
- Non chiamare l'API
GetThermalHeadroom()troppo spesso. Se lo fai, l'API restituisceNaN. Non devi chiamarlo più di una volta ogni 10 secondi. - Evita di chiamare da più thread, è più difficile garantire la frequenza di chiamata e l'API potrebbe restituire
NaN. - Se il valore iniziale di
GetThermalHeadroom()è NaN, l'API non è disponibile sul dispositivo - Se
GetThermalHeadroom()restituisce un valore elevato (ad es. 0,85 o superiore) eGetCurrentThermalStatus()restituisce ancoraTHERMAL_STATUS_NONE, è probabile che lo stato non sia aggiornato. Utilizza l'euristica per stimare lo stato corretto di limitazione termica o utilizza semplicementegetThermalHeadroom()senzagetCurrentThermalStatus().
Esempio di euristica:
- Controlla che l'API Thermal sia supportata.
isAPISupported()controlla il valore della prima chiamata agetThermalHeadroomper assicurarsi che non sia 0 o NaN e salta l'utilizzo dell'API se il primo valore è 0 o NaN. - Se
getCurrentThermalStatus()restituisce un valore diverso daTHERMAL_STATUS_NONE, la limitazione termica del dispositivo è attiva. - Se
getCurrentThermalStatus()continua a restituireTHERMAL_STATUS_NONE, non significa necessariamente che il dispositivo non sia soggetto a limitazione termica. Potrebbe significare chegetCurrentThermalStatus()non è supportato sul dispositivo. Controlla il valore restituito digetThermalHeadroom()per assicurarti delle condizioni del dispositivo. - Se
getThermalHeadroom()restituisce un valore > 1,0, lo stato potrebbe essereTHERMAL_STATUS_SEVEREo superiore, riduci immediatamente il workload e mantienilo più basso finchégetThermalHeadroom()non restituisce un valore inferiore - Se
getThermalHeadroom()restituisce un valore di 0,95, lo stato potrebbe in realtà essereTHERMAL_STATUS_MODERATEo superiore, ridurre immediatamente il workload e mantenere l'avviso per evitare una lettura più elevata - Se
getThermalHeadroom()restituisce un valore di 0,85, lo stato potrebbe essereTHERMAL_STATUS_LIGHT, tieni d'occhio la situazione e riduci il carico di lavoro, se possibile.
Pseudocodice:
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.
}
}
}
Diagramma: