Uscita:
Android 11 (livello API 30) - API Thermal
Android 12 (livello API 31) - API NDK
(Anteprima) Android 15 (DP1) - getThermalHeadroomThresholds()
Le prestazioni potenziali della tua app sono limitate dallo stato termico del dispositivo, che può variare in base a caratteristiche quali meteo, utilizzo recente e design termico del dispositivo. I dispositivi possono mantenere un livello di prestazioni elevato solo per un periodo di tempo limitato prima di essere limitati termicamente. Un obiettivo chiave dell'implementazione dovrebbe essere il raggiungimento degli obiettivi di prestazioni senza superare i limiti termici. l'API Thermal permette di farlo senza ottimizzazioni specifiche per i dispositivi. Inoltre, durante il debug dei problemi di prestazioni, è importante sapere se lo stato termico del dispositivo limita le prestazioni. Inoltre, durante il debug dei problemi di prestazioni, è importante sapere se lo stato termico del dispositivo limita le prestazioni.
In genere i motori di gioco hanno parametri di prestazioni di runtime che possono regolare il carico di lavoro applicato dal motore 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à GPU e le risoluzioni del framebuffer. In Unity Engine, gli sviluppatori di giochi possono regolare il carico di lavoro modificando le Impostazioni qualità utilizzando il plug-in Adaptive Performance. Per Unreal Engine, utilizza Impostazioni di scalabilità per regolare i livelli qualitativi in modo dinamico.
Quando un dispositivo si avvicina a uno stato termico non sicuro, il gioco può evitare di essere limitato riducendo il carico di lavoro attraverso questi parametri. Per evitare la limitazione, devi monitorare lo stato termico del dispositivo e regolare proattivamente il carico di lavoro del motore grafico. Quando il dispositivo si surriscalda, per dissipare il calore il carico di lavoro deve scendere al di sotto del livello di prestazioni sostenibili. Quando il margine termico scende a livelli più sicuri, il gioco può aumentare di nuovo le impostazioni di qualità, ma assicurarsi 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 potrà mantenere il livello di prestazioni attuale senza surriscaldarsi. Se il tempo è inferiore all'importo necessario per eseguire il carico di lavoro, il gioco dovrebbe ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può passare a core più piccoli, ridurre la frequenza fotogrammi o la fedeltà.
Acquisisci gestore termico
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);
Per un maggiore controllo, prevedi il margine termico a x secondi di anticipo
Puoi chiedere al sistema di prevedere la temperatura x secondi prima del carico di lavoro attuale. In questo modo avrai un controllo più granulare e più tempo per reagire, riducendo il carico di lavoro per evitare l'attivazione della limitazione termica.
Il risultato va da 0,0 f (nessuna limitazione, THERMAL_STATUS_NONE
) a 1,0 f (limitata eccessiva, THERMAL_STATUS_SEVERE
).
Se hai livelli di qualità grafica diversi nei tuoi giochi, puoi seguire le nostre
linee guida relative al margine termico.
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);
In alternativa, affidati allo stato termico per maggiore chiarezza
Ogni modello di dispositivo può essere progettato in modo diverso. Alcuni dispositivi potrebbero essere in grado di distribuire meglio il calore e quindi di resistere a un margine termico più elevato prima di essere limitati. Se vuoi leggere un raggruppamento semplificato di intervalli di intervalli termici, puoi controllare lo stato termico per comprendere il valore di 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);
Ricevi una notifica quando cambia lo stato termico
Puoi anche evitare di eseguire il polling di thermalHeadroom
fino a quando 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.
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);
Al termine, ricordati di rimuovere il listener
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 ripulire il termico manager che hai acquisito. Se utilizzi Java, il riferimento di PowerManager può essere eliminato automaticamente. Tuttavia, se utilizzi l'API Java tramite JNI e hai conservato un riferimento, ricordati di ripulire il 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) che l'API Java (tramite JNI), consulta la sezione API Thermal integrata 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 potrà mantenere il livello di prestazioni attuale prima di raggiungere THERMAL_STATUS_SEVERE
.
Ad esempio, se getThermalHeadroom(30)
restituisce 0,8, significa che entro 30 secondi il margine di miglioramento dovrebbe raggiungere 0,8, ovvero 1,0, a una distanza di 0,2 da una limitazione grave. Se il tempo è inferiore alla quantità necessaria per eseguire il carico di lavoro, il gioco dovrebbe ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può ridurre la frequenza fotogrammi, la fedeltà o
ridurre il lavoro di connettività di rete.
Stati termici e significato
- Se il dispositivo non viene limitato termicamente:
- Un po' di limitazione, ma nessun impatto significativo sulle prestazioni:
- 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 termica su dispositivi meno recenti. Di seguito sono riportate le limitazioni e le relative soluzioni:
- Non chiamare l'API
GetThermalHeadroom()
troppo spesso. In questo modo, l'API restituirà NaN. Dovresti chiamarla al massimo una volta al secondo. - Se il valore iniziale di
GetThermalHeadroom()
è NaN, l'API non è disponibile sul dispositivo - Se
GetThermalHeadroom()
restituisce un valore alto (ad es. 0,85 o più) eGetCurrentThermalStatus()
restituisce comunqueTHERMAL_STATUS_NONE
, è probabile che lo stato non venga aggiornato. Utilizza l'euristica per stimare lo stato di limitazione termica corretto oppure utilizza semplicementegetThermalHeadroom()
senzagetCurrentThermalStatus()
.
Esempio di euristica:
- Verifica che l'API Thermal sia supportata.
isAPISupported()
controlla il valore della prima chiamata agetThermalHeadroom
per assicurarsi che non sia 0 o NaN e ignora l'utilizzo dell'API se il primo valore è 0 o NaN. - Se
getCurrentThermalStatus()
restituisce un valore diverso daTHERMAL_STATUS_NONE
, il dispositivo viene limitato termicamente. - Se
getCurrentThermalStatus()
continua a restituireTHERMAL_STATUS_NONE
, non significa necessariamente che il dispositivo non sia sottoposto a una limitazione termica. Questo potrebbe significare chegetCurrentThermalStatus()
non è supportato sul dispositivo. Controlla il valore restituito digetThermalHeadroom()
per verificare la condizione del dispositivo. - Se
getThermalHeadroom()
restituisce un valore maggiore di 1,0, lo stato potrebbe essere effettivamenteTHERMAL_STATUS_SEVERE
o superiore, ridurre immediatamente il carico di lavoro e mantenere un carico di lavoro inferiore fino a quandogetThermalHeadroom()
restituisce un valore inferiore - Se
getThermalHeadroom()
restituisce un valore pari a 0,95, lo stato potrebbe effettivamente essereTHERMAL_STATUS_MODERATE
o superiore, riduci immediatamente il carico di lavoro e tieni d'occhio l'attenzione per evitare letture maggiori - Se
getThermalHeadroom()
restituisce un valore pari a 0,85, lo stato potrebbe essere in realtàTHERMAL_STATUS_LIGHT
; mantieni il controllo e, se possibile, riduci il carico di lavoro
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: