Gestione energetica dell'app

In Android 9 e versioni successive, la piattaforma può monitorare i comportamenti delle app che influiscono negativamente sulla durata della batteria dei dispositivi. La piattaforma utilizza e valuta le regole di configurazione per fornire un flusso UX che offra agli utenti la possibilità di limitare le app che violano le regole.

In Android 8.0 e versioni precedenti erano presenti restrizioni tramite funzionalità come Doze, standby delle app, limiti in background e limiti di posizione in background. Tuttavia, alcune app hanno continuato a mostrare comportamenti scorretti, alcuni dei quali sono descritti in Android vitals . Android 9 ha introdotto un'infrastruttura del sistema operativo in grado di rilevare e limitare le app in base a regole di configurazione che possono essere aggiornate nel tempo.

Restrizioni di fondo

Gli utenti possono limitare le app oppure il sistema può suggerire che le app che rileva incidono negativamente sulla salute del dispositivo.

App limitate:

  • Può ancora essere avviato dall'utente.
  • Non è possibile eseguire lavori/allarmi o utilizzare la rete in background.
  • Impossibile eseguire servizi in primo piano.
  • Può essere modificata dall'utente in un'app senza restrizioni.

Gli implementatori dei dispositivi possono aggiungere ulteriori restrizioni alle app per:

  • Limita il riavvio automatico dell'app.
  • Limitare il vincolo dei servizi (altamente rischioso).

Non si prevede che le app con restrizioni in background consumino le risorse del dispositivo, come memoria, CPU e batteria. Le app con limitazioni in background non dovrebbero influire sull'integrità del dispositivo quando l'utente non le utilizza attivamente. Tuttavia, si prevede che le stesse app siano completamente funzionanti quando l'utente le avvia.

Utilizzo di implementazioni personalizzate

Gli implementatori dei dispositivi possono continuare a utilizzare i propri metodi personalizzati per applicare restrizioni alle app.

Integrazione delle restrizioni delle app

Le sezioni seguenti descrivono come definire e integrare le restrizioni delle app sul tuo dispositivo. Se utilizzi metodi di limitazione delle app da Android 8.x o versioni precedenti, esamina attentamente le sezioni seguenti per le modifiche in Android 9 e versioni successive.

Impostazione del flag AppOpsManager

Quando un'app è limitata, imposta il flag appropriato in AppOpsManager . Uno snippet di codice di esempio da 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);
    }

Assicurarsi che isBackgroundRestricted restituisca true

Quando un'app è limitata, assicurati che ActivityManager.isBackgroundRestricted() restituisca true .

Registrazione del motivo della restrizione

Quando un'app è soggetta a restrizioni, registra i motivi della limitazione. Un frammento di codice di esempio della registrazione da 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));
  }

Sostituisci type con il valore di AnomalyType .

Gli implementatori del dispositivo possono utilizzare le costanti definite in 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;
    }

Quando l'utente o il sistema rimuove le restrizioni di un'app, è necessario registrare i motivi della rimozione delle restrizioni. Un frammento di codice di esempio della registrazione da 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));
    }

Test delle restrizioni dell'app

Per testare il comportamento delle restrizioni delle app in Android 9 e versioni successive, utilizza uno dei seguenti comandi:

  • Metti un'app in restrizione:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Elimina le restrizioni per un'app e ripristina il comportamento predefinito:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Rendere immediatamente inattiva un'app in background:
    am make-uid-idle [--user user-id | all | current] package-name
  • Aggiungi un pacchetto a tempwhitelist per un breve periodo:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Aggiungi/rimuovi un pacchetto dalla whitelist dell'utente:
    cmd deviceidle whitelist [+/-]package-name
  • Controlla lo stato interno del jobscheduler e del gestore degli allarmi:
    dumpsys jobscheduler
    dumpsys alarm

Standby dell'applicazione

Lo standby delle app prolunga la durata della batteria rinviando l'attività di rete in background e i processi per le app che l'utente non utilizza attivamente.

Ciclo di vita in standby dell'app

La piattaforma rileva le app inattive e le mette in standby finché l'utente non inizia a interagire attivamente con l'app.

Durante la fase di rilevamento , la piattaforma rileva che un'app è inattiva quando il dispositivo non è in carica e l'utente non ha avviato l'app direttamente o indirettamente per un determinato periodo di tempo di orologio e per un determinato periodo di tempo di visualizzazione. . (I lanci indiretti si verificano quando un'app in primo piano accede a un servizio in una seconda app.)

Durante lo standby delle app , la piattaforma impedisce alle app di accedere alla rete più di una volta al giorno, rinviando la sincronizzazione delle app e altri lavori.

La piattaforma esce dall'app dallo standby quando:

  • L'app diventa attiva.
  • Il dispositivo è collegato e in carica.

Le app attive non sono influenzate dallo standby delle app. Un'app è attiva quando ha:

  • Un processo attualmente in primo piano (come attività o servizio in primo piano oppure utilizzato da un'altra attività o servizio in primo piano), ad esempio ascoltatore di notifiche, servizi di accessibilità, sfondi animati e così via.
  • Una notifica visualizzata dall'utente, ad esempio nella schermata di blocco o nella barra delle notifiche
  • È stato lanciato esplicitamente dall'utente

Un'app è inattiva se nessuna delle attività sopra indicate si è verificata per un periodo di tempo.

Test dello standby dell'app

Puoi testare manualmente lo standby dell'app utilizzando i seguenti comandi 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