Zarządzanie energią aplikacji

W systemie Android 9 i nowszych platforma może monitorować aplikacje pod kątem zachowań, które negatywnie wpływają na żywotność baterii urządzeń. Platforma używa i ocenia reguły konfiguracji, aby zapewnić przepływ UX, który daje użytkownikom możliwość ograniczenia aplikacji, które naruszają reguły.

W systemie Android 8.0 i wcześniejszych obowiązywały ograniczenia związane z takimi funkcjami, jak drzemka, czuwanie aplikacji, limity w tle i limity lokalizacji w tle. Jednak niektóre aplikacje nadal wykazywały złe zachowania, z których niektóre są opisane w Android Vitals . Android 9 wprowadził infrastrukturę systemu operacyjnego, która może wykrywać i ograniczać aplikacje na podstawie reguł konfiguracji, które mogą być aktualizowane w czasie.

Ograniczenia w tle

Użytkownicy mogą ograniczać aplikacje lub system może sugerować aplikacje, które wykryje, negatywnie wpływające na stan urządzenia.

Ograniczone aplikacje:

  • Nadal może zostać uruchomiony przez użytkownika.
  • Nie można uruchamiać zadań / alarmów ani korzystać z sieci w tle.
  • Nie można uruchomić usług pierwszego planu.
  • Może zostać zmieniona na nieograniczoną aplikację przez użytkownika.

Implementatorzy urządzeń mogą dodawać dodatkowe ograniczenia do aplikacji, aby:

  • Ogranicz aplikację przed samodzielnym ponownym uruchomieniem.
  • Ogranicz usługi przed związaniem (wysoce ryzykowne).

Aplikacje działające w tle z ograniczeniami nie powinny zużywać żadnych zasobów urządzenia, takich jak pamięć, procesor i bateria. Aplikacje z ograniczeniami w tle nie powinny wpływać na stan urządzenia, gdy użytkownik nie korzysta z nich aktywnie. Oczekuje się jednak, że te same aplikacje będą w pełni funkcjonalne, gdy użytkownik je uruchomi.

Korzystanie z niestandardowych implementacji

Osoby wdrażające urządzenia mogą nadal używać swoich niestandardowych metod, aby nakładać ograniczenia na aplikacje.

Integracja ograniczeń aplikacji

W poniższych sekcjach opisano, jak definiować i integrować ograniczenia aplikacji na urządzeniu. Jeśli korzystasz z metod ograniczania aplikacji z systemu Android 8.x lub starszego, zapoznaj się dokładnie z poniższymi sekcjami pod kątem zmian w systemie Android 9 i nowszych.

Ustawianie flagi AppOpsManager

Gdy aplikacja jest ograniczona, ustaw odpowiednią flagę w AppOpsManager . Przykładowy fragment kodu z packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryUtils.java :

   public void setForceAppStandby(int uid, String packageName,
            int mode) {
        final boolean isPreOApp = isPreOApp(packageName);
        if (isPreOApp) {
       // Control whether app could run in the background if it is pre O app
            mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName, mode);
        }
       // Control whether app could run jobs in the background
        mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
    }

Zapewnienie, że isBackgroundRestricted zwraca wartość true

Gdy aplikacja jest ograniczona, upewnij się, że ActivityManager.isBackgroundRestricted() zwraca wartość true .

Rejestrowanie powodu ograniczenia

Gdy aplikacja jest ograniczona, zarejestruj przyczyny ograniczenia. Przykładowy fragment kodu logowania z packages/apps/Settings/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java :

mBatteryUtils.setForceAppStandby(mBatteryUtils.getPackageUid(packageName), packageName,AppOpsManager.MODE_IGNORED);
if (CollectionUtils.isEmpty(appInfo.anomalyTypes)) {
  // Only log context if there is no anomaly type
  mMetricsFeatureProvider.action(mContext,
    MetricsProto.MetricsEvent.ACTION_TIP_RESTRICT_APP, packageName,
    Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT,metricsKey));
            } else {
  // Log ALL the anomaly types
  for (int type : appInfo.anomalyTypes) {
    mMetricsFeatureProvider.action(mContext,
      MetricsProto.MetricsEvent.ACTION_TIP_RESTRICT_APP, packageName,
      Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, metricsKey),
      Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, type));
  }

