[Перевод] Увеличение времени работы от аккумулятора в Android M

9a77df0562674b0ea5aa6443d56fdf5f.jpg

По мнению многих разработчиков, в большинстве случаев к слишком быстрому разряду аккумуляторов смартфонов приводит плохая оптимизация приложений. В мае этого года в Google прошла очередная ежегодная конференция Google I/O, на которой было анонсировано много всего интересного для разработчиков. В частности, когда речь зашла об Android M, то одной из центральных тем были именно производительность мобильных устройств и продолжительность работы от аккумулятора. Давайте рассмотрим взглянем на новые функции и инструменты, которые помогут пользователям и инструментам выжать ещё больше из аккумуляторов мобильных устройств.

Doze


Это один из главных инструментов в новой ОС для обуздания активности приложений, когда устройство находится в спящем режиме. На смартфонах под управлением Lollipop и более старых версий Android, любое приложение может вывести устройство из сна ради своего обновления, что позволяет поддерживать актуальность данных. Doze анализирует текущее состояние устройства и данные с акселерометра, определяет, когда смартфон не используется, и отправляет его в «глубокий сон». В этом режиме обновление приложений запрещается до тех пор, пока устройство не будет разбужено каким-то иным, более приоритетным событием. В режиме «глубокого сна» отключается сетевая активность, блокировки засыпания, предупреждения и задачи JobScheduler.

Как подсказывает опыт, часто обновляющиеся в фоновом режиме приложения являются одной из главных причин быстрого разряда аккумулятора. И Google придерживается того же мнения. На конференции была приведена информация, что планшеты Nexus 9 с запущенным Doze работали почти в два раза дольше в режиме ожидания.

Чтобы протестировать эту функцию, обновитесь до Android M, а затем с помощью команды ADB отключите зарядку устройства:

adb shell dumpsys battery unplug


Doze может переводить устройство в один из нескольких режимов:

  • ACTIVE: дисплей включен.
  • INACTIVE: дисплей выключен, но устройство активно.
  • IDLE_PENDING: переход в состояние «глубокого сна».
  • IDLE: устройство спит.
  • IDLE_MAINTENANCE: короткий промежуток времени, в течение которого разрешается выполнение всех запланированных уведомлений и обновлений.


Между этими состояниями можно переключаться вручную:

adb shell dumpsys deviceidle step


Сколько времени нужно на перевод устройства в этот режим?

adb shell dumpsys deviceidle


Это позволяет получить много интересной информации о Doze. К примеру, на Nexus 6 (с включённым дисплеем) были получены следующие результаты:

Whitelist system apps:
com.android.providers.downloads
com.android.vending
com.google.android.gms
Whitelist user apps:
com.facebook.katana
Whitelist app uids:
UID=10012: true
UID=10016: true
UID=10026: true
UID=10100: true
mSigMotionSensor={Sensor name="Invensense Significant Motion Detector", vendor="Invensense Inc.", version=1, type=17, maxRange=1.0, resolution=1.0, power=0.3, minDelay=-1}
mCurDisplay=Display id 0: DisplayInfo{"Built-in Screen", uniqueId "local:0", app 1440 x 2392, real 1440 x 2560, largest app 2413 x 2308, smallest app 1440 x 1356, mode 1, defaultMode 1, modes [{id=1, width=1440, height=2560, fps=60.0}], rotation 0, density 560 (494.27 x 492.606) dpi, layerStack 0, appVsyncOff 7500000, presDeadline 12666667, type BUILT_IN, state ON, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=3.5, width=1440, height=2392, scaledDensity=3.5, xdpi=494.27, ydpi=492.606}, isValid=true
mIdleDisabled=false
mScreenOn=true
mCharging=false
mSigMotionActive=false
mState=ACTIVE
mInactiveTimeout=+30m0s0ms


В первой части перечисляются процессы, аккредитованные Doze. Их активность никак не ограничивается. Обратите внимание, что в этот список вручную добавлен Facebook (Настройки —> Аккумулятор —> Facebook —> активировать «Отключить оптимизацию»). Далее идёт раздел с информацией с акселерометра и состоянием дисплея. Эти данные будут использоваться для последующего вывода устройства из состояния «глубокого сна». В данном примере дисплей включен, а значит Doze находится в режиме ACTIVE.

