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

Давай представим, что у нас есть приложение, а у него, в свою очередь, есть служба (service), которая должна постоянно висеть в фоне, обрабатывать команды, полученные от сетевого сервера, и отправлять ответы. Связь с сервером, как это и положено мобильным устройствам, поддерживается с помощью long poll запросов, то есть приложение подключается к удаленному серверу и ждет, пока тот отправит что-либо в ответ, а потом переподключается и ждет снова. Это эффективный и очень экономный в плане заряда батареи способ, который в том числе используется в механизме push-уведомлений самого Android.

В теории все выглядит отлично, архитектура приложения абсолютно правильная, вот только, если начать его тестировать, вскроется несколько очень неприятных моментов.

 

Режимы энергосбережения Android

В Android 4.4–5.1 (версии ниже мы рассматривать не будем — они стремительно устаревают) служба будет работать и моментально откликаться на запросы сервера, но только до тех пор, пока экран включен. Через несколько секунд после отключения экрана смартфон перейдет в режим сна (suspend), и промежуток между отправкой запроса и ответом нашего приложения будет составлять примерно минуту. Это срок между maintenance-пробуждениями устройства, и повлиять на него мы не можем.

В Android 6.0–7.1 ситуация будет примерно такой же, однако спустя примерно час смартфон перейдет в так называемый режим Doze. После этого ответ от приложения можно либо не получить вовсе, либо получить спустя час или два. А все потому, что в режиме Doze смартфон фактически не дает работать сторонним приложениям и их службам и полностью отрезает им доступ в Сеть. Управление они могут получить только на короткий промежуток времени спустя час после перехода в режим Doze, затем два часа, четыре часа, со все большим увеличением промежутков между пробуждениями.

Хорошие новости в том, что Doze работает общесистемно и включается спустя час после отключения экрана и только если не трогать смартфон (в 7.0–7.1 можно и трогать), а отключается сразу после разблокировки смартфона, подсоединения к заряднику или движения смартфона (опять же не в 7.0–7.1). То есть можно надеяться на то, что хотя бы днем наш сервис будет работать нормально.

Плохие же новости в том, что, помимо Doze, в Android 6.0–7.1 есть и другой механизм энергосбережения под названием App Standby. Работает он примерно так: система следит за тем, какие приложения использует юзер, и применяет к редко используемым приложениям те же ограничения, что и в случае с режимом Doze. При подключении к заряднику все переведенные в режим Standby приложения получают амнистию. К приложениям, имеющим уведомление или права администратора (не root), режим Standby не применяется.

Итого, в Android есть сразу три механизма, с которыми придется бороться:

  • Suspend — обычный режим энергосбережения, может замедлить получение ответа от устройства примерно на одну минуту;
  • App Standby — агрессивный режим энергосбережения, способный замедлить получение ответа на сутки;
  • Doze — агрессивный общесистемный режим энергосбережения, который применяется ко всем приложениям.

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

 

Сценарий 1. Небольшая задержка в ответе некритична, переход в Doze некритичен

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

Два самых простых способа добиться этого — либо вывести службу на передний план (foreground service), либо дать приложению права администратора устройства. Начнем с первого варианта.

 

Foreground service

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

Создать foreground service очень просто. Достаточно вставить в код службы примерно такие строки:

Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

Notification notification = new Notification.Builder(this)
    .setContentTitle(getText(R.string.notification_title))
    .setContentText(getText(R.string.notification_message))
    .setSmallIcon(R.drawable.icon)
    .setContentIntent(pendingIntent)
    .setTicker(getText(R.string.ticker_text))
    .build();

startForeground(0, notification);

Этот пример создает уведомление, при тапе на которое будет запущена ExampleActivity, в конце с помощью startForeground() служба переводится в статус foreground.

 

Права администратора

Другой вариант — это дать приложению права администратора. Такие права обеспечивают возможность управлять политикой формирования паролей экрана блокировки, делать удаленную блокировку и вайп устройства.

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

Получить, а точнее запросить права администратора опять же просто. Для начала нам понадобится пара колбэков, которые будут вызваны после того, как права получены или отозваны:

Продолжение статьи доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

Заинтересовала статья, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для статей, опубликованных более двух месяцев назад.


3 комментария

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Windows 10 против шифровальщиков. Как устроена защита в обновленной Windows 10

Этой осенью Windows 10 обновилась до версии 1709 с кодовым названием Fall Creators Update …