Pull to refresh

Слой радиоинтерфейса в ОС Android

Reading time 6 min
Views 47K
Сегодня я расскажу про то, как устроено взаимодействие с модемом в ОС Android. В данной статье описывается структура компонентов операционной системы Android, ответственных за сетевое взаимодействие по протоколам пакетной передачи данных – GPRS, EDGE, 3G и т.д.
Эта статья содержит большое количество теории, практика же будет во второй статье.

Описание слоя радиоинтерфейса


Рассмотрим, так называемый, слой радиоинтерфейса, от английского – Radio Interface Layer. В ОС Android представляет он представляет собой абстрактный слой между сервисом телефонии (android.telephony) и модемом.


Рисунок 1. Слой радиоинтерфейса.

На рисунке 1 красным цветом выделен слой радиоинтерфейса, который включает в себя:
  • java слой радионитерфейса;
  • RIL демон;
  • планировщик событий;
  • RIL производителя.

Компоненты слоя радиоинтерфейса выполняют следующие задачи:
Java слой радионитерфейса (RIL Java) отправляет запросы RIL демону через локальный Linux сокет /dev/socket/rild. Исходные коды RIL Java располагаются в файле /telephony/java/com/android/internal/telephony/gsm/RIL.java.
RIL демон загружает и инициализирует RIL производителя и планировщик событий. Исходные коды RIL демона располагаются в каталоге /hardware/ril/rild/.
Планировщик событий обрабатывает запрашиваемые и незапрашиваемые команды. Является посредником между RIL Java и RIL производителя. Исходные коды планировщика событий располагаются в каталоге /hardware/ril/libril/.
RIL производителя инициализирует модем, производит взаимодействие непосредственнос с модемом. RIL производителя представляет из себя динамическую библиотеку, разрабатываемую производителем модема. Шаблон для разработки располагается в каталоге /hardware/ril/reference-ril/. Cамыми популярными производителями модемов для мобильных устройств на сегодняшний день являются компании Intel и Qualcomm, а исходные коды библиотек не доступны.

Внутренняя структура RIL демона


На рисунке 2 изображена внутренняя структура RIL демона. Задача RIL демона – инициализировать слой радиоинтерфейса при запуске ОС. Изучив небольшой объём кода RIL демона, можно увидеть, что он осуществляет свою работу по следующему алгоритму:
1. Считывает из настроек системы путь к RIL производителя (rild.libpath) и свойства системы, которые используеются RIL производителем.
2. Загружает RIL производителя и запускает цикл событий в планировщике событий.
3. Вызывает функцию RIL_Init для инициализации и получения ссылок на функции RIL производителя.
4. Вызывает функцию RIL_register, для регистрации планировщиком событий ссылок на функции RIL производителя.


Рисунок 2. Внутренняя структура RIL демона.
Существует два вида взаимодействия между компонентами слоя радиоинтерфейса: запрашиваемые (solicited) и незапрашиваемые (unsolicited) команды. Запрашиваемые команды инициируются сервисом телефонии, например исходящий звонок, установление интернет соединения. Незапрашиваемые команды инициируются модемом, например входящее SMS сообщение, входящий звонок.

Связь между сервисом телефонии и планировщиком событий

Взаимодействие между RIL Java и планировщиком событий происходит через локальный Linux сокет /dev/socket/rild. Каждый запрос к уровню библиотек записывается в экземпляр класса com.android.internal.telephony.RILRequest, для сохранения информации о запросе, до тех пор, пока не будет получен ответ от нижележащих слоев радиоинтерфейса.
Параметры запроса записываются в структуру parcel, а сам запрос отправляется в класс com.android.internal.telephony.RIL.RILSender. Формат запроса указан на рисунке ниже:

Класс com.android.internal.telephony.RIL.RILReceiver прослушивает локальный Linux сокет, ожидая ответов от планировщика событий. RILReceiver получает два вида ответов: запрашиваемые и незапрашиваемые. Их формат представлен на рисунках ниже.

Рисунок 4. Формат запрашиваемого ответа.

Рисунок 5. Формат незапрашиваемого ответа.

Реализация RIL производителя


Для реализации RIL производителя компания-производитель модема разрабатывает динамическую библиотеку, которая реализует множество функций, необходимых операционной системе Android для обработки запросов, адресованных модему. Её название определяется следующим соглашением: libril-<название компании>-<версия RIL>.so
В заголовочном файле /include/telephony/ril.h содержится:
  • описание множества структур, например: RIL_RadioState, RIL_Data_Call_Response;
  • прототипы функций, например: RIL_Init, RIL_onRequestComplete;
  • числовые определения для запрашиваемых и незапрашиваемых команд, например: #define RIL_REQUEST_SETUP_DATA_CALL 27.

