В Android 9 и более поздних версий платформа может отслеживать поведение приложений, которое негативно влияет на время работы батареи устройства. Платформа использует и оценивает правила настройки, чтобы предоставить пользователям возможность ограничить приложения, нарушающие правила.
В Android 8.0 и более ранних версий действовали ограничения, связанные с такими функциями, как спящий режим, App Standby, лимиты на фоновые процессы и лимиты на доступ к данным о местоположении в фоновом режиме. Однако в некоторых приложениях по-прежнему наблюдались существенные неполадки, часть которых описана в Android Vitals. В Android 9 появилась инфраструктура ОС, которая может обнаруживать и ограничивать приложения на основе правил, которые можно обновлять.
Ограничения фоновой работы
Пользователи могут ограничивать работу приложений, а система может предлагать приложения, которые, по ее мнению, негативно влияют на состояние устройства.
Приложения с ограничениями:
- Пользователь по-прежнему может запустить его.
- Не может выполнять задачи, запускать будильники или использовать сеть в фоновом режиме.
- Не удается запустить активные службы.
- Пользователь может изменить его на приложение без ограничений.
Производители устройств могут добавлять в приложения дополнительные ограничения, чтобы:
- Запретить приложению перезапускаться самостоятельно.
- Запретить привязку сервисов (высокий риск).
Ограниченные приложения в фоновом режиме не должны потреблять ресурсы устройства, такие как память, ЦП и батарея. Приложения с ограниченной фоновой активностью не должны влиять на состояние устройства, когда пользователь не работает с ними. При этом приложения должны быть полностью функциональны, когда пользователь их запускает.
Как использовать собственные реализации
Производители устройств могут и дальше использовать собственные методы, чтобы применять ограничения к приложениям.
Как интегрировать ограничения для приложений
В разделах ниже рассказывается, как задать и интегрировать ограничения для приложений на устройстве. Если вы используете методы ограничения приложений из Android 8.x или более ранних версий, внимательно изучите следующие разделы, чтобы узнать об изменениях в Android 9 и более поздних версиях.
Как задать флаг AppOpsManager
Если приложение ограничено, задайте соответствующий флаг в параметре AppOpsManager. Пример фрагмента кода из 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); }
Убедитесь, что isBackgroundRestricted возвращает true.
Если приложение ограничено, убедитесь, что команда
ActivityManager.isBackgroundRestricted() возвращает значение true.
Как регистрировать причину ограничения
Если приложение ограничено, запишите причины ограничения. Пример фрагмента кода для регистрации из 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)); }
Замените type значением из AnomalyType.
Производители устройств могут использовать константы, определенные в файле
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; }
Когда пользователь или система снимает ограничения с приложения, вы должны регистрировать причины этого. Пример фрагмента кода для регистрации из 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)); }
Ограничения для тестовых приложений
Чтобы проверить, как работают ограничения для приложений в Android 9 и более поздних версиях, используйте одну из следующих команд:
- Чтобы ограничить доступ к приложению:
appops set package-name RUN_ANY_IN_BACKGROUND ignore
- Чтобы снять ограничения с приложения и восстановить режим работы по умолчанию:
appops set package-name RUN_ANY_IN_BACKGROUND allow
- Чтобы приложение в фоновом режиме сразу перешло в режим ожидания:
am make-uid-idle [--user user-id | all | current] package-name
- Добавьте пакет в
tempwhitelistна короткий срок:cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
- Добавление пакета в белый список пользователя или удаление из него:
cmd deviceidle whitelist [+/-]package-name
- Проверьте внутреннее состояние
jobschedulerи менеджера будильников:dumpsys jobschedulerdumpsys alarm
Режим ожидания приложений
Режим App Standby позволяет продлить время работы от батареи, откладывая фоновую сетевую активность и задачи для приложений, которые пользователь не использует.
Жизненный цикл режима ожидания приложения
Платформа обнаруживает неактивные приложения и переводит их в режим ожидания, пока пользователь не начнет активно взаимодействовать с ними.
На этапе обнаружения платформа определяет, что приложение неактивно, если устройство не заряжается и пользователь не запускал приложение напрямую или косвенно в течение определенного времени (как общего, так и времени работы экрана). (Косвенный запуск происходит, когда активное приложение обращается к службе в другом приложении.)
В режиме ожидания приложения платформа запрещает приложениям получать доступ к сети чаще одного раза в день, откладывая синхронизацию и другие задачи.
Платформа выводит приложение из режима ожидания, когда:
- Приложение становится активным.
- Устройство подключено к источнику питания и заряжается.
Активные приложения не затрагиваются функцией App Standby. Приложение считается активным, если:
- Процесс, который в данный момент выполняется на переднем плане (как действие или сервис переднего плана, либо используется другим действием или сервисом переднего плана), например прослушиватель уведомлений, сервисы специальных возможностей, живые обои и т. д.
- Уведомление, которое пользователь увидел на заблокированном экране или в панели уведомлений.
- было запущено пользователем;
Приложение считается неактивным, если ни одно из перечисленных выше действий не выполнялось в течение определенного периода времени.
Тестирование режима App Standby
Вы можете вручную протестировать App Standby, используя следующие команды adb:
adb shell dumpsys battery unplugadb shell am set-idle package-name trueadb shell am set-idle package-name falseadb shell am get-idle package-name