Энергопотребление Android-приложений

Ваши пользователи жалуются на то, что приложение очень быстро сажает заряд телефона? Запущенный фоновый сервис внезапно останавливается? Сообщения от FCM не доходят до пользователя? Что связывает эти три серьезных вопроса? Ответ прост — неверно выстроенная работа с энергопотреблением приложения.
Давайте разберемся в основных моментах, связанных с этой темой. Возможно, это позволит вам в будущем избежать ошибок, с которыми сталкивалось большинство разработчиков мобильных приложений.

В интернете огромное количество разрозненной информации, собрать которую в единое общее руководство было одной из основных целей этой статьи.

image


Общая информация

В Android есть следующие платформенные фичи для оптимизации энергопотребления:

В Android 6 появились две фичи для сохранения заряда батареи за счет управления поведением приложений, когда устройство не на зарядке:


  • Doze Mode.
  • App Standby.


Doze Mode

Когда устройство находится в режиме Doze, доступ приложений к определенным ресурсам откладывается до появления окна обслуживания (maintenance window). Список конкретных ограничений.

Если пользователь оставляет на какое-то время устройство отключенным от зарядки и с выключенным экраном, то оно переходит в режим Doze. В этом режиме система пытается сохранить заряд батареи, ограничивая доступ приложений к сетевым и ресурсоемким службам, откладывает Jobs, синхронизацию и Alarms.

Периодически система выходит из режима Doze, чтобы приложения могли выполнить отложенные действия. Во время этого окна обслуживания (maintenance window) система запускает все отложенные синхронизации, Jobs, Alarms и позволяет приложениям получить доступ к сети.


13a135bc7d64042a79cc5e1f50ced5c6.png

Со временем система все реже и реже планирует maintenance windows, что помогает снизить расход энергии, когда устройство не на зарядке.

В режиме Doze к приложениям применяются следующие ограничения:


  • Доступ в сеть приостановлен.
  • Стандартные AlarmManager откладываются до следующего окна обслуживания.
  • Система не сканирует Wi-Fi.
  • Система не позволяет запускаться sync adapters.
  • Система не позволяет запускаться JobScheduler.

Чеклист для приложения в режиме Doze:


  • Использовать FCM для обмена сообщениями.
  • Если пользователь должен сразу увидеть уведомление, то нужно использовать FCM с высоким приоритетом.
  • Предоставлять достаточное количество информации в сообщении, чтобы избежать последующих запросов в сеть.
  • Установить критически оповещения с setAndAllowWhileIdle () and setExactAndAllowWhileIdle ().
  • Протестировать приложение в режиме Doze.


App StandBy, App StandBy Buckets

App StandBy позволяет системе определить, что приложение простаивает, когда пользователь не пользуется им активно. App StandBy запускается, когда не выполняется ни одно из следующих условий:


  • Пользователь явно запускает приложение.
  • Приложение находится на переднем плане (явно или в качестве Foreground service, либо используется другой Activity).
  • Приложение генерирует уведомления, которые пользователь видит на экране блокировки или в области уведомлений.
  • Приложение является активным приложением администратора устройств.

Когда устройство подключается к зарядке, система выпускает приложения из режима Standby, что позволяет им выполнять любые задачи. Если устройство не используется в течение длительного периода времени, система предоставляет бездействующим приложениям доступ в сеть примерно раз в день.

Определение частоты использования отличается у разных производителей, особенно «жестит» Samsung.

В Android 9 появились новые фичи для управления питанием устройства. Они делятся на две категории:


  • App standby buckets. Система ограничивает доступ приложения к ресурсам устройства в зависимости от модели поведения пользователя.
  • Battery Saver Improvements. Когда включена функция экономии заряда батареи, система накладывает ограничения на все приложения.

Эти ограничения применяются ко всем приложениям независимо от их targetSdk.

App StandBy Buckets помогает системе приоритизировать запросы приложений к ресурсам на основании того, как давно и как часто использовалось приложение. На основе шаблонов использования приложение помещается в один из пяти сегментов. Система ограничивает ресурсы устройства, доступные для каждого приложения, в зависимости от того, в каком сегменте находится приложение.

