В Android 9 и более поздних версиях платформа может отслеживать поведение приложений, которое негативно влияет на время автономной работы устройств. Платформа использует и оценивает правила установки, чтобы обеспечить поток UX, который дает пользователям возможность ограничивать приложения, которые нарушают правила.
В Android 8.0 и более ранних версиях были ограничения с помощью таких функций, как дремота, режим ожидания приложения, ограничения в фоновом режиме и ограничения на фоновое местоположение. Тем не менее, некоторые приложения продолжали демонстрировать плохое поведение, некоторые из которых описаны в 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 ] [-dduration ] [packagepackage-name ] - Добавить/удалить пакет из белого списка пользователей:
cmd deviceidle whitelist [+/-]
package-name - Проверить внутреннее состояние
jobscheduler
и менеджера тревог:dumpsys jobscheduler
dumpsys alarm
Приложение в режиме ожидания
Режим ожидания приложений продлевает срок службы батареи, откладывая фоновую сетевую активность и задания для приложений, которые пользователь не использует активно.
Жизненный цикл приложения в режиме ожидания
Платформа обнаруживает неактивные приложения и переводит их в режим ожидания до тех пор, пока пользователь не начнет активно взаимодействовать с приложением.
На этапе обнаружения платформа определяет, что приложение неактивно, когда устройство не заряжается и пользователь не запускал приложение прямо или косвенно в течение определенного времени, а также определенного времени нахождения на экране. . (Косвенные запуски происходят, когда приложение переднего плана обращается к службе во втором приложении.)
Во время ожидания приложения платформа запрещает приложениям доступ к сети более одного раза в день, откладывая синхронизацию приложений и другие задания.
Платформа выходит из режима ожидания , когда:
- Приложение становится активным.
- Устройство подключено и заряжается.
На активные приложения не влияет режим ожидания приложения. Приложение активно , если оно:
- Процесс, который в настоящее время находится на переднем плане (либо как действие или служба переднего плана, либо используется другим действием или службой переднего плана), например прослушиватель уведомлений, службы специальных возможностей, живые обои и т. д.
- Уведомление, просматриваемое пользователем, например, на экране блокировки или в области уведомлений.
- Был явно запущен пользователем
Приложение считается неактивным , если ни одно из перечисленных выше действий не выполнялось в течение определенного периода времени.
Тестирование приложения в режиме ожидания
Вы можете вручную протестировать режим ожидания приложения, используя следующие команды adb
:
adb shell dumpsys battery unplug
adb shell am set-idle
package-name trueadb shell am set-idle
package-name falseadb shell am get-idle
package-name