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 Ihrer App wird durch den thermischen Zustand des Geräts begrenzt, der je nach Faktoren wie Wetter, aktueller Nutzung und dem thermischen Design des Geräts variieren kann. Geräte können nur für eine begrenzte Zeit eine hohe Leistung erbringen, bevor sie thermisch gedrosselt werden. Ein wichtiges Ziel Ihrer Implementierung sollte es sein, Leistungsziele zu erreichen, ohne die thermischen Grenzwerte zu überschreiten. Die Thermal API macht dies möglich, ohne dass gerätespezifische Optimierungen erforderlich sind. Außerdem ist es wichtig zu wissen, ob der thermische Zustand Ihres Geräts die Leistung einschränkt, wenn Sie Leistungsprobleme beheben.

Spiele-Engines haben in der Regel Laufzeitleistungsparameter, mit denen die Arbeitslast angepasst werden kann, die die Engine auf das Gerät legt. Mit diesen Parametern können Sie beispielsweise die Anzahl der Worker-Threads, die Worker-Thread-Affinität für große und kleine Kerne, GPU-Fidelity-Optionen und Framebuffer-Auflösungen festlegen. In der Unity-Engine können Spieleentwickler die Arbeitslast anpassen, indem sie die Qualitätseinstellungen über das Adaptive Performance-Plug-in ändern. Verwenden Sie für Unreal Engine die Scalability Settings (Skalierbarkeitseinstellungen), um die Qualitätsstufen dynamisch anzupassen.

Wenn sich ein Gerät einem unsicheren thermischen Zustand nähert, kann dein Spiel eine Drosselung vermeiden, indem es die Arbeitslast über diese Parameter verringert. Um Drosselung zu vermeiden, sollten Sie den thermischen Zustand des Geräts im Blick behalten und die Arbeitslast der Spiele-Engine proaktiv anpassen.

Wenn das Gerät überhitzt ist, muss die Arbeitslast unter das nachhaltige Leistungsniveau sinken, damit die Wärme abgeleitet werden kann. Sobald der thermische Spielraum auf ein sicheres Niveau gesunken ist, kann das Spiel die Qualitätseinstellungen wieder erhöhen. Es sollte jedoch darauf geachtet werden, dass ein nachhaltiges Qualitätsniveau für eine optimale Spieldauer gefunden wird.

Sie können den thermischen Zustand des Geräts überwachen, indem Sie die Methode getThermalHeadroom abfragen. Mit dieser Methode wird vorhergesagt, wie lange das Gerät das aktuelle Leistungsniveau aufrechterhalten kann, ohne zu überhitzen. Wenn die Zeit kürzer ist als die für die Ausführung der Arbeitslast erforderliche Zeit, sollte Ihr Spiel die Arbeitslast auf ein nachhaltiges Niveau reduzieren. Das Spiel kann beispielsweise auf kleinere Kerne umgestellt, die Framerate reduziert oder die Wiedergabetreue verringert werden.

ADPF Thermal API – Vor der Integration
Abbildung 1: Thermischer Headroom ohne aktive Überwachung von „getThermalHeadroom“
ADPF Thermal API nach der Integration
Abbildung 2. Thermischer Headroom mit aktivem Monitoring von „getThermalHeadroom“

Thermal Manager erwerben

Wenn Sie die Thermal API verwenden möchten, müssen Sie zuerst den Thermal Manager abrufen.

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

Thermischen Headroom x Sekunden im Voraus prognostizieren, um mehr Kontrolle zu haben

Sie können das System bitten, die Temperatur für x Sekunden im Voraus zu prognostizieren, basierend auf der aktuellen Arbeitslast. So haben Sie eine genauere Kontrolle und mehr Zeit, um zu reagieren, indem Sie die Arbeitslast reduzieren, bevor die thermische Drosselung einsetzt.

Das Ergebnis reicht von 0,0 f (keine Drosselung, THERMAL_STATUS_NONE)

bis 1,0 f (starkes Throttling,THERMAL_STATUS_SEVERE). Wenn Sie in Ihren Spielen verschiedene Grafikqualitätsstufen haben, können Sie sich an unseren Richtlinien für den thermischen Headroom orientieren.

C++

