App-Energieverwaltung

In Android 9 und höher kann die Plattform Apps auf Verhalten überwachen, das sich negativ auf die Akkulaufzeit von Geräten auswirkt. Die Plattform verwendet und wertet Setup-Regeln aus, um einen UX-Flow bereitzustellen, der Benutzern die Möglichkeit gibt, Apps einzuschränken, die gegen die Regeln verstoßen.

In Android 8.0 und niedriger gab es Einschränkungen durch Funktionen wie Doze, App-Standby, Hintergrundbeschränkungen und Hintergrundstandortbeschränkungen. Einige Apps zeigten jedoch weiterhin fehlerhaftes Verhalten, von dem einige in Android Vitals beschrieben werden. Mit Android 9 wurde eine Betriebssystem-Infrastruktur eingeführt, die Apps anhand von Setup-Regeln erkennen und einschränken kann, die im Laufe der Zeit aktualisiert werden können.

Hintergrundbeschränkungen

Benutzer können Apps einschränken, oder das System schlägt möglicherweise Apps vor, von denen es erkennt, dass sie sich negativ auf den Zustand des Geräts auswirken.

Eingeschränkte Apps:

  • Kann weiterhin vom Benutzer gestartet werden.
  • Es können keine Jobs/Alarme ausgeführt oder das Netzwerk im Hintergrund verwendet werden.
  • Vordergrunddienste können nicht ausgeführt werden.
  • Kann vom Benutzer in eine uneingeschränkte App geändert werden.

Geräteimplementierer können Apps zusätzliche Einschränkungen hinzufügen, um:

  • Beschränken Sie den Selbstneustart der App.
  • Beschränken Sie die Bindung von Diensten (sehr riskant).

Es wird nicht erwartet, dass eingeschränkte Apps im Hintergrund Geräteressourcen wie Speicher, CPU und Akku verbrauchen. Auf den Hintergrund beschränkte Apps sollten sich nicht auf den Gerätezustand auswirken, wenn der Benutzer diese Apps nicht aktiv nutzt. Es wird jedoch erwartet, dass dieselben Apps voll funktionsfähig sind, wenn der Benutzer die Apps startet.

Verwendung benutzerdefinierter Implementierungen

Geräteimplementierer können weiterhin ihre benutzerdefinierten Methoden verwenden, um Einschränkungen auf die Apps anzuwenden.

App-Einschränkungen integrieren

In den folgenden Abschnitten wird beschrieben, wie Sie App-Einschränkungen auf Ihrem Gerät definieren und integrieren. Wenn Sie App-Einschränkungsmethoden von Android 8.x oder niedriger verwenden, lesen Sie die folgenden Abschnitte sorgfältig auf Änderungen in Android 9 und höher.

Festlegen des AppOpsManager-Flags

Wenn eine App eingeschränkt ist, legen Sie das entsprechende Flag in AppOpsManager fest. Ein Beispiel-Codeausschnitt aus 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);
    }

Stellen Sie sicher, dass isBackgroundRestricted „true“ zurückgibt

Wenn eine App eingeschränkt ist, stellen Sie sicher, dass ActivityManager.isBackgroundRestricted() true zurückgibt.

Protokollierung des Grundes für die Einschränkung

Wenn eine App eingeschränkt ist, protokollieren Sie die Gründe für die Einschränkung. Ein Beispiel-Codeausschnitt der Protokollierung aus 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));
  }

Ersetzen Sie type durch den Wert von AnomalyType .

Geräteimplementierer können die in src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java definierten Konstanten verwenden:

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

Wenn der Benutzer oder das System die Einschränkungen einer App aufhebt, müssen Sie die Gründe für die Aufhebung der Einschränkungen protokollieren. Ein Beispiel-Codeausschnitt der Protokollierung aus 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));
    }

App-Einschränkungen testen

Um das Verhalten von App-Einschränkungen in Android 9 und höher zu testen, verwenden Sie einen der folgenden Befehle:

  • Setzen Sie eine App in die Einschränkung:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Heben Sie die Einschränkung für eine App auf und stellen Sie das Standardverhalten wieder her:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Lassen Sie eine App im Hintergrund sofort inaktiv werden:
    am make-uid-idle [--user user-id | all | current] package-name
  • Fügen Sie für kurze Zeit ein Paket zu tempwhitelist hinzu:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Ein Paket zur Benutzer-Whitelist hinzufügen/entfernen:
    cmd deviceidle whitelist [+/-]package-name
  • Überprüfen Sie den internen Status von jobscheduler und Alarmmanager:
    dumpsys jobscheduler
    dumpsys alarm

App-Standby

Der App-Standby verlängert die Akkulaufzeit, indem Hintergrundnetzwerkaktivitäten und Jobs für Apps, die der Benutzer nicht aktiv nutzt, zurückgestellt werden.

App-Standby-Lebenszyklus

Die Plattform erkennt inaktive Apps und versetzt sie in den App-Standby, bis der Benutzer beginnt, sich aktiv mit der App zu beschäftigen.

Während der Erkennungsphase erkennt die Plattform, dass eine App inaktiv ist, wenn das Gerät nicht aufgeladen wird und der Benutzer die App für eine bestimmte Uhrzeit sowie eine bestimmte Zeit, in der der Bildschirm eingeschaltet war, weder direkt noch indirekt gestartet hat . (Indirekte Starts erfolgen, wenn eine Vordergrund-App auf einen Dienst in einer zweiten App zugreift.)

Im App-Standby verhindert die Plattform, dass Apps mehr als einmal am Tag auf das Netzwerk zugreifen, wodurch App-Synchronisierungen und andere Aufgaben verzögert werden.

Die Plattform beendet die App aus dem Standby-Modus, wenn:

  • Die App wird aktiv.
  • Das Gerät ist angeschlossen und wird geladen.

Aktive Apps sind vom App-Standby nicht betroffen. Eine App ist aktiv , wenn sie Folgendes hat:

  • Ein Prozess, der sich derzeit im Vordergrund befindet (entweder als Aktivität oder Vordergrunddienst oder von einer anderen Aktivität oder einem anderen Vordergrunddienst verwendet), z. B. Benachrichtigungs-Listener, Barrierefreiheitsdienste, Live-Hintergrund usw.
  • Eine vom Benutzer angezeigte Benachrichtigung, z. B. im Sperrbildschirm oder in der Benachrichtigungsleiste
  • Wurde vom Benutzer explizit gestartet

Eine App ist inaktiv , wenn über einen bestimmten Zeitraum hinweg keine der oben genannten Aktivitäten stattgefunden hat.

App-Standby testen

Sie können den App-Standby manuell testen, indem Sie die folgenden adb Befehle verwenden:

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