Пять сегментов, назначаемые приложениям в зависимости от приоритета:


  • Active. Приложение находится в активном сегменте, если пользователь в настоящий момент использует приложение. Т.е. если видна Activity, или запущен Foreground service, или есть synchronized adapter, связанный с приложением на переднем плане, или пользователь кликнул на уведомление. Если приложение в активном сегменте, то никакие ограничения на использование ресурсов устройства не накладываются.
  • Working set. Приложение находится в этом сегменте, если часто запускается, но в данный момент не активно. Система накладывает умеренные ограничения на действия этого приложения.
  • Frequent. Приложение находится в этом сегменте, если используется часто, но не каждый день. Система накладывает больше ограничений, также накладываются ограничения на количество сообщений FCM с высоким приоритетом.
  • Rare. Приложение находится в этом сегменте, если оно редко используется. В этом случае система накладывает строгие ограничения и на получение сообщений FCM с высоким приоритетом. Система также ограничивает возможность приложения подключаться к интернету.
  • Never. Это сегмент для приложений, которые были установлены, но никогда не запускались. Система накладывает жесткие ограничения.

Каждый производитель может установить свои критерии присвоения неактивных приложений к сегментам.

Для определения сегмента, в который система поместит приложение, используется машинное обучение. С его помощью прогнозируется поведение пользователя. Например, если приложение из сегмента Rare было только что использовано и перешло в Active, то это не означает, что после использования приложение поднимется в более приоритетный сегмент. Сегменты определяются на основе прогнозов будущих действий пользователя, а не на основе недавнего использования.

Полезная информация по работе с App StandBy Buckets:


  • НЕ пытаться манипулировать тем, к какому сегменту система отнесет приложение.
  • Создать Launcher Activity, если ее нет.
  • Создавать обработчик нажатий на уведомления. Если с ними нельзя взаимодействовать, то приложение не сможет перейти в активный сегмент.
  • Если приложение не показывает пользователю уведомление при получении high-priority FCM-уведомления, то пользователь не сможет взаимодействовать с приложением, и оно не перейдет в активный сегмент. Если многие сообщения будут помечены как high-priority, то приложение исчерпает свою квоту на такие сообщения, и все последующие будут иметь normal-priority.


Firebase Cloud Messaging с App StandBy и режимом Doze

Необходимо использовать FCM для взаимодействия с приложением во время простоя устройства. FCM оптимизирован для работы в режимах ожидания Doze и App StandBy с помощью высокоприоритетных FCM-сообщений. Высокоприоритетные сообщения позволяют разбудить приложение для доступа к сети, даже если устройство находится в режиме Doze или приложение в режиме App StandBy. В обоих режимах система доставляет сообщение и дает приложению временный доступ к сетевым сервисам, а затем возвращает устройство или приложение в режим ожидания.


Как протестировать приложение с различными ограничениями системы


Тестирование Doze Mode


  • Получить доступ к ADB (android device bridge) в текущей сессии:


  • Перевести систему в режим ожидания:


  • Выйти из режима ожидания:


  • Активировать устройство:


  • Проверить поведение приложения.


Тестирование приложения с App StandBy для Android < 9


  • Перевести приложение в App StandBy:


  • Пробудить приложение:


  • Проверить работу приложения. Убедиться, что восстанавливается корректно. Проверить, продолжают ли работать уведомления и фоновые процессы.


Тестирование App Standby Buckets

Можно вручную переместить приложение в определенный App StandBy bucket с помощью команды:

Команда проверки, в каком сегменте сейчас приложение:


Тестирование ограничений на фоновые процессы


  • Вручную применить ограничения на выполнение фоновых задач:


  • Убрать ограничения на выполнение фоновых процессов:


Тестирование режима Battery safety


  • Отключить устройство от ПК:


  • Проверить поведение устройства в условиях экономии энергии:


  • Отменить ручную настройку:

Ограничения, начиная с Android 7:


  • Не отправляются широковещательные сообщения `CONNECTIVITY_ACTION`, если receiver объявлен в манифесте. Если receiver зарегистрирован динамически, то сообщение будет получено.
  • Приложения не могут получать или отправлять `ACTION_NEW_PICTURE` или `ACTION_NEW_VIDEO`.

Ограничения, начиная с Android 9:

Если система замечает, что приложение потребляет чрезмерное количество ресурсов, она уведомляет пользователя и дает ему возможность ограничить действия приложения. Это поведение включает в себя:


  • Чрезмерные wake locks.
  • Избыточное количество фоновых сервисов.

Точные ограничения определяются производителем устройства.


Battery Historian

Инструмент Battery Historian дает представление о расходе заряда батареи. Инструмент визуализирует связанные с энергопотреблением события и предоставляет разнообразные данные, которые могут помочь вам определить поведение приложения, разряжающего батарею.


Анализ приложения с помощью Battery Historian

Предварительно необходимо установить Docker.


  • Получить доступ к ADB (android device bridge) в текущей сессии:


  • Подключить устройство к ПК.
  • Убить текущий ADB-сервер.


  • Проверить доступные устройства:


  • Сбросить данные о батарее:


  • Отключить устройство и пройти по выбранному вами сценарию использования приложения.
  • Подключить устройство.
  • Проверить, что устройство подключено:


  • Сделать дамп данных батареи:


  • Создать отчет для данных:


  • Запустить (порт можно указать любой):


  • В браузере перейти по ссылке http://localhost:5554 и открыть ZIP файл.


  • Вот так примерно будет выглядеть график BatteryHistorian:


3f578e7edd5e7ad2221d9874f2b671e9.png

На этом графике вы можете узнать, в какой момент запустился ваш сервис, установились wake locks, был запущен JobScheduler и другую информацию. Возможно, вы даже узнаете о своем приложении то, чего еще не знали и о чем не подозревали. Уделите этому инструменту пару-тройку свободных часов и гарантирую, вы не пожалеете.


Energy Profiler

Energy Profiler — встроенный в Android Studio анализатор энергопотребления. Думаю, тут не стоит задерживаться. Этот инструмент довольно хорошо описан, и каждый может оценить его в действии.


BatteryStats + UI-тесты

В этой главе мы разберем, как можно использовать связку из BatteryStats и UI-тестирования.


  • Перед запуском теста я написал bash-скрипт:


  • Для начала нужно ввести расположение класса с тестом. Например, класс `com.myApp.MyTestEspressoTest`.
  • Далее подключается ADB.
  • Устройство отключается от ПК.
  • Сбрасывается статистика BatteryStats.
  • Запускается тест, подставляет класс, введенный нами ранее, и используемый фреймворк для тестирования.
  • Выгружается информация об энергопотреблении и парсится в более читаемый формат с помощью .awk-файла. Далее этот файл сохраняется под именем BatteryTestsResultFull.txt в главной папке приложения (или в любой другой, которую вы выберете).
  • Выводится сообщение с расположением файла с результатом.
  • Сбрасывается статистика BatteryStats.
  • Вы восхитительны!

Для парсинга файла, получившегося после теста, применяется .awk-файл. Сам файл я решил не прикладывать, т.к. он получился огромным, и не все будут использовать те же поля, что использовал я. В результате получаем текстовый BatteryTestsResult.txt такого содержания:

Результат более удобочитаемый, что стандартный файл BatteryStats. При желании вы можете добавить необходимые поля для анализа либо вместо .awk-файла использовать регулярные выражения.


P.S. Проблемы с Samsung

При написании статьи я наткнулся на полезный сайт https://dontkillmyapp.com, на котором можно узнать, какие ограничения накладывают различные производители на энергопотребление устройств. Самой частой проблемой, с которой я сталкивался, была жалоба пользователей Samsung на высокое энергопотребление различными приложениями. И на этом ресурсе я нашел ответ на свой вопрос.

Вместе с релизом Samsung S8 была представлена утилита для увеличения времени работы батареи под названием App Power Monitor. И чтобы приложения работали корректно, их нужно вносить в whitelist. Также Samsung — рекордсмен по убийству приложений благодаря его «Адаптивной батарее».

На сайте есть рекомендации для разработчиков по обходу ограничений, но в случае с данным производителем:


1ff48cd93eb2d656e5ee12e0397b4a37.png

Чтобы до конца понять, как работает и от каких факторов зависит энергопотребление Android-приложения, одной статьи, конечно, недостаточно. Но надеюсь, что я выполнил свою главную цель — заинтересовать вас этой темой, и вы сможете оптимизировать работу с энергопотреблением. На этом у меня все.

© Habrahabr.ru