Administración de energía de la aplicación

En Android 9 y versiones posteriores, la plataforma puede monitorear las aplicaciones en busca de comportamientos que afecten negativamente la duración de la batería de los dispositivos. La plataforma usa y evalúa las reglas de configuración para proporcionar un flujo de experiencia de usuario que brinda a los usuarios la opción de restringir las aplicaciones que violan las reglas.

En Android 8.0 y versiones anteriores, había restricciones a través de funciones como Doze, aplicación en espera, límites de fondo y límites de ubicación de fondo. Sin embargo, algunas aplicaciones continuaron mostrando malos comportamientos, algunos de los cuales se describen en Android vitals . Android 9 introdujo una infraestructura de sistema operativo que puede detectar y restringir aplicaciones según las reglas de configuración que se pueden actualizar con el tiempo.

Restricciones de fondo

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

Aplicaciones restringidas:

  • Todavía puede ser lanzado por el usuario.
  • No se pueden ejecutar trabajos/alarmas ni utilizar la red en segundo plano.
  • No se pueden ejecutar servicios en primer plano.
  • El usuario puede cambiar a una aplicación sin restricciones.

Los implementadores de dispositivos pueden agregar restricciones adicionales a las aplicaciones para:

  • Restrinja la aplicación de reinicios automáticos.
  • Restringir los servicios para que no estén vinculados (alto riesgo).

No se espera que las aplicaciones restringidas en segundo plano consuman ningún recurso del dispositivo, como memoria, CPU y batería. Las aplicaciones restringidas en segundo plano no deberían afectar el estado del dispositivo cuando el usuario no está usando activamente esas aplicaciones. Sin embargo, se espera que las mismas aplicaciones sean completamente funcionales cuando el usuario las inicie.

Uso de implementaciones personalizadas

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

Integración de restricciones de aplicaciones

Las siguientes secciones describen cómo definir e integrar restricciones de aplicaciones en su dispositivo. Si está utilizando métodos de restricción de aplicaciones de Android 8.x o inferior, revise las siguientes secciones detenidamente para conocer los cambios en Android 9 y superior.

Configuración del indicador AppOpsManager

Cuando una aplicación está restringida, configure el indicador apropiado en AppOpsManager . Un fragmento de código de ejemplo 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);
    }

Asegurarse de que isBackgroundRestricted devuelva verdadero

Cuando una aplicación está restringida, asegúrese de que ActivityManager.isBackgroundRestricted() devuelva true .

Registro del motivo de la restricción

Cuando una aplicación está restringida, registre los motivos de la restricción. Un fragmento de código de ejemplo de registro de 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));
  }

Reemplace type con 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 elimina las restricciones de una aplicación, debe registrar los motivos para eliminar las restricciones. Un fragmento de código de ejemplo de registro de 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));
    }

Prueba de restricciones de aplicaciones

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

  • Poner una aplicación en restricción:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Saque una aplicación de la restricción y restablezca el comportamiento predeterminado:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Hacer que una aplicación en segundo plano quede inactiva inmediatamente:
    am make-uid-idle [--user user-id | all | current] package-name
  • Agregue un paquete a la tempwhitelist por un período breve:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Agregar/eliminar un paquete de la lista blanca de usuarios:
    cmd deviceidle whitelist [+/-]package-name
  • Verifique el estado interno del programador de jobscheduler y el administrador de alarmas:
    dumpsys jobscheduler
    dumpsys alarm

Aplicación en espera

El modo de espera de la aplicación prolonga la vida útil de la batería al diferir la actividad de la red en segundo plano y los trabajos para las aplicaciones que el usuario no está usando activamente.

Ciclo de vida en espera de la aplicación

La plataforma detecta aplicaciones inactivas y las pone en espera hasta que el usuario comienza a interactuar activamente con la aplicación.

Durante la fase de detección , la plataforma detecta que una aplicación está inactiva cuando el dispositivo no se está cargando y el usuario no ha iniciado la aplicación directa o indirectamente durante una cantidad específica de tiempo de reloj, así como una cantidad específica de tiempo de pantalla. . (Los lanzamientos indirectos ocurren cuando una aplicación en primer plano accede a un servicio en una segunda aplicación).

Durante el modo de espera de la aplicación , la plataforma evita que las aplicaciones accedan a la red más de una vez al día, aplazando las sincronizaciones de aplicaciones y otros trabajos.

La plataforma sale de la aplicación del modo de espera cuando:

  • La aplicación se activa.
  • El dispositivo está enchufado y cargándose.

Las aplicaciones activas no se ven afectadas por la aplicación en espera. Una aplicación está activa cuando tiene:

  • Un proceso actualmente en primer plano (ya sea como actividad o servicio en primer plano, o en uso por otra actividad o servicio en primer plano), como detector de notificaciones, servicios de accesibilidad, fondo de pantalla en vivo, etc.
  • Una notificación vista por el usuario, como en la pantalla de bloqueo o en la bandeja de notificaciones.
  • Ha sido lanzado explícitamente por el usuario

Una aplicación está inactiva si ninguna de las actividades anteriores ha ocurrido durante un período de tiempo.

Probando el modo de espera de la aplicación

Puede probar manualmente el modo de espera de la aplicación con los siguientes comandos 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