Пользователь
0,0
рейтинг
20 июня 2013 в 22:36

Разработка → Слой радиоинтерфейса в ОС Android из песочницы

Сегодня я расскажу про то, как устроено взаимодействие с модемом в ОС 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
@stoplinux
карма
18,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (11)

  • +1
    В следующей статье я планирую рассказать про то, как написать свою программу

    Пишу подобную программу, на данный момент вклинился между rild и Ril.java. Пока только «слушаю» сообщения в оба направления. Спасибо за статью! Жду продолжения.
  • +2
    Я использую андроид-устройства уже несколько лет, и есть у них особенность работы с сетью, которая всё это время не даёт мне покоя. Касается это в первую очередь 3g-сетей, хотя изредка случается и с вай-фаем. Выражается примерно в следующем:

    1) смартфон показывает хороший уровень соединения с сетью и индикатор H (HSDPA, условно, случается на всех индикаторах)
    2) я пробую в каком-то приложении запустить функцию, требующую соединения (например, в приложении вконтактика тяну страничку вниз, чтобы обновить новости или отправляю картинку в твиттер).
    3) приложение рисует бегунок обновления, обновление не происходит, как будто сети нет
    4) индикатор связи с сетью может поменяться на другой (а может и не поменяться, только дёрнется уровень сигнала)
    5) приложение висит в состоянии обновления достаточно долго (минуту и больше), после чего процесс заканчивается, но обновление не происходит
    6) повторный запуск обновления быстро и беспроблемно отрабатывает, загружая свежие данные.

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

    И вот раз уж зашла на хабре речь про взаимодействие андроид-приложений с сетью, хотелось бы услышать комментарии сведущих людей, с чем связана эта проблема, является ли она косяком ОСи, приложения и возможно ли её исправить.
    • 0
      Это и на обычных ПК есть. Например, выдергиваем сетевой хвост и запускаем RDP соединение до сервера. Подключаем хвост, а приложение как висит в статусе «Подключение...», так и дальше продолжает. Но если параллельно новое запустить уже в нормальном состоянии — все сработает.
    • 0
      А стрелочки передачи данных при этом появляются?
  • –2
    Спасибо! А кстати — с чем связано что телефон Android 4.2 с четырехядерным процем и 1,5Ghz частотой вытягивает по WiFi файл с ресурса по SAMBA протоколу крайне медленно? При скорости WiFi 54 Mbit/s закачка идет макс. 50 кбит/с !? Куда вся разница уходит? Даже тупой ноут копирует файл > 1мбит/s
    • 0
      100% c модемом связано.
  • 0
    Спасибо за пост. Имею вопрос: Как в сети GSM узнать ARFCN номер частоты, на которой сидит телефон?
    • 0
      Модем таких функций не предоставляет. Узнать можно при наличии специального оборудования или при имитации базовой станции. Зачем Вам её знать?
      • +1
        Зачастую становится обидно, что Android по функционалу не дотягивает до нокиевских нетмониторов. А номера каналов и частоты очень даже могут пригодится в работе инженеров или простых энтузиастов.
        • 0
          Если такая возможность существует, то она наверняка описана в документации к модему. Вот например хорошая подборка к популярному модему forum.xda-developers.com/showthread.php?t=1483053
  • 0
    :) специального оборудования? Nokia E52 на симбиане с FieldTest приходится таскать, чтобы сесть на нужный канал и проверить качество в полевых условиях. А в андроидовых нетмониторах даже информация о номере канала отсутствует, интересно, почему из ОСи такая информация недоступна.

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