Zastąp type wartością z AnomalyType .

Osoby wdrażające urządzenia mogą korzystać ze stałych zdefiniowanych w src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java :

public @interface AnomalyType {
        // This represents an error condition in the anomaly detection.
        int NULL = -1;
         // The anomaly type does not match any other defined type.
        int UNKNOWN_REASON = 0;
         // The application held a partial (screen off) wake lock for a period of time that
         // exceeded the threshold with the screen off when not charging.
        int EXCESSIVE_WAKELOCK_ALL_SCREEN_OFF = 1;
         // The application exceeded the maximum number of wakeups while in the background
         // when not charging.
        int EXCESSIVE_WAKEUPS_IN_BACKGROUND = 2;
         // The application did unoptimized Bluetooth scans too frequently when not charging.
        int EXCESSIVE_UNOPTIMIZED_BLE_SCAN = 3;
         // The application ran in the background for a period of time that exceeded the
         // threshold.
        int EXCESSIVE_BACKGROUND_SERVICE = 4;
         // The application exceeded the maximum number of wifi scans when not charging.
        int EXCESSIVE_WIFI_SCAN = 5;
         // The application exceed the maximum number of flash writes
        int EXCESSIVE_FLASH_WRITES = 6;
         // The application used more than the maximum memory, while not spending any time
         // in the foreground.
        int EXCESSIVE_MEMORY_IN_BACKGROUND = 7;
         // The application exceeded the maximum percentage of frames with a render rate of
         // greater than 700ms.
        int EXCESSIVE_DAVEY_RATE = 8;
         // The application exceeded the maximum percentage of frames with a render rate
         // greater than 16ms.
        int EXCESSIVE_JANKY_FRAMES = 9;
         // The application exceeded the maximum cold start time - the app has not been
         // launched since last system start, died or was killed.
        int SLOW_COLD_START_TIME = 10;
         // The application exceeded the maximum hot start time - the app and activity are
         // already in memory.
        int SLOW_HOT_START_TIME = 11;
         // The application exceeded the maximum warm start time - the app was already in
         // memory but the activity wasn't created yet or was removed from memory.
        int SLOW_WARM_START_TIME = 12;
         // The application exceeded the maximum number of syncs while in the background.
        int EXCESSIVE_BACKGROUND_SYNCS = 13;
         // The application exceeded the maximum number of gps scans while in the background.
        int EXCESSIVE_GPS_SCANS_IN_BACKGROUND = 14;
         // The application scheduled more than the maximum number of jobs while not charging.
        int EXCESSIVE_JOB_SCHEDULING = 15;
         // The application exceeded the maximum amount of mobile network traffic while in
         // the background.
        int EXCESSIVE_MOBILE_NETWORK_IN_BACKGROUND = 16;
         // The application held the WiFi lock for more than the maximum amount of time while
         // not charging.
        int EXCESSIVE_WIFI_LOCK_TIME = 17;
         // The application scheduled a job that ran longer than the maximum amount of time.
        int JOB_TIMED_OUT = 18;
         // The application did an unoptimized Bluetooth scan that exceeded the maximum
         // time while in the background.
        int LONG_UNOPTIMIZED_BLE_SCAN = 19;
         // The application exceeded the maximum ANR rate while in the background.
        int BACKGROUND_ANR = 20;
         // The application exceeded the maximum crash rate while in the background.
        int BACKGROUND_CRASH_RATE = 21;
         // The application exceeded the maximum ANR-looping rate.
        int EXCESSIVE_ANR_LOOPING = 22;
         // The application exceeded the maximum ANR rate.
        int EXCESSIVE_ANRS = 23;
         // The application exceeded the maximum crash rate.
        int EXCESSIVE_CRASH_RATE = 24;
         // The application exceeded the maximum crash-looping rate.
        int EXCESSIVE_CRASH_LOOPING = 25;
         // The application crashed because no more file descriptors were available.
        int NUMBER_OF_OPEN_FILES = 26;
    }

