API Thermal

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à.

Pre-integrazione dell'API ADPF Thermal
Figura 1. Margine termico senza monitoraggio attivo di getThermalHeadroom
API Thermal ADPF post-integrazione
Figura 2. Thermal Headroom con monitoraggio attivo di `getThermalHeadroom`

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

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 restituisce NaN. 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) e GetCurrentThermalStatus() restituisce ancora THERMAL_STATUS_NONE, è probabile che lo stato non sia aggiornato. Utilizza l'euristica per stimare lo stato corretto di limitazione termica o utilizza semplicemente getThermalHeadroom() senza getCurrentThermalStatus().

Esempio di euristica:

  1. Controlla che l'API Thermal sia supportata. isAPISupported() controlla il valore della prima chiamata a getThermalHeadroom per assicurarsi che non sia 0 o NaN e salta l'utilizzo dell'API se il primo valore è 0 o NaN.
  2. Se getCurrentThermalStatus() restituisce un valore diverso da THERMAL_STATUS_NONE, la limitazione termica del dispositivo è attiva.
  3. Se getCurrentThermalStatus() continua a restituire THERMAL_STATUS_NONE, non significa necessariamente che il dispositivo non sia soggetto a limitazione termica. Potrebbe significare che getCurrentThermalStatus() non è supportato sul dispositivo. Controlla il valore restituito di getThermalHeadroom() per assicurarti delle condizioni del dispositivo.
  4. Se getThermalHeadroom() restituisce un valore > 1,0, lo stato potrebbe essere THERMAL_STATUS_SEVERE o superiore, riduci immediatamente il workload e mantienilo più basso finché getThermalHeadroom() non restituisce un valore inferiore
  5. Se getThermalHeadroom() restituisce un valore di 0,95, lo stato potrebbe in realtà essere THERMAL_STATUS_MODERATE o superiore, ridurre immediatamente il workload e mantenere l'avviso per evitare una lettura più elevata
  6. Se getThermalHeadroom() restituisce un valore di 0,85, lo stato potrebbe essere THERMAL_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:

Esempio di euristica ADPF
Figura 3.Esempio di euristica per determinare il supporto dell'API Thermal su dispositivi meno recenti