float thermal_headroom = AThermal_getThermalHeadroom(0);
ALOGI("ThermalHeadroom: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(0);
Log.d("ADPF", "ThermalHeadroom: " + thermalHeadroom);

Alternativ können Sie den thermischen Status zur Klärung heranziehen.

Die einzelnen Gerätemodelle können unterschiedlich gestaltet sein. Einige Geräte können Wärme besser ableiten und halten daher höhere thermische Reserven aus, bevor die Leistung gedrosselt wird. Wenn Sie eine vereinfachte Gruppierung von Bereichen des thermischen Spielraums sehen möchten, können Sie den thermischen Status prüfen, um den Wert des thermischen Spielraums auf dem aktuellen Gerät zu interpretieren.

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 thermische Status ändert

Sie können auch vermeiden, thermalHeadroom abzufragen, bis thermalStatus ein bestimmtes Niveau erreicht hat (z. B. THERMAL_STATUS_LIGHT). Dazu können Sie einen Callback registrieren, damit Sie vom System benachrichtigt werden, wenn sich der Status ändert.

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

Wenn Sie fertig sind, müssen Sie den abgerufenen thermal_manager bereinigen. Wenn Sie Java verwenden, kann die PowerManager-Referenz automatisch für Sie bereinigt werden. Wenn Sie 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 zur Implementierung der Thermal API in einem nativen C++-Spiel mit der C++ API (NDK API) und der Java API (über JNI) finden Sie im Abschnitt Thermal API einbinden des Adaptability-Codelab.

Richtlinien für den thermischen Headroom

Sie können den thermischen Zustand des Geräts überwachen, indem Sie die Methode getThermalHeadroom abfragen. Diese Methode prognostiziert, wie lange das Gerät das aktuelle Leistungsniveau beibehalten kann, bevor es THERMAL_STATUS_SEVERE erreicht. Wenn getThermalHeadroom(30) beispielsweise 0,8 zurückgibt, bedeutet das, dass der Headroom in 30 Sekunden voraussichtlich 0,8 erreichen wird. Das ist 0,2 entfernt von einer starken Drosselung (1,0). Wenn die Zeit kürzer ist als die Zeit, die zum Ausführen der Arbeitslast erforderlich ist, sollte dein Spiel die Arbeitslast auf ein nachhaltiges Niveau reduzieren. Das Spiel kann beispielsweise die Framerate oder die Qualität verringern oder die Netzwerkverbindung reduzieren.

Temperaturstatus und Bedeutung

Geräteeinschränkungen der Thermal API

Aufgrund der Implementierung der Thermal API auf älteren Geräten gibt es einige bekannte Einschränkungen oder zusätzliche Anforderungen. Die Einschränkungen und Möglichkeiten, sie zu umgehen, sind:

  • Rufen Sie die GetThermalHeadroom() API nicht zu häufig auf. In diesem Fall gibt die API NaN zurück. Sie sollten sie nicht öfter als einmal alle 10 Sekunden aufrufen.
  • Vermeiden Sie Aufrufe von mehreren Threads aus, da es schwieriger ist, die Aufrufhäufigkeit zu gewährleisten. Außerdem kann es dazu führen, dass die API NaN zurückgibt.
  • 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 mehr) und GetCurrentThermalStatus() weiterhin THERMAL_STATUS_NONE zurückgibt, wird der Status wahrscheinlich nicht aktualisiert. Verwenden Sie Heuristiken, um den richtigen Status für die thermische Drosselung zu schätzen, oder verwenden Sie einfach getThermalHeadroom() ohne getCurrentThermalStatus().

Beispiel für Heuristik:

  1. Prüfe, ob die Thermal API unterstützt wird. Mit isAPISupported() wird der Wert des ersten Aufrufs von getThermalHeadroom geprüft, um sicherzustellen, dass er nicht 0 oder NaN ist. Wenn der erste Wert 0 oder NaN ist, wird die API nicht verwendet.
  2. Wenn getCurrentThermalStatus() einen anderen Wert als THERMAL_STATUS_NONE zurückgibt, wird die Leistung des Geräts aufgrund von Überhitzung gedrosselt.
  3. Wenn getCurrentThermalStatus() immer wieder THERMAL_STATUS_NONE zurückgibt, bedeutet das nicht unbedingt, dass die Leistung des Geräts nicht durch thermisches Drosseln eingeschränkt wird. Das kann bedeuten, dass getCurrentThermalStatus() auf dem Gerät nicht unterstützt wird. Prüfen Sie den Rückgabewert von getThermalHeadroom(), um den Zustand des Geräts zu ermitteln.
  4. Wenn getThermalHeadroom() einen Wert von > 1,0 zurückgibt, könnte der Status tatsächlich THERMAL_STATUS_SEVERE oder höher sein. Reduzieren Sie die Arbeitslast sofort und halten Sie sie auf einem niedrigeren Niveau, bis getThermalHeadroom() einen niedrigeren Wert zurückgibt.
  5. Wenn getThermalHeadroom() den Wert 0,95 zurückgibt, kann der Status tatsächlich THERMAL_STATUS_MODERATE oder höher sein. Reduzieren Sie die Arbeitslast sofort und behalten Sie die Situation im Auge, um höhere Werte zu vermeiden.
  6. Wenn getThermalHeadroom() einen Wert von 0,85 zurückgibt, könnte der Status tatsächlich THERMAL_STATUS_LIGHT sein. Behalten Sie die Situation im Auge und reduzieren Sie die Arbeitslast, wenn möglich.

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-Heuristik
Beispiel
Abbildung 3. Beispiel für eine Heuristik zur Bestimmung der Thermal API-Unterstützung auf älteren Geräten