Gestione dell'alimentazione delle app

In Android 9 e versioni successive, la piattaforma può monitorare il comportamento delle app influisce negativamente sulla durata della batteria dei dispositivi. La piattaforma utilizza e valuta le regole di configurazione per fornire un flusso UX che consenta agli utenti di Limitare le app che violano le regole.

In Android 8.0 e versioni precedenti, erano presenti limitazioni relative alle funzionalità come sospensione, standby delle app, limiti in background e posizione in background limiti. Tuttavia, alcune app hanno continuato a mostrare comportamenti dannosi e alcune descritti in Android vitals. Android 9 ha introdotto un'infrastruttura del sistema operativo in grado di rilevare e limitare alle app in base a regole di configurazione che possono essere aggiornate nel tempo.

Limitazioni in background

Gli utenti possono limitare le app o il sistema potrebbe suggerirle app rileva un impatto negativo sull'integrità del dispositivo.

App con limitazioni:

  • Può ancora essere avviato dall'utente.
  • Non può eseguire job/sveglie o utilizzare la rete in background.
  • Impossibile eseguire i servizi in primo piano.
  • Può essere modificato dall'utente in un'app senza restrizioni.

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

  • Limita i riavvii automatici dell'app.
  • Limitare l'associazione dei servizi (altamente rischioso).

Non è previsto il consumo delle risorse del dispositivo da parte delle app con limitazioni in background, ad esempio di memoria, CPU e batteria. Le app con limitazioni in background non dovrebbero influire sull'integrità del dispositivo quando l'utente non utilizza attivamente queste app. Tuttavia, si prevede che le stesse app completamente funzionante quando l'utente avvia le app.

Utilizzare implementazioni personalizzate

Gli utenti che implementano i dispositivi possono continuare a utilizzare i propri metodi personalizzati per applicare limitazioni alle app.

Integrare le limitazioni delle app

Le seguenti sezioni descrivono come definire e integrare le app limitazioni applicate al tuo dispositivo. Se usi metodi di limitazione delle app da Android 8.x o versioni precedenti, rivedi attentamente le sezioni seguenti per cambiamenti in Android 9 e versioni successive.

Imposta il flag AppOpsManager

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

Assicurati che isBackgroundRestricted restituisca true

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

Registra il motivo della limitazione

Quando un'app è limitata, registra i motivi della limitazione. Un di esempio di snippet di codice di logging 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 utenti che implementano i dispositivi 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 rimuovono le restrizioni di un'app, devi: Registra i motivi della rimozione delle restrizioni. Esempio di snippet di codice di logging 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));
    }

Testare le limitazioni delle app

Per testare il comportamento delle limitazioni delle app in Android 9 e versioni successive, usa una delle seguenti comandi:

  • Limitare un'app:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Rimuovi le restrizioni di un'app e ripristina il comportamento predefinito:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Per disattivare immediatamente un'app in background:
    am make-uid-idle [--user user-id | all | current] package-name
  • Aggiungi un pacchetto a tempwhitelist per un breve periodo di tempo:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Aggiungi/rimuovi un pacchetto dalla lista consentita degli utenti:
    cmd deviceidle whitelist [+/-]package-name
  • Controlla lo stato interno di jobscheduler e di Gestione sveglie:
    dumpsys jobscheduler
    dumpsys alarm

Standby delle app

La modalità standby delle app prolunga la durata della batteria posticipando la rete in background le attività e i lavori per le app che l'utente non sta utilizzando attivamente.

Ciclo di vita dell'app in standby

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

Durante la fase di rilevamento, la piattaforma rileva che un'app non è attiva quando Il dispositivo non si carica e l'utente non ha avviato l'app direttamente o indirettamente per una determinata quantità di tempo di orologio e per una determinata quantità di tempo di attivazione dello schermo. Gli avvii indiretti si verificano quando un'app in primo piano accede a un servizio in una seconda app.

Quando è attivo lo standby delle app, la piattaforma impedisce maggiormente alle app di accedere alla rete di una volta al giorno, posticipando le sincronizzazioni delle app e altri job.

La piattaforma esce dall'app in standby quando:

  • L'app diventa attiva.
  • Il dispositivo è collegato alla corrente ed è in carica.

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

  • Un processo attualmente in primo piano (come un'attività o servizio in primo piano o utilizzato da un'altra attività o servizio in primo piano), come listener di notifiche, servizi di accessibilità, sfondo animato e così via.
  • Una notifica visualizzata dall'utente, ad esempio nella schermata di blocco o barra delle notifiche
  • Essere state lanciate esplicitamente dall'utente.

Un'app è inattiva se non si è verificata nessuna delle attività precedenti per un determinato periodo del tempo.

Prova standby dell'app

Puoi testare manualmente lo standby dell'app utilizzando il seguente 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