Broadcast (Широковещательные сообщения)
Практическая часть показана в отдельной статье.
Иногда для правильной работы приложению следует знать о текущем заряде батареи или наличии интернета. Если делать проверку самостоятельно на постоянной основе, то на систему идёт большая нагрузка. Но в этом нет нужды, система сама следит за подобными вещами и готова поделиться со всеми нуждающимися своими сообщениями. Ваша задача — реализовать у себя широковещательный приёмник (Broadcast Receiver). Получатель трансляции всегда будет получать уведомления, независимо от состояния вашего приложения — работает ли ваше приложение в фоновом режиме или вообще не работает в данный момент.
Широковещательные сообщения делают приложение более открытым; передавая события, использующие сообщения, вы открываете компоненты своего приложения для сторонних приложений, и сторонние разработчики реагируют на события без необходимости изменять ваше оригинальное приложение. В своём приложении вы можете прослушивать широковещательные сообщения других приложений, заменить или улучшить функциональность собственного (или стороннего) приложения или реагировать на системные изменения и события приложений.
Вы тоже можете организовать отправку широковещательных сообщений, а другие приложения могут обзавестись приёмниками для обработки ваших сообщений.
Приёмник широковещательных сообщений — это компонент для получения внешних событий и реакции на них. Инициализировать передачи могут:
- другие приложения или службы
- сама система
- ваше собственное приложение
Широковещательные сообщения можно разделить на две группы:
- Неявная широковещательная трансляция (implicit broadcast) — сообщения рассылаются всем желающим, а не конкретно вашему приложению. Вам нужно только зарегистрироваться для получения этих сообщений через фильтр IntentFilter в манифесте. Система просматривает все объявленные фильтры намерений в вашем манифесте и проверяет, есть ли совпадение. Из-за этого поведения неявные широковещательные сообщения не имеют целевого атрибута
- Явная трансляция (explicit broadcast) предназначена для конкретных приложений. В атрибуте target указывают имя пакета приложения или имя класса компонента, по которому можно найти получателя
Класс BroadcastReceiver является базовым для класса, в котором должны происходить получение и обработка сообщений, посылаемых клиентским приложением с помощью вызова метода sendBroadcast().
Зарегистрировать экземпляр класса BroadcastReceiver можно динамически в коде или статически в манифесте.
Для статической регистрации в файле манифеста в секции application следует создать секцию receiver и указать класс приёмника. Атрибут android:exported=»true» сообщает получателю, что он может принимать широковещательные сообщения вне области приложения. Внутри секции указывается фильтр намерений в виде строки, чтобы определить, какие сообщения приёмник должен прослушивать.
Если регистрация была сделана через манифест, приложение не обязано работать, чтобы ваш приёмник среагировал на трансляцию намерения. Приложение запустится автоматически, когда подходящие намерение будет транслировано. Система сама сканирует содержимое манифеста всех приложений и делает за нас всю работу. Это хорошее решение, позволяющее экономить ресурсы. Такой подход позволяет создавать приложения, способные реагировать на события даже после завершения или принудительного завершения.
Динамическая регистрация происходит с помощью метода Context.registerReceiver().
Перед этим создаётся класс, расширяющий базовый класс BroadcastReceiver и реализуется метод обратного вызова onReceive() обработчика событий.
Метод onReceive() будет выполнен при получении широковещательного намерения, если полученное намерение соответствует фильтру. Приложения с зарегистрированными приёмниками широковещательных намерений будут запущены автоматически при получении соответствующего намерения. Метод должен быть завершён в течение пяти секунд, иначе появится диалоговое окно о принудительном закрытии.
Когда широковещательное сообщение прибывает для получателя сообщения, Android вызывает его методом onReceive() и передаёт в него объект Intent, содержащий сообщение. Приёмник широковещательных сообщений является активным только во время выполнения этого метода. Процесс, который в настоящее время выполняет BroadcastReceiver, т. е. выполняющийся в настоящее время код в методе обратного вызова onReceive(), как полагает система, является приоритетным процессом и будет сохранён, кроме случаев критического недостатка памяти в системе.
Когда программа возвращается из метода onReceive(), приёмник становится неактивным и система полагает, что работа объекта BroadcastReceiver закончена. Процесс с активным широковещательным получателем защищён от уничтожения системой. Однако процесс, содержащий неактивные компоненты, может быть уничтожен системой в любое время, когда память, которую он потребляет, будет необходима другим процессам.
Это представляет проблему, когда ответ на широковещательное сообщение занимает длительное время. Если метод onReceive() порождает отдельный поток, а затем возвращает управление, то полный процесс, включая и порождённый поток, система Android считает неактивным (если другие компоненты приложения не активны в процессе), и считает этот процесс кандидатом на уничтожение.
В частности, вы не можете отобразить диалог или осуществить связывание со службой внутри экземпляра BroadcastReceiver. Для первого случая необходимо вместо этого использовать методы класса NotificationManager. Во втором случае можно использовать вызов метода Context.startService(), чтобы послать команду для запуска службы.
Решение этой проблемы возможно, если запустить в методе onReceive() отдельную службу вместе с BroadcastReceiver и позволить службе выполнять задание, чтобы сохранить содержание процесса активным в течение всего времени вашей операции.
Также можно зарегистрировать широковещательный приёмник не через манифест, а программно. Приёмник, зарегистрированный таким способом, будет отвечать на поступающие намерения только в том случае, если компонент приложения, которому он принадлежит, выполняется в этот момент.
Это может быть полезным, когда приёмник используется для обновления элементов пользовательского интерфейса внутри активности, запуска служб или уведомления через NotificationManager. В таких случаях вы можете отменять регистрацию широковещательного приёмника, если активность не отображается на экране или находится в неактивном состоянии.
В коде программы можете написать приблизительно такой код (обычно используют метод onResume()):
Для отмены регистрации используется метод unregisterReceiver() в контексте приложения, передавая ему в качестве параметра экземпляр широковещательного приёмника (обычно в методе onPause()):
Для объекта BroadcastReceiver нет никаких возможностей видеть или фиксировать намерения, используемые в методе startActivity(). Аналогично, когда вы передали намерение для запуска активности через объект BroadcastReceiver, вы не сможете найти или запустить требуемую активность. Эти две операции семантически полностью различаются: запуск активности через намерение является приоритетной операцией для системы, изменяющей содержимое экрана устройства, с которым в настоящее время взаимодействует пользователь. Передача широковещательных сообщений для системы является фоновой работой, о которой обычно не знает пользователь и которая, соответственно, имеет более низкий приоритет.
Приёмники системных событий
Android использует широковещательные сообщения для системных событий, таких как уровень зарядки батареи, сетевые подключения, входящие звонки, изменения часового пояса, состояние подключения данных, входящие сообщения SMS или обращения по телефону. Вы можете использовать эти сообщения, чтобы добавлять к вашим собственным проектам новые функциональные возможности, основанные на системных событиях.
Следующий список показывает некоторые из встроенных действий, представленных как константы в классе Intent, которые используются для того, чтобы проследить изменения состояния устройства:
- ACTION_BOOT_COMPLETED — передаётся один раз, когда устройство завершило свою загрузку. Требует разрешения RECEIVE_BOOT_COMPLETED
- ACTION_CAMERA_BUTTON — передаётся при нажатии пользователем клавиши Camera
- ACTION_DATE_CHANGED и ACTION_TIME_CHANGED — запускаются при изменении даты или времени на устройстве вручную пользователем
- ACTION_SCREEN_OFF и ACTiON_SCREEN_ON — передаются, когда экран выключается или включается
- ACTION_TIMEZONE_CHANGED — передаётся при изменении текущего часового пояса
Типы трансляций
Есть три способа отправки трансляций
- Порядковые сообщения о намерениях (Ordered broadcasts), которые посылаются методом Context.sendOrderedBroadcast(). Эти сообщения посылаются только одному получателю за один раз. Поскольку каждое полученное сообщение выполняется по очереди, он может в случае необходимости полностью прервать сообщение, чтобы его не успели передать другим приёмникам. Приёмниками сообщений можно управлять с помощью атрибута android:priority фильтра сообщений; приёмники сообщений, имеющие одинаковый приоритет, будут выполнены в произвольном порядке.
- Нормальные сообщения о намерениях (Normal broadcasts) — посылаемые вызовом метода context.sendBroadcast() и являющиеся полностью асинхронными. Все широковещательные приёмники получают сообщение и не зависят друг от друга. Это более эффективно, но означает, что получатели не могут использовать результат или прервать сообщение;
- Метод LocalBroadcastManager.sendBroadcast() отправляет широковещательные сообщения только получателям, определённым в вашем приложении, и не выходит за рамки вашего приложения
Если важно, чтобы приёмники получали намерения в определённом порядке или могли влиять на транслируемое намерение, можно использовать метод sendOrderedBroadcast():
С помощью этого метода ваше намерение дойдёт до всех зарегистрированных приёмников, обладающих необходимым доступом (если он был указан), в порядке их приоритета. Приоритет задаётся с помощью атрибута android:priority внутри узла фильтра намерений в манифесте. Чем больше значение, тем выше приоритет.
Производить упорядоченные трансляции с использованием приоритетов рекомендуется только для тех приёмников, которым необходим конкретный порядок приёма сообщений.
Ограничения в Android 8.0 Oreo (API 26)
Часть неявных (implicit) широковещательных сообщений, задаваемых через манифест, запретили. Теперь нужно регистрировать их программно. Существует список исключений, которые будут работать как прежде без ограничений.
В качестве замены для некоторых случаев подойдёт JobScheduler.
Примерами устаревшего способа работы с приёмником является android.net.conn.CONNECTIVITY_CHANGE, ACTION_POWER_CONNECTED и др.
Ограничения в Android 9.0 Pie (API 28)
Стало доступно меньше информации, получаемой при трансляции системы Wi-Fi и Network_State_Changed_Action.
Источник
Страшная сказка на ночь для пользователей Android
Каждый, наверное, сталкивался с сайтами, предлагающими пользователю платную подписку на ту или иную услугу. В силу специфики моей работы мне иногда приходится проверять подобные ресурсы. Чаще всего они наспех набиты контентом, фальшивыми комментариями и созданы специально для обмана пользователя. Создатели обещают золотые горы, а на деле все заканчивается банальным разводом на деньги. Данная статья — один из частных случаев анализа фейк-сайта с приложением для Android.
Все началось с того, что мне прислали на проверку сайт. По виду — обычный варезный блог с громкими заголовками типа “Бесплатные обои и картинки для андроида”, “Самые умные программы на андроид” и тому подобное. Сразу бросилось в глаза, что во всех постах одинаковые комментарии, оставленные “разными людьми”. Содержание примерно следующее:
— Сайт просит ввести номер телефона, это нормально?
— Да, это для регистрации, проверка, что ты не бот.
— О, круто, спасибо!
В общем факт обмана виден сразу, но я решил копать дальше. При попытке загрузить приложение из любого поста с помощью стационарного компьютера, меня перекидывает на другой ресурс. Ссылка вида http://****/**/?sub_id=* (ага, возможно партнерочка). Там мне предлагают купить за деньги Google Chrome (и ведь ведутся же люди!).
Допустим… Но ведь ресурс посвящен приложениям для Android устройств, значит, нужно попробовать зайти с девайса. Как и следовало ожидать: вместо предложения купить супер-браузер загружается install.apk. “Вот это уже интересно” — подумал я и не ошибся.
Первое, что бросилось в глаза — огромное количество потенциально опасных разрешений.
Не слабый набор, правда? Мне стало интересно, что же приложение делает со всеми этими разрешениями.
Не буду описывать сам процесс декомпиляции, лишь упомяну, что использовал apktools, dex2jar, JD-GUI и jad. В итоге я получил декомпилированные ресурсы и набор классов.
Первое, на что я обратил внимание, это, разумеется, AndroidManifest.xml.
Коротко о разрешениях:
READ_PHONE_STATE — получение информации о телефоне (номер телефона, серийник, информация о вызовах);
SEND_SMS — отправка sms-сообщений;
RECEIVE_SMS — прием sms-сообщений и последующее удаление их (именно поэтому приоритет у MainReceiver наивысший);
INTERNET — использование интернета;
WAKE_LOCK — отключает спящий режим (видимо для повышения стабильности :);
ACCESS_NETWORK_STATE — информация о сетевых соединениях;
RECEIVE_BOOT_COMPLETED — получать сообщения о загрузке устройства, что позволяет выполнять приложение при запуске;
WRITE_EXTERNAL_STORAGE — запись/удаление информации на карте памяти;
INSTALL_PACKAGES — приложение может устанавливать или обновлять пакеты;
DELETE_PACKAGES — приложение может удалять пакеты;
READ_CONTACTS — доступ к контактам;
CALL_PHONE — осуществляет телефонные вызовы;
CALL_PRIVILEGED — осуществляет телефонные вызовы, в том числе по экстренным номерам;
GET_TASKS — получение данных о запущенных приложениях;
SYSTEM_ALERT_WINDOW — показывает сообщения поверх всех окон;
RESTART_PACKAGES — способно завершать фоновые процессы других приложений (официальное описание);
KILL_BACKGROUND_PROCESSES — способно завершать фоновые процессы других приложений (официальное описание);
READ_LOGS — чтение конфиденциальных данных из журнала.
Так же есть ресивер, который срабатывает на следующие намерения:
SMS_RECEIVED — получено sms-сообщение;
custom.alarm — внутреннее событие;
BOOT_COMPLETED — загрузка завершена;
USER_PRESENT — пользователь разблокировал устройство;
PHONE_STATE — изменение состояния сотовой сети (не знаю, как выразиться корректней, также позволяет мониторить вызовы пользователя);
SCREEN_OFF — при отключении экрана;
SCREEN_ON — при включении экрана.
Так как времени на изучение приложение у меня было немного (стояла задача в общих чертах узнать, что делает приложение), я не стал вдаваться во все тонкости. Почти все URL там зашифрованы, и для расшифровки нужно просидеть не один час. Можно, конечно, получить их с помощью WireShark, но в этом нет необходимости.
Работа приложения
Пришло время заглянуть в декомпилированные классы. Начнем пожалуй с MainActivity. Я прокомментирую функции, на которые стоит обратить внимание:
При детальном анализе можно увидеть, что сообщение отправляется сразу, а не после нажатии кнопки “Далее” (как это обычно принято). Лицензионное соглашение есть, но оно очень хорошо запрятано. Но отправка сообщения — это не самая страшная проблема. Помните большое количество разрешений? Давайте посмотрим, зачем они все-таки нужны приложению.
Чтобы сэкономить место и ваше время, я не буду выкладывать MainReceiver. Сразу скажу, что он обрабатывает и удаляет (!) входящие сообщения, а в случае необходимости еще и отвечает.
Самое интересное находится в MainService. При запуске сервис подключается к серверу, запрашивает оттуда данные, получает нечто в json и при успешном ответе запускает метод executeCommands(jsonobject1). И тут начинается магия:
Фактически это троянский конь. Классический такой троянский конь, позволяющий сливать данные пользователя и управлять его телефоном.
Резюме
На хабре не тот контингент, которому стоит читать нотацию на тему “не ставьте не проверенные приложения”, поэтому данную часть своего выступления я опущу.
Первые вредоносные приложения просто отправляли платные sms-сообщения, потом начали рассылать себя всем из списка контактов, а теперь — мы имеем полноценную троянскую лошадь, которую можно дергать за поводья удаленно. Эволюция…
Перечислю еще раз вкратце (для тех, кто пролистал, не читая код с моими комментариями) что умеет делать приложение:
1. Менять URL основного сервера
2. Устанавливать sms-фильтры (удалять то, что попадает в фильтр еще до того, как пользователь успеет получить уведомление)
3. Удалять сообщения
4. Отправлять сообщения
5. Выполнять http-запросы (botnet. )
6. Проверять наличие обновлений и обновляться
7. Удалять произвольные пакеты
8. Отправлять пользователю нотификации
9. Открывать произвольный URL
10. Сливать контакты на сервер
11. Сливать список установленных приложений на сервер
12. Выполнять произвольные вызовы (например, в Замбези)
13. Использовать Twitter в качестве альтернативного способа обновления некоторых данных (к сожалению, декомпиляция прошла с ошибками и не все файлы удалось просмотреть).
Источник