Administración de energía de las apps

En Android 9 y versiones posteriores, la plataforma puede supervisar apps para detectar comportamientos que afecta negativamente la duración de la batería de los dispositivos. La plataforma usa y y evalúa las reglas de configuración para brindar un flujo de UX restringir las apps que infrinjan las reglas.

En Android 8.0 y versiones anteriores, había restricciones a través de funciones como Descanso, App Standby, límites en segundo plano y ubicación en segundo plano límites. Sin embargo, algunas apps siguieron mostrando comportamientos inadecuados, algunas de que se describen en Android vitals. Android 9 introdujo una infraestructura de SO que puede detectar y restringir apps basadas en reglas de configuración que pueden actualizarse con el tiempo.

Restricciones en segundo plano

Los usuarios pueden restringir aplicaciones o el sistema puede sugerir aplicaciones que detecta que tienen un impacto negativo en el estado del dispositivo.

Apps restringidas:

  • El usuario aún puede iniciarla.
  • No puede ejecutar trabajos ni alarmas, ni usar la red en segundo plano.
  • No se pueden ejecutar servicios en primer plano.
  • El usuario puede cambiar a una app sin restricciones.

Los implementadores de dispositivos pueden agregar restricciones adicionales a las apps para lo siguiente:

  • Impedir que la app se reinicie automáticamente
  • Restringe los servicios para que no se vinculen (muy riesgoso).

No se espera que las apps restringidas en segundo plano consuman recursos del dispositivo, como memoria, CPU y batería. Las apps con restricción en segundo plano no deberían afectar el estado del dispositivo cuando el usuario no usa activamente esas apps. Sin embargo, se espera que las mismas apps sea completamente funcional cuando el usuario inicia las aplicaciones.

Usa implementaciones personalizadas

Los implementadores de dispositivos pueden seguir usando sus métodos personalizados para aplicar restricciones en las apps.

Cómo integrar restricciones de apps

En las siguientes secciones, se describe cómo definir e integrar apps restricciones en tu dispositivo. Si usas métodos de restricción de apps desde Android 8.x o versiones anteriores, revisa atentamente las siguientes secciones para cambios en Android 9 y versiones posteriores.

Configura la marca AppOpsManager

Cuando se restringe una app, establece la marca correspondiente en AppOpsManager Un ejemplo de fragmento de código de 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);
    }

Asegúrate de que isBackgroundRestricted muestre el valor true

Cuando se restrinja una app, asegúrate de que ActivityManager.isBackgroundRestricted() muestra true.

Registra el motivo de la restricción.

Cuando se restringe una app, registra los motivos de la restricción. Los ejemplo de fragmento de código de registro desde 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));
  }

Reemplaza type por el valor de AnomalyType.

Los implementadores de dispositivos pueden usar las constantes definidas en 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;
    }

Cuando el usuario o el sistema quitan las restricciones de una app, debes registrar los motivos por los que se quitaron las restricciones. Un ejemplo de fragmento de código de registro desde 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));
    }

Cómo probar las restricciones de apps

Para probar el comportamiento de las restricciones de apps en Android 9 y versiones posteriores, usa uno de los los siguientes comandos:

  • Restringe una app:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Quita una app de la restricción y restablece el comportamiento predeterminado:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Haz que una app en segundo plano quede inactiva de inmediato:
    am make-uid-idle [--user user-id | all | current] package-name
  • Agrega un paquete a tempwhitelist durante un período breve:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Agrega o quita un paquete de la lista blanca del usuario:
    cmd deviceidle whitelist [+/-]package-name
  • Verifica el estado interno de jobscheduler y el administrador de alarmas:
    dumpsys jobscheduler
    dumpsys alarm

App Standby

App Standby prolonga la duración de batería aplazando la red en segundo plano la actividad y los trabajos de las apps que el usuario no usa de forma activa.

Ciclo de vida de App Standby

La plataforma detecta apps inactivas y las ubica en la app. en espera hasta que el usuario comience a interactuar activamente con la aplicación.

Durante la fase de detección, la plataforma detecta que una app está inactiva cuando El dispositivo no se está cargando y el usuario no inició la app directamente. de forma indirecta por una cantidad específica de tiempo de reloj, así como por una cantidad específica de tiempo de pantalla encendida. (Los lanzamientos indirectos ocurren cuando una app en primer plano accede a un servicio en una segunda app).

Durante App Standby, la plataforma evita que las apps accedan más a la red. más de una vez al día y aplazando sincronizaciones de aplicaciones y otros trabajos.

La plataforma saldrá de la app del modo en espera en las siguientes situaciones:

  • Se activa la app.
  • El dispositivo está enchufado y cargándose.

Las apps activas no se ven afectadas por App Standby. Una app se considera activa cuando tiene lo siguiente:

  • Un proceso actualmente en primer plano (ya sea como una actividad o servicio en primer plano, o bien en uso por parte de otra actividad o servicio en primer plano), como el objeto de escucha de notificaciones, los servicios de accesibilidad, los fondos animados, etcétera.
  • Una notificación vista por el usuario, como en la pantalla de bloqueo o bandeja de notificaciones
  • Que el usuario la inició de manera explícita

La app está inactiva si no se produjo ninguna de las actividades anteriores durante un período un plazo determinado.

Cómo probar App Standby

Puedes probar manualmente App Standby con el siguiente comando adb comandos:

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