Период неактивности устройства установлен в 30 минут. Если выключить дисплей, этот раздел меняется:

mState=INACTIVE
mInactiveTimeout=+30m0s0ms
mNextAlarmTime=+28m26s193ms


С выключенным дисплеем устройство переходит в режим INACTIVE и может переключиться в режим перехода в «глубокий сон». Таймаут также равен 30 минутам, и, согласно таймеру, из этого периода прошло около 1,5 минут. Вручную переводим устройство в IDLE_PENDING:

mState=IDLE_PENDING
mInactiveTimeout=+30m0s0ms
mNextAlarmTime=+24m34s189ms
mNextIdlePendingDelay=+5m0s0ms
mNextIdleDelay=+60m0s0ms


Спустя 30 минут пребывания в этом режиме, устройство перейдёт в IDLE. Таким образом, для перехода в «глубокий сон» требуется суммарно 60 минут. Переход:

mState=IDLE
mInactiveTimeout=+30m0s0ms
mNextAlarmTime=+59m42s953ms
mNextIdlePendingDelay=+5m0s0ms
mNextIdleDelay=+2h0m0s0ms


Через 60 минут сработает триггер, устройство пробудится и отправит все накопившиеся сообщения, инициализирует события и триггеры. Параметр mNextIdleDelay говорит о том, что следующее пробуждение из «глубокого сна» произойдёт через 2 часа. Получается следующая цикличность смен режимов: 1, 2, 4 и 6 часов. То есть самый большой промежуток между пробуждениями составляет 6 часов, 4 раза в сутки.

Как ведут себя приложения, когда устройство выходит из режима «глубокого сна»?

Можете самостоятельно протестировать своё приложение, отправив устройство в «глубокий сон»:

adb shell am set-idle  true


С помощью той же команды его можно пробудить (введя значение false вместо true), и посмотреть, как активируются разные процессы, рассылаются и выполняются запросы.

Как видите, Doze является замечательным инструментом для экономии аккумулятора, когда устройство выключено.

Режим ожидания для приложений


В текущих версиях Android любое приложение имеет доступ к радиомодулю, даже в фоновом режиме. Иными словами, какое-нибудь давно скачанное и забытое вами приложение может втихую по несколько раз в день передавать какие-либо данные без вашего ведома. С помощью Doze это можно заблокировать запуск приложений, но они всё-равно смогут запускать процессы и обновляться, когда пользователь включает дисплей устройства. С помощью новой функции режима ожидания для приложений (App standby) можно приложениям, которые не запускались в активном режиме в течение какого-то периода времени (в днях), принудительно назначать режим ожидания. В этом режиме приложениям ограничивается доступ в интернет или запуск каких-либо процессов, пока смартфон не будет подключён к зарядному устройству. Тем самым экономится аккумулятор устройства.

Как работает режим ожидания для приложений? Если выполнить:

adb shell dumpsys usagestats


то можно получить много информации об активности приложений за последний день/неделю/месяц и год.

Например
user=0
In-memory daily stats
timeRange="6/1/2015, 5:00 - 11:16 PM"
   packages
     package=com.google.android.googlequicksearchbox totalTime="00:36" lastTime="6/1/2015, 10:56 PM" inactiveTime="01:05"
     package=com.android.providers.calendar totalTime="00:00" lastTime="6/1/2015, 10:20 PM" inactiveTime="02:26"
     package=com.android.providers.media totalTime="00:00" lastTime="6/1/2015, 10:20 PM" inactiveTime="02:20"
     package=com.android.providers.downloads totalTime="00:00" lastTime="6/1/2015, 10:20 PM" inactiveTime="02:20"
     package=com.android.defcontainer totalTime="00:00" lastTime="6/1/2015, 11:10 PM" inactiveTime="00:00"
     package=android totalTime="00:00" lastTime="6/1/2015, 10:32 PM" inactiveTime="01:44"
     package=com.urbandroid.inline totalTime="00:00" lastTime="6/1/2015, 11:14 PM" inactiveTime="00:00"
     package=com.google.android.gm totalTime="00:00" lastTime="6/1/2015, 9:01 PM" inactiveTime="06:36"

