Anno di uscita:
Android 11 (livello API 30) - API Thermal
Android 12 (livello API 31) - API NDK
(Anteprima) Android 15 (DP1) - getThermalHeadroomThresholds()
Il potenziale rendimento della tua app è limitato dallo stato termico del dispositivo, che può variare in base a caratteristiche come il meteo, l'utilizzo recente e la progettazione termica del dispositivo. I dispositivi possono mantenere un livello di rendimento elevato solo per un periodo di tempo limitato prima di essere sottoposti a limitazione termica. Un obiettivo chiave della tua implementazione dovrebbe essere il raggiungimento degli obiettivi di rendimento senza superare le limitazioni termiche. L'API Thermal lo rende possibile senza la necessità di ottimizzazioni specifiche per il dispositivo. Inoltre, quando esegui il debug dei problemi di rendimento, è importante sapere se lo stato termico del dispositivo sta limitando il rendimento.
I motori di gioco di solito hanno parametri di rendimento 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 di worker, l'affinità dei thread di worker per i core grandi e piccoli, le opzioni di fedeltà della GPU e le risoluzioni del framebuffer. In Unity Engine, 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 rendimento 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 qualitativo sostenibile per un tempo di gioco ottimale.
Puoi monitorare lo stato termico del dispositivo eseguendo il polling del
getThermalHeadroom metodo. Questo metodo prevede per quanto tempo il dispositivo può mantenere il livello di rendimento attuale senza surriscaldarsi. Se il tempo è inferiore alla quantità necessaria per eseguire il carico di lavoro, il gioco deve ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può passare a core più piccoli, ridurre la frequenza fotogrammi o ridurre 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);
Eseguire una query sul margine termico
Puoi chiedere al sistema il margine termico attuale. Questo fornisce un'indicazione di quanto il carico di lavoro sia vicino alla limitazione termica. L'API ti consente anche di prevedere la temperatura x secondi in anticipo con il carico di lavoro attuale. In questo modo l'applicazione ha più tempo per rispondere, ma sarà meno precisa rispetto all'utilizzo dello stato termico attuale.
Il risultato varia da 0,0f (nessuna limitazione,
THERMAL_STATUS_NONE)
a 1,0f (limitazione elevata,
THERMAL_STATUS_SEVERE).
Se nei tuoi giochi hai 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, affidati allo 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 di sopportare un margine 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);
getThermalHeadroom. Per una soluzione a questa situazione, consulta Limitazioni dei dispositivi dell'API Thermal.
Ricevere una notifica 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).
Per farlo, puoi registrare un callback per consentire al sistema di inviarti una notifica ogni volta che lo
stato cambia.
GetCurrentThermalStatus() senza eseguire la convalida con
GetThermalHeadroom()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);
Ricorda di rimuovere il listener al termine dell'operazione.
C++
int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
// failed, check whether the callback has been registered previously
}
Java
powerManager.removeThermalStatusListener(listener);
Esegui la pulizia
Al termine, dovrai liberare spazio in thermal_manager che hai acquisito. Se utilizzi Java, il riferimento PowerManager può essere raccolto automaticamente dal Garbage Collector. Tuttavia, se utilizzi l'API Java tramite JNI e hai mantenuto un riferimento, ricordati di eseguire la pulizia del riferimento.
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 Integrare l'API Thermal nella sezione del codelab sull'adattabilità.
Linee guida sul margine termico
Puoi monitorare lo stato termico del dispositivo eseguendo il polling del
getThermalHeadroom
metodo. Questo metodo prevede per quanto tempo il dispositivo può mantenere il livello di rendimento attuale
prima di raggiungere
THERMAL_STATUS_SEVERE.
Ad esempio, se getThermalHeadroom(30) restituisce 0,8, indica che in 30 secondi il margine dovrebbe raggiungere 0,8, dove c'è una distanza di 0,2 dalla limitazione elevata o 1,0. Se il tempo è inferiore alla quantità necessaria per eseguire il carico di lavoro, il gioco deve ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può ridurre la frequenza fotogrammi, ridurre la fedeltà o ridurre il lavoro di connettività di rete.
Stati termici e significato
- Se il dispositivo non è sottoposto a limitazione termica:
- Alcune limitazioni, ma nessun impatto significativo sul rendimento:
- Limitazione significativa che influisce sul rendimento:
Limitazioni dei dispositivi dell'API Thermal
Esistono alcune limitazioni note o requisiti aggiuntivi dell'API Thermal, a causa delle implementazioni dell'API Thermal sui dispositivi meno recenti. Le limitazioni e le relative soluzioni sono le seguenti:
- Non chiamare l'API
GetThermalHeadroom()troppo spesso. In caso contrario, 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()continua a restituireTHERMAL_STATUS_NONE, è probabile che lo stato non sia aggiornato. Utilizza l'euristica per stimare lo stato di limitazione termica corretto o utilizza semplicementegetThermalHeadroom()senzagetCurrentThermalStatus().
Esempio di euristica:
- Verifica 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, il dispositivo è sottoposto a limitazione termica. - Se
getCurrentThermalStatus()continua a restituireTHERMAL_STATUS_NONE, non significa necessariamente che il dispositivo non sia sottoposto a limitazione termica. Potrebbe significare chegetCurrentThermalStatus()non è supportato sul dispositivo. Controlla il valore restituito digetThermalHeadroom()per assicurarti della condizione del dispositivo. - Se
getThermalHeadroom()restituisce un valore > 1,0, lo stato potrebbe essereTHERMAL_STATUS_SEVEREo superiore, ridurre immediatamente il carico di lavoro e mantenerlo più basso finchégetThermalHeadroom()non restituisce un valore inferiore. - Se
getThermalHeadroom()restituisce un valore di 0,95, lo stato potrebbe essereTHERMAL_STATUS_MODERATEo superiore, ridurre immediatamente il carico di lavoro e tenere d'occhio per evitare una lettura più elevata. - Se
getThermalHeadroom()restituisce un valore di 0,85, lo stato potrebbe essereTHERMAL_STATUS_LIGHT, tenere d'occhio e ridurre 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: