Thermal API

Veröffentlicht:

Android 11 (API-Level 30) – Thermal API

Android 12 (API-Level 31) – NDK API

(Vorabversion) Android 15 (DP1) – getThermalHeadroomThresholds()

Die potenzielle Leistung deiner App ist durch den Temperaturzustand des Geräts begrenzt, der je nach Eigenschaften wie Wetter, jüngster Nutzung und thermischer Beschaffenheit des Geräts variieren kann. Geräte können nur für einen begrenzten Zeitraum ein hohes Leistungsniveau aufrechterhalten, bevor sie thermisch gedrosselt werden. Ein zentrales Ziel der Implementierung sollte darin bestehen, Leistungsziele ohne Überschreiten von Temperaturbeschränkungen zu erreichen. Mit der Thermal API ist es möglich, ohne dass gerätespezifische Optimierungen erforderlich sind. Außerdem ist es beim Beheben von Leistungsproblemen wichtig, zu wissen, ob der Temperaturzustand Ihres Geräts die Leistung beeinträchtigt. Außerdem ist es beim Beheben von Leistungsproblemen wichtig zu wissen, ob der Temperaturzustand Ihres Geräts die Leistung einschränkt.

Spiel-Engines haben normalerweise Parameter für die Laufzeitleistung, mit denen die Arbeitslast angepasst werden kann, die die Engine auf das Gerät aufwendet. Mit diesen Parametern können Sie beispielsweise die Anzahl der Worker-Threads, die Worker-Thread-Affinität für große und kleine Kerne, die Optionen zur Grafikqualität und die Framebuffer-Auflösungen festlegen. In Unity Engine können Spieleentwickler die Arbeitslast anpassen, indem sie die Qualitätseinstellungen mithilfe des Adaptive Performance-Plug-ins ändern. Verwenden Sie für Unreal Engine die Skalierbarkeitseinstellungen, um die Qualitätsstufen dynamisch anzupassen.

Wenn sich ein Gerät einem unsicheren Temperaturzustand nähert, kann Ihr Spiel nicht gedrosselt werden, indem die Arbeitslast durch diese Parameter verringert wird. Um eine Drosselung zu vermeiden, sollten Sie den Temperaturzustand des Geräts überwachen und die Arbeitslast der Spiel-Engine proaktiv anpassen. Wenn das Gerät überhitzt, muss die Arbeitslast unter das nachhaltige Leistungsniveau fallen, um Wärme abzuleiten. Sobald der theoretische Toleranzbereich auf sicherere Levels gesunken ist, kann das Spiel die Qualitätseinstellungen wieder erhöhen. Achten Sie aber darauf, eine nachhaltige Qualität für eine optimale Spielzeit zu finden.

Sie können den Temperaturzustand des Geräts überwachen, indem Sie die Methode getThermalHeadroom abfragen. Mit dieser Methode wird vorhergesagt, wie lange das Gerät das aktuelle Leistungsniveau ohne Überhitzung halten kann. Wenn die Zeit kürzer ist, als zum Ausführen der Arbeitslast erforderlich ist, sollte Ihr Spiel die Arbeitslast auf ein nachhaltiges Niveau reduzieren. Im Spiel kann es beispielsweise zu kleineren Kernen kommen, die Framerate reduzieren oder die Grafikqualität verschlechtern.

Vorintegration der ADPF Thermal API
Abbildung 1: Thermal Headroom ohne aktives Monitoring von getThermalHeadroom
ADPF Thermal API – Nach-Integration
Abbildung 2. Thermal Headroom mit aktiver Überwachung von „getThermalHeadroom“

Thermal Manager übernehmen

Wenn Sie die Thermal API nutzen möchten, müssen Sie zuerst den Thermal Manager erwerben

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);

Prognostizieren Sie für mehr Kontrolle den thermischen Toleranzbereich x Sekunden im Voraus.

Sie können das System bitten, die Temperatur für die aktuelle Arbeitslast auf x Sekunden voraus zu prognostizieren. Dies gibt Ihnen eine genauere Kontrolle und mehr Zeit zum Reagieren, da die Arbeitslast reduziert wird, um eine Drosselung der Wärme zu verhindern.

Das Ergebnis reicht von 0,0f (keine Drosselung, THERMAL_STATUS_NONE) bis 1,0f (starke Drosselung, THERMAL_STATUS_SEVERE). Wenn Sie in Ihren Spielen unterschiedliche Grafikqualitätsstufen haben, können Sie unseren Richtlinien für thermische Toleranzbereiche folgen.

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);

Alternativ kannst du dich zur Klärung auf den Temperaturstatus verlassen

Jedes Gerätemodell kann anders aufgebaut sein. Einige Geräte können die Wärme besser verteilen und so einen höheren thermischen Toleranzbereich aushalten, bevor sie gedrosselt werden. Wenn Sie eine vereinfachte Gruppierung der Bereiche des thermischen Toleranzraums lesen möchten, können Sie den Temperaturstatus prüfen, um den Wert des thermischen Tolerraums auf dem aktuellen Gerät zu ermitteln.

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);

Benachrichtigungen erhalten, wenn sich der Temperaturzustand ändert

Sie können auch vermeiden, thermalHeadroom abzufragen, bis thermalStatus ein bestimmtes Level erreicht (z. B. THERMAL_STATUS_LIGHT). Dazu können Sie einen Callback registrieren, mit dem Sie das System benachrichtigt, wenn sich der Status geändert hat.

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);

Denken Sie daran, den Listener zu entfernen, wenn Sie fertig sind.

C++

int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether the callback has been registered previously
}

Java

powerManager.removeThermalStatusListener(listener);

Bereinigung

Sobald Sie fertig sind, müssen Sie das von Ihnen erworbene Thermal Manager bereinigen. Wenn Sie Java verwenden, kann die PowerManager-Referenz automatisch für Sie automatisch bereinigt werden. Wenn Sie jedoch die Java API über JNI verwenden und eine Referenz beibehalten haben, denken Sie daran, die Referenz zu bereinigen.

C++

AThermal_releaseManager(thermal_manager);

Eine vollständige Anleitung zum Implementieren der Thermal API in einem nativen C++-Spiel mit der C++ API (NDK API) und der Java API (über JNI) finden Sie im Abschnitt Integrate Thermal API im Abschnitt Anpassungscodelab.

Richtlinien für den thermischen Toleranzbereich

Sie können den Temperaturzustand des Geräts überwachen, indem Sie die Methode getThermalHeadroom abfragen. Mit dieser Methode wird vorhergesagt, wie lange das Gerät das aktuelle Leistungsniveau halten kann, bevor THERMAL_STATUS_SEVERE erreicht wird. Wenn getThermalHeadroom(30) beispielsweise 0,8 zurückgibt, wird erwartet, dass der Toleranzbereich in 30 Sekunden 0,8 erreicht (bei einer Entfernung von 0,2 von einer starken Drosselung) und 1,0. Wenn die Zeit unter dem erforderlichen Zeitaufwand zum Ausführen der Arbeitslast liegt, sollte Ihr Spiel die Arbeitslast auf ein tragfähiges Niveau reduzieren. Das Spiel kann beispielsweise die Framerate oder die Grafikqualität reduzieren oder die Arbeit an der Netzwerkverbindung reduzieren.

Temperaturstatus und Bedeutung

Geräteeinschränkungen der Thermal API

Aufgrund von Implementierungen der Thermal API auf älteren Geräten gibt es einige bekannte Einschränkungen oder zusätzliche Anforderungen für die Thermal API. Es gibt folgende Einschränkungen und wie Sie sie umgehen können:

  • Rufe die GetThermalHeadroom() API nicht zu häufig auf. Andernfalls gibt die API NaN zurück. Sie sollte maximal einmal pro Sekunde aufgerufen werden.
  • Wenn der Anfangswert von GetThermalHeadroom() NaN ist, ist die API auf dem Gerät nicht verfügbar.
  • Wenn GetThermalHeadroom() einen hohen Wert zurückgibt (z.B.0,85 oder höher) und GetCurrentThermalStatus() immer noch THERMAL_STATUS_NONE zurückgibt, wird der Status wahrscheinlich nicht aktualisiert. Verwenden Sie die Heuristik, um den korrekten Status der Drosselung der Energiezufuhr zu schätzen, oder verwenden Sie einfach getThermalHeadroom() ohne getCurrentThermalStatus().

Beispiel für Heuristik:

  1. Prüfen Sie, ob die Thermal API unterstützt wird. isAPISupported() prüft den Wert des ersten Aufrufs von getThermalHeadroom, um sicherzustellen, dass er nicht 0 oder NaN ist. Wenn der erste Wert entweder 0 oder NaN ist, wird er mit der API übersprungen.
  2. Wenn getCurrentThermalStatus() einen anderen Wert als THERMAL_STATUS_NONE zurückgibt, wird das Gerät thermisch gedrosselt.
  3. Wenn getCurrentThermalStatus() weiterhin THERMAL_STATUS_NONE zurückgibt, bedeutet dies nicht zwangsläufig, dass das Gerät nicht thermisch gedrosselt wird. Möglicherweise wird getCurrentThermalStatus() auf dem Gerät nicht unterstützt. Prüfen Sie den Rückgabewert von getThermalHeadroom(), um den Zustand des Geräts sicherzustellen.
  4. Wenn getThermalHeadroom() einen Wert von > 1,0 zurückgibt, könnte der Status tatsächlich THERMAL_STATUS_SEVERE oder höher sein, die Arbeitslast sofort reduzieren und eine geringere Arbeitslast beibehalten, bis getThermalHeadroom() einen niedrigeren Wert zurückgibt
  5. Wenn getThermalHeadroom() einen Wert von 0,95 zurückgibt, könnte der Status tatsächlich THERMAL_STATUS_MODERATE oder höher sein, die Arbeitslast sofort reduzieren und die Überwachung beibehalten, um höhere Lesevorgänge zu verhindern
  6. Wenn getThermalHeadroom() einen Wert von 0, 85 zurückgibt, könnte der Status tatsächlich THERMAL_STATUS_LIGHT sein. Behalten Sie das Watchout bei und reduzieren Sie die Arbeitslast nach Möglichkeit.

Pseudocode:

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

Diagramm:

ADPF-heuristisches Beispiel
Abbildung 3: Beispiel für eine Heuristik zum Ermitteln der Thermal API-Unterstützung auf älteren Geräten