Слой радиоинтерфейса является аппаратно независимым и RIL производителя может использовать любой протокол для взаимодействия с модемом. Как правило, используется множество стандартизованных Hayes AT-команд, тем не менее, некоторые производители модемов дополняют стандартный набор AT-команд своими собственными расширениями.
Для управления запрашиваемыми командами производитель модема должен реализовать набор функций, прототипы которых описаны ниже. Типы запросов запрашиваемых команд определены в заголовочном файле ril.h с префиксом RIL_REQUEST_.
  • void (*RIL_RequestFunc)(int request,void *data, size_t datalen,RIL_Token t) 
    
    это функция обработки запрашиваемых команд. Именно она обрабатывает запрашиваемые команды, которые определены в заголовочном файле ril.h и начинаются с префикса RIL_REQUEST_.
  • RIL_RadioState (*RIL_RadioStateRequest)() 
    
    эта функция возвращает текущее состояние модема.
  • int (*RIL_Supports)(int requestCode)
    
    функция возвращает 1, в случае если данный код запроса поддерживается, и 0 в противном случае.
  • void (*RIL_Cancel)(RIL_Token t)
    
    эта функция используется для индикации того, что незавершенный запрос будет отменён. Вызывается в отдельном потоке, отличном от того, в котором вызвана функция RIL_RequestFunc.
  • const char * (*RIL_GetVersion) (void)
    
    возвращает версию RIL производителя.

RIL производителя использует следующие обратные вызовы для связи с RIL демоном:
  • void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen)
    
    сообщает о том, что запрашиваемая команда была обработана.
  • void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime)
    
    функция отвечающая за промежуток времени, спусти который необходимо произвести обратный вызов.

Функция обратного вызова, которая используется производителем RIL для запуска незапрашиваемых команд должна иметь следующий вид:
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen);


Запрашиваемые команды

Существует 61 запрашиваемая команда. Их можно сгруппировать следующим образом:
  • работа с SIM картой, вводом/выводом и уникальным идентификатором устройства (11);
  • статус и обработка звонка (16);
  • сетевой статус (4);
  • сетевые настройки (12);
  • SMS сообщения(3);
  • соединение по протоколам пакетной передачи данных(4);
  • питание и перезапуск (2);
  • дополнительные сервисы (5);
  • определения и поддержка производителя (4).

Рисунок 6 иллюстрирует последовательность вызовов на различных уровнях слоя радиоинтерфейса при поступлении запрашиваемой команды «установление интернет соединения»:
1. RIL Java вызывает RILSender.handleMessage() и отправляет планировщику событий через локальный Linux сокет /dev/socket/rild запрос с сгруппированными аргументами.
2. Планировщик событий последовательно вызывает listenCallback(), processCommandCallback(), proccessCommandBuffer(), производит предварительную обработку данных и вызывает dispatch(Request code)
3. В RIL производителя вызывается функция OnRequest(), в которой по коду запроса (SETUP_DATA_CALL) определяется какое действие должно осуществляться в дальнейшем. RIL производителя отправляет соответсвующую запросу последовательность AT-команд модему и принимает ответы на них. Заканчивает обработку кода запроса вызовом функции OnRequestComplete(). Если необходимо, отправляет ответ планировщику событий.
4. Планировщик событий обрабатывает ответ от RIL производителя и вызывает функцию response(Request code) и отправляет ответ RIL Java.
5. RIL Java принимает ответ с помощью метода RILReceiver.run().


Рисунок 6. Запрашиваемая команда.

Незапрашиваемые команды

Существует 11 незапрашиваемых команд, сгрупированных следующим образом:
  • изменение сетевого статуса (4);
  • входящее SMS сообщение (3);
  • входящее USSD уведомление (2);
  • изменение силы сигнала или времени (2).



Рисунок 7. Незапрашиваемая команда.
Рисунок 7 иллюстрирует последовательность вызовов на различных уровнях слоя радиоинтерфейса при поступлении незапрашиваемой команды «входящее SMS сообщение»:
1. От модема приходит AT-ответ, RIL производителя считывает его и вызывает соответствующую функцию обработчик. RIL производителя подготавливает данные для отправки их планировщику событий. Заканчивает обработку вызовом OnUnsolicitedResponse().
2. Планировщик событий обрабатывает данные, пришедшие с ответом, отправляет ответ RIL Java через локальный Linux сокет /dev/socket/rild.
3. RIL Java принимает ответ с помощью RILReceiver.run().

В следующей статье я планирую рассказать про то, как написать свою программу для взаимодействия непосредственно с модемом и чего таким образом можно добиться.
При написании статьи использовались:
1. Исходные коды ОС Android android.googlesource.com
2. dpsm.wordpress.com/2010/09/01/smart-phones-are-still-phones
3. www.netmite.com/android/mydroid/development/pdk/docs/telephony.html
4. www.slideshare.net/ssusere3af56/android-radio-layer-interface
Tags:
Hubs:
+67
Comments 11
Comments Comments 11

Articles