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](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_pre-integration.png?authuser=7&hl=pl)
![Po integracji interfejsu ADPF Thermal API](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_thermal_post-integration.png?authuser=7&hl=pl)
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
- Jeśli urządzenie nie jest ograniczone termicznie:
- Niewielkie ograniczanie, ale nie ma istotnego wpływu na wydajność:
- Znaczne ograniczanie, które wpływa na wydajność:
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), aGetCurrentThermalStatus()
nadal zwraca wartośćTHERMAL_STATUS_NONE
, stan prawdopodobnie nie został zaktualizowany. Użyj heurystyki, aby oszacować prawidłowy stan ograniczania temperatury, lub użyj funkcjigetThermalHeadroom()
bez funkcjigetCurrentThermalStatus()
.
Przykład użycia heurystyki:
- Sprawdź, czy interfejs Thermal API jest obsługiwany.
isAPISupported()
sprawdza wartość pierwszego wywołaniagetThermalHeadroom
, aby upewnić się, że nie ma wartości 0 ani NaN, i pomija wartość 0 lub NaN przy użyciu interfejsu API. - Jeśli
getCurrentThermalStatus()
zwraca wartość inną niżTHERMAL_STATUS_NONE
, urządzenie jest ograniczone termicznie. - Jeśli
getCurrentThermalStatus()
stale zwracaTHERMAL_STATUS_NONE
, nie musi to oznaczać, że urządzenie nie jest ograniczane termicznie. Może to oznaczać, że aplikacjagetCurrentThermalStatus()
nie jest obsługiwana na urządzeniu. Sprawdź zwracaną wartośćgetThermalHeadroom()
, aby upewnić się, że urządzenie jest w dobrym stanie. - 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ókigetThermalHeadroom()
nie zwróci niższej wartości - 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 - 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: