Thermal API

Data wydania:

Android 11 (poziom interfejsu API 30) – Thermal API

Android 12 (poziom API 31) – NDK API

(Wersja testowa) Android 15 (DP1) – getThermalHeadroomThresholds()

Potencjalna wydajność aplikacji jest ograniczona przez stan termiczny urządzenia, który może się zmieniać w zależności od takich czynników jak pogoda, ostatnie użycie czy konstrukcja termiczna urządzenia. Urządzenia mogą utrzymać wysoką wydajność tylko przez ograniczony czas, zanim zostaną objęte ograniczeniem termicznym. Kluczowym celem wdrożenia powinno być osiągnięcie celów związanych z wydajnością bez przekraczania ograniczeń termicznych. Thermal API pozwala na to bez optymalizacji pod kątem konkretnych urządzeń. Ponadto podczas debugowania problemów z wydajnością ważna jest wiedza o tym, czy temperatura termiczna urządzenia ogranicza wydajność. Ponadto podczas debugowania problemów z wydajnością ważna jest wiedza o tym, czy temperatura termiczna urządzenia ogranicza wydajność.

Mechanizmy gier zwykle mają parametry wydajności w czasie działania, które pozwalają dostosować obciążenie pracą nakładane na urządzenie. Te parametry mogą na przykład określać liczbę wątków instancji roboczych, koligację wątków instancji roboczych z dużymi i małymi rdzeniami, opcje wierności procesora graficznego i rozdzielczości bufora ramki. W Unity Engine deweloperzy gier mogą dostosowywać zadanie, zmieniając ustawienia jakości za pomocą wtyczki adaptacyjnej wydajności. W przypadku platformy Unreal Engine użyj ustawień skalowalności, aby dynamicznie dostosowywać poziomy jakości.

Gdy urządzenie zbliża się do niebezpiecznego stanu termicznego, gra może uniknąć ograniczenia przepustowości, zmniejszając obciążenie za pomocą tych parametrów. Aby uniknąć ograniczania, monitoruj temperaturę urządzenia i aktywnie dostosuj obciążenie silnika gry. Gdy urządzenie się przegrzeje, zadanie musi spaść poniżej poziomu zrównoważonego, aby można było odprowadzać ciepło. Gdy limit temperatury spadnie do bezpieczniejszego poziomu, gra może ponownie zwiększyć ustawienia jakości, ale pamiętaj, aby znaleźć zrównoważony poziom jakości, który zapewni optymalny czas gry.

Stan temperatury urządzenia możesz sprawdzać, wysyłając odpytywanie metody getThermalHeadroom. Ta metoda przewiduje, jak długo urządzenie może utrzymać bieżący poziom wydajności bez przegrzania. Jeśli czas jest krótszy niż ilość potrzebna do uruchomienia zadania, gra powinna zmniejszyć to zadanie do poziomu zrównoważonego. Na przykład gra może korzystać z mniejszych rdzeni, zmniejszyć liczbę klatek lub uzyskać niższą jakość.

Wstępna integracja interfejsu ADPF Thermal API
Rysunek 1. Zasobnik termiczny bez aktywnego monitorowania getThermalHeadroom
Po integracji interfejsu ADPF Thermal API
Rysunek 2. Funkcja termiczna z aktywnym monitorowaniem urządzenia „getThermalHeadroom”

Kup menedżera termicznego

Aby korzystać z Thermal API, musisz najpierw pozyskać Thermal Manager

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

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

Przygotuj prognozowanie zapasu termalnego x sekund do przodu, aby mieć większą kontrolę

Możesz poprosić system o prognozowanie temperatury na x sekund do przodu w ramach bieżącego zadania. Daje to bardziej szczegółową kontrolę i więcej czasu na reakcję, ponieważ zmniejsza obciążenie pracą, aby zapobiegać włączeniu ograniczania ciepła.

Wynik może wynosić od 0,0f (bez ograniczania, THERMAL_STATUS_NONE) do 1,0f (mocne ograniczanie: THERMAL_STATUS_SEVERE). Jeśli w grach korzystasz z różnych poziomów jakości grafiki, postępuj zgodnie z naszymi wskazówkami dotyczącymi wykorzystania termometru.

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

Aby dowiedzieć się więcej, możesz też użyć stanu termicznego

Każdy model urządzenia może być zaprojektowany w inny sposób. Niektóre urządzenia lepiej rozprowadzają ciepło, dzięki czemu są w stanie lepiej wytrzymać większe pole manewru w obszarze temperatury, zanim zostaną ograniczone. Jeśli chcesz odczytać w formie uproszczonej grupy zakresów zapasu termicznego, możesz sprawdzić stan termiczny, aby poznać wartość zapasu termicznego obecnego urządzenia.

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

Otrzymuj powiadomienia o zmianach stanu termicznego

