Такие приложения, как Tasker и Locale, уже давно стали одним из главных аргументов в споре поклонников Android и iOS. Действительно, обычные, не требующие ни прав root, ни прав администратора приложения, а позволяют творить со смартфоном такое, что любой ветеран Linux-скриптинга обзавидуется. Как же они работают и почему подобных приложений нет в iOS и других мобильных системах? Все дело в Binder — IPC/RPC-механизме, пронизывающем весь Android.

 

Вместо введения

Создатели Android, имея возможность продумать архитектуру ОС с нуля, учитывая современные реалии, закономерно решили изолировать установленные приложения друг от друга. Так появилась идея использовать песочницы, поэтому Android-приложение: а) имеет доступ только к своему собственному каталогу и (если есть такие полномочия) к SD-карте — не содержащей важных данных свалке барахла, б) может использовать только заранее оговоренные возможности ОС (а в Android 6.0 пользователь может отозвать такие полномочия прямо во время работы программы) и в) не имеет права запускать, создавать каналы связи или вызывать методы других приложений.

Реализовано это все с помощью стандартных прав доступа к файлам (в Android каждое приложение работает с правами созданного специально для него пользователя Linux), многочисленных проверок на полномочия доступа к ресурсам ОС на всех уровнях вплоть до ядра и запуска каждого приложения в своей собственной виртуальной машине (сейчас ее уже сменил ART, но сути это не меняет).

Все эти механизмы отлично работают и выполняют свои функции, но есть одна проблема: если приложения полностью отрезаны друг от друга, вплоть до исполнения от имени разных юзеров, то как им общаться и как они должны взаимодействовать с более привилегированными системными сервисами, которые суть те же приложения? Ответ на этот вопрос — система сообщений и вызова процедур Binder, одна из многочисленных находок создателей легендарной BeOS, перекочевавшая в Android.

Binder похож на механизм COM из Windows, но пронизывает систему от и до. Фактически вся высокоуровневая часть Android базируется на Binder, позволяя компонентам системы и приложениям обмениваться данными и передавать друг другу управление, четко контролируя полномочия компонентов на взаимодействие. Binder используется для взаимодействия приложений с графической подсистемой, с его же помощью происходит запуск и остановка приложений, «общение» приложений с системными сервисами. Binder используется даже тогда, когда ты запускаешь новую активность или сервис внутри своего приложения, причем по умолчанию сервис работает в том же процессе, что и основная часть приложения, но его очень легко вынести в отдельный процесс, просто добавив одну строку в манифест. Все будет работать так, как и раньше, и благодарить за это надо Binder.

Сказанное может показаться тебе несколько странным, и, возможно, ты впервые слышишь о каком-то магическом Binder, но это благодаря тому, что Android абстрагирует программиста от прямого общения с этим драйвером (да, он реализован в ядре и управляется с помощью файла /dev/binder). Но ты точно имел дело с интентами, абстрактной сущностью, построенной поверх Binder.

 

Магические интенты

В Android объект класса Intent является абстракцией сообщения Binder и по большому счету представляет собой способ передачи управления компонентам своего или чужого приложения, вне зависимости от того, запущено приложение, к которому относится данный компонент, или нет. Банальнейший пример — запуск активности:

Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
Процесс общения компонентов приложения через Binder
Процесс общения компонентов приложения через Binder

Это пример так называемого явного интента. Есть класс SecondActivity, в котором есть метод OnCreate(), а мы просто говорим системе: «Хочу запустить активность, реализованную в данном классе». Сообщение уходит, система его получает, находит метод OnCreate() в классе SecondActivity и запускает его. Скучно, просто, а местами даже тупо. Но все становится намного интереснее, если использовать неявный интент. Для этого немного изменим наш пример:

Intent intent = new Intent("com.my.app.MY_ACTION");
startActivity(intent);

И модифицируем описание активности в манифесте:

<activity android:name="com.my.app.SecondActivity" android:label="@string/app_name" >
  <intent-filter>
    <action android:name="com.my.app.MY_ACTION" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Результат будет тот же, а возни намного больше. Однако есть одно очень большое но: в данном случае мы использовали не имя компонента, который хотим запустить (SeconActivity), а действие, которое хотим выполнить (com.my.app.MY_ACTION), а формулировка «Я хочу запустить…» превратилась в «Я хочу выполнить такое-то действие, и мне плевать, кто это сделает». В результате нашу активность теперь можно запустить из любого другого приложения точно таким же способом. Все, что нужно, — это указать действие, все остальное система сделает сама.

Может показаться, что все это немного бессмысленно и бесполезно, но взгляни на следующий пример:

Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:12345678900"));
startActivity(intent);

Этот простой код позволяет позвонить любому абоненту (при наличии полномочия android.permission.CALL_PHONE), а все благодаря тому, что приложение Phone умеет обрабатывать действие Intent.ACTION_CALL (точно таким же способом, как в нашем примере, с помощью intent-filter). Более того, если на смартфоне установлена сторонняя «звонилка», которая умеет реагировать на то же действие, система спросит, какое именно приложение использовать для звонка (а юзер может выбрать вариант, который будет использован в будущем).

Существует множество стандартных системных действий, которые могут обрабатывать приложения, например Intent.ACTION_VIEW для открытия веб-страниц, изображений и других документов, ACTION_SEND для отправки данных (стандартный диалог «Поделиться»), ACTION_SEARCH и так далее. Плюс разработчики приложений могут определять свои собственные действия на манер того, как мы это сделали во втором примере. Но одно действие обязаны обрабатывать все приложения, которые должны иметь иконку на рабочем столе, — это android.intent.action.MAIN. Среда разработки сама создает для него intent-filter и указывает MainActivity в качестве получателя. Так что ты можешь даже не подозревать о том, что твое приложение умеет его обрабатывать, но именно оно позволяет рабочему столу узнать, что на смартфон установлено твое приложение.

Однако все это не так уж и интересно, и в этой статье я бы хотел сконцентрироваться на другом аспекте интентов и Binder, а именно на широковещательных сообщениях.

 

Широковещательные сообщения

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

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

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

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

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

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


Комментарии

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

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

Check Also

Как сделать игру. Выбираем движок и пишем клон тех самых «танчиков»

С каждым днем игры становятся все сложнее и навороченнее. Быть инди, а точнее соло-разрабо…