Gdy użytkownik lub system usunie ograniczenia aplikacji, należy zarejestrować przyczyny usunięcia ograniczeń. Przykładowy fragment kodu logowania z packages/apps/Settings/src/com/android/settings/fuelgauge/batterytip/actions/UnrestrictAppAction.java :

public void handlePositiveAction(int metricsKey) {
        final AppInfo appInfo = mUnRestrictAppTip.getUnrestrictAppInfo();
        // Clear force app standby, then app can run in the background
        mBatteryUtils.setForceAppStandby(appInfo.uid, appInfo.packageName,
                AppOpsManager.MODE_ALLOWED);
        mMetricsFeatureProvider.action(mContext,
                MetricsProto.MetricsEvent.ACTION_TIP_UNRESTRICT_APP, appInfo.packageName,
                Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, metricsKey));
    }

Testowanie ograniczeń aplikacji

Aby przetestować zachowanie ograniczeń aplikacji w systemie Android 9 i nowszych, użyj jednego z następujących poleceń:

  • Ogranicz aplikację:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Wyłącz aplikację z ograniczeń i przywróć zachowanie domyślne:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Spraw, aby aplikacja działająca w tle natychmiast przechodziła w stan bezczynności:
    am make-uid-idle [--user user-id | all | current] package-name
  • Dodaj pakiet do tempwhitelist na krótki czas:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Dodaj / usuń pakiet z białej listy użytkowników:
    cmd deviceidle whitelist [+/-]package-name
  • Sprawdź stan wewnętrzny jobscheduler i menedżera alarmów:
    dumpsys jobscheduler
    dumpsys alarm

Czuwanie aplikacji

Tryb gotowości aplikacji wydłuża żywotność baterii, odraczając aktywność sieciową w tle i zadania dla aplikacji, z których użytkownik aktywnie nie korzysta.

Cykl życia aplikacji w stanie gotowości

Platforma wykrywa nieaktywne aplikacje i umieszcza je w trybie gotowości do czasu, gdy użytkownik zacznie aktywnie korzystać z aplikacji.

Podczas fazy wykrywania platforma wykrywa, że ​​aplikacja jest nieaktywna, gdy urządzenie się nie ładuje, a użytkownik nie uruchomił aplikacji bezpośrednio lub pośrednio przez określony czas zegara, a także przez określony czas na ekranie . (Uruchamiania pośrednie występują, gdy aplikacja pierwszego planu uzyskuje dostęp do usługi w drugiej aplikacji).

W trybie gotowości aplikacji platforma uniemożliwia aplikacjom dostęp do sieci więcej niż raz dziennie, odraczając synchronizację aplikacji i inne zadania.

Platforma opuszcza aplikację ze stanu wstrzymania, gdy:

  • Aplikacja staje się aktywna.
  • Urządzenie jest podłączone i ładuje się.

Tryb gotowości aplikacji nie ma wpływu na aktywne aplikacje. Aplikacja jest aktywna, gdy ma:

  • Proces znajdujący się obecnie na pierwszym planie (jako działanie lub usługa pierwszoplanowa lub używany przez inne działanie lub usługę pierwszoplanową), taki jak odbiornik powiadomień, usługi ułatwień dostępu, animowana tapeta itp.
  • Powiadomienie wyświetlane przez użytkownika, na przykład na ekranie blokady lub pasku powiadomień
  • Zostały wyraźnie uruchomione przez użytkownika

Aplikacja jest nieaktywna, jeśli żadne z powyższych działań nie miało miejsca przez pewien czas.

Testowanie czuwania aplikacji

Możesz ręcznie przetestować stan gotowości aplikacji za pomocą następujących poleceń adb :

adb shell dumpsys battery unplug
adb shell am set-idle package-name true
adb shell am set-idle package-name false
adb shell am get-idle package-name