Możesz też unikać odpytywania thermalHeadroom do momentu, aż thermalStatus osiągnie określony poziom (np. THERMAL_STATUS_LIGHT). W tym celu możesz zarejestrować wywołanie zwrotne, dzięki któremu system powiadomi Cię o zmianie stanu.

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

Pamiętaj, żeby usunąć słuchacza, gdy skończysz

C++

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

Java

powerManager.removeThermalStatusListener(listener);

Uporządkuj

Gdy skończysz, wyczyść nabyte przez siebie urządzenie Thermostat_manager. Jeśli używasz Javy, odniesienie do PowerManagera może być automatycznie usuwane. Jeśli jednak używasz interfejsu JNI w środowisku Java API i zachowasz odwołanie, pamiętaj o wyczyszczeniu go.

C++

AThermal_releaseManager(thermal_manager);

Pełny przewodnik wdrażania interfejsu Thermal API w natywnej grze w C++ za pomocą interfejsu C++ API (NDK API) i interfejsu Java API (za pomocą JNI) znajdziesz w sekcji o Integrated Thermal API w sekcji Ćwiczenia z programowania.

Wytyczne dotyczące rezerwy termalnej

Stan temperatury urządzenia możesz sprawdzać, wysyłając odpytywanie metody getThermalHeadroom. Ta metoda przewiduje, jak długo urządzenie może utrzymać bieżący poziom wydajności, zanim osiągnie wartość THERMAL_STATUS_SEVERE. Jeśli np. getThermalHeadroom(30) zwraca wartość 0,8, oznacza to, że w ciągu 30 sekund pole manewru powinno osiągnąć wartość 0,8, czyli 0,2 odległości od silnego ograniczania (1,0). Jeśli czas jest krótszy niż ilość potrzebna do uruchomienia zadania, gra powinna zmniejszyć to obciążenie do zrównoważonego poziomu. Na przykład gra może zmniejszyć liczbę klatek, jakość lub połączenie z siecią.

Stany termiczne i znaczenie

Ograniczenia interfejsu Thermal API dotyczące urządzeń

Istnieją pewne znane ograniczenia lub dodatkowe wymagania interfejsu Thermal API z powodu implementacji tego interfejsu na starszych urządzeniach. Ograniczenia i sposoby ich obchodzenia:

  • Nie wywołuj zbyt często interfejsu API GetThermalHeadroom(). Spowoduje to zwrócenie przez API wartości NaN. Wywołuj je nie częściej niż raz na sekundę.
  • Jeśli wartością początkową GetThermalHeadroom() jest NaN, interfejs API nie jest dostępny na urządzeniu
  • Jeśli GetThermalHeadroom() zwraca wysoką wartość (np. 0,85 lub więcej), a GetCurrentThermalStatus() nadal zwraca wartość THERMAL_STATUS_NONE, stan prawdopodobnie nie został zaktualizowany. Użyj heurystyki, aby oszacować prawidłowy stan ograniczania temperatury, lub użyj funkcji getThermalHeadroom() bez funkcji getCurrentThermalStatus().

Przykład użycia heurystyki:

  1. Sprawdź, czy interfejs Thermal API jest obsługiwany. isAPISupported() sprawdza wartość pierwszego wywołania getThermalHeadroom, aby upewnić się, że nie ma wartości 0 ani NaN, i pomija wartość 0 lub NaN przy użyciu interfejsu API.
  2. Jeśli getCurrentThermalStatus() zwraca wartość inną niż THERMAL_STATUS_NONE, urządzenie jest ograniczone termicznie.
  3. Jeśli getCurrentThermalStatus() stale zwraca THERMAL_STATUS_NONE, nie musi to oznaczać, że urządzenie nie jest ograniczane termicznie. Może to oznaczać, że aplikacja getCurrentThermalStatus() nie jest obsługiwana na urządzeniu. Sprawdź zwracaną wartość getThermalHeadroom(), aby upewnić się, że urządzenie jest w dobrym stanie.
  4. Jeśli getThermalHeadroom() zwraca wartość większą niż 1,0, stan może wynosić THERMAL_STATUS_SEVERE lub więcej, natychmiast zmniejsz obciążenie i utrzymaj jego mniejszą wartość, dopóki getThermalHeadroom() nie zwróci niższej wartości
  5. Jeśli getThermalHeadroom() zwraca wartość 0,95, stan może wynosić THERMAL_STATUS_MODERATE lub więcej, natychmiast zmniejsz obciążenie i zachowaj czujność, aby zapobiec zwiększeniu odczytu
  6. Jeśli getThermalHeadroom() zwraca wartość 0, 85, stan może w rzeczywistości mieć wartość THERMAL_STATUS_LIGHT.Zachowaj czujność i w miarę możliwości zmniejsz obciążenie

Pseudokod:

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

Schemat:

Przykład heurystyki ADPF
Rysunek 3. Przykład użycia heurystyki do określania obsługi interfejsu Thermal API na starszych urządzeniach