In-memory weekly stats
timeRange="5/29/2015, 2:33 PM - 6/1/2015, 11:16 PM"
   packages
     package=com.amazon.mShop.android.shopping totalTime="01:04" lastTime="5/29/2015, 3:24 PM" inactiveTime="3:55:51"
     package=com.google.android.youtube totalTime="55:51" lastTime="5/31/2015, 2:04 AM" inactiveTime="1:09:00"
     package=com.android.providers.telephony totalTime="00:00" lastTime="5/29/2015, 2:56 PM" inactiveTime="5:37:10"
     package=com.android.sdm.plugins.connmo totalTime="00:00" lastTime="5/29/2015, 3:13 PM" inactiveTime="5:46:30"
     package=com.google.android.googlequicksearchbox totalTime="33:12" lastTime="6/1/2015, 10:56 PM" inactiveTime="01:05"
     package=com.android.providers.calendar totalTime="00:00" lastTime="6/1/2015, 10:20 PM" inactiveTime="02:26"
     package=com.android.providers.media totalTime="00:00" lastTime="6/1/2015, 10:20 PM" inactiveTime="02:20"
     package=com.google.android.apps.docs.editors.docs totalTime="00:00" lastTime="5/29/2015, 3:13 PM" inactiveTime="5:46:30"
     package=com.google.android.onetimeinitializer totalTime="00:00" lastTime="5/29/2015, 3:13 PM" inactiveTime="5:46:30"


Встроенный в ОС алгоритм определяет дату последнего запуска приложения, и при необходимости переводит его в неактивный режим. Список таких приложений можно просмотреть, если зайти в меню настроек в пункт «Inactive apps».

49e1686cfbca455daad9e1adb6bfc3f8.jpg

Производительность приложений


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

2172c1cc7b7c4f32adf0433cdc1cfe8a.jpg2bb5dad2dc3e49178eea421cb6a91dec.jpg

В данном случае основные потребители заряда аккумулятора: ЦПУ (в том числе и в фоновом режиме), сетевой протокол и радиомодуль. Представленная статистика собрана за 28 часов, с момента полной зарядки аккумулятора.
Также в Android M теперь доступно меню, с помощью которого можно «игнорировать оптимизацию». В этом случае отключаются Doze и режим ожидания для приложений. Это позволяет разработчикам тестировать производительность своих приложений как с включённой, так и с выключенной оптимизацией, выясняя, как это влияет на продолжительность работы от аккумулятора. А заодно как быстро устаревают данные в приложении.

GCM Network Manager


Замечательная новинка, для использования которой даже не требуется наличие Android M — её можно запускать на любых версиях ОС, вплоть до 2.3!

В вышедшем в конце прошлого года Lollipop появился JobScheduler API. На Android 5.0 и выше этот API отделяет от приложений все аппаратные предупреждения и блокировки засыпания, перенося их на уровень ОС. Это позволяет операционной системе агрегировать все эти события от разных приложений, тем самым уменьшая количество пробуждений и предупреждений, а значит и экономя заряд аккумулятора. Замечательно, вот только работает это на Lollipop и выше (на момент написания статьи, это примерно 12,4% Android-устройств).

Чтобы обеспечить тот же уровень производительности для сетевых соединений, в Google Play Services версии 7.5 добавят GCM Network Manager. Он использует фреймворк, аналогичный JobScheduler, но при этом будет работать на любых устройствах, где установлен Google Play Services (вплоть до Android 2.3, то есть на 99% всех Android-устройств). GCM Network Manager поддерживает такие же сценарии и режимы, что и JobScheduler, а также позволяет ограничивать количество сетевых подключений до тех пор, пока смартфон не будет подключён к зарядному устройству, а также использовать для больших обновлений исключительно Wi-Fi.

* * *

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

© Habrahabr.ru