Продолжаю рассказ о технологии виртуализации Android, сделанной в Параллельс Лаборатория группа студентов Кафедра МиИТ Академического университета Санкт-Петербурга в рамках магистерской диссертации.
Во вчерашней статье Для этого мы рассмотрели общую концепцию виртуализации устройств Android. Цель сегодняшнего поста — понять суть виртуализации телефонии, звука и систем пользовательского ввода.
Аудио и телефония были виртуализированы в пользовательском пространстве.
Общая идея такой виртуализации — реализация прокси (сервера и клиента) на уровне аппаратно-независимого интерфейса в стеке Android. Прокси-сервер размещается в отдельном контейнере со стеком программного обеспечения оригинальной операционной системы для выполнения клиентских запросов на физических устройствах.
Прокси-клиент размещается в каждом контейнере с пользователем Android.
Аудио-устройство
Типичным сценарием использования аудиоустройства при запуске нескольких устройств Android является прослушивание музыки в одной ОС и воспроизведение звука игры, запущенной в другой.Вероятно, пользователю хотелось бы слышать звук всех работающих Андроидов, но на самом деле физическое звуковое устройство для этого не предназначено.
При попытке его использования ОС сообщает об ошибке и иногда не может воспроизводить звук до следующей перезагрузки.
Виртуализация аудиоустройств должна позволить прослушивать звук со всех устройств Android одновременно.
Также необходимо реализовать взаимодействие со службой телефонии так, чтобы во время телефонного разговора аудиоустройство записывало и передавало в сотовую сеть голос пользователя и воспроизводило голос собеседника, полученный из сотовой сети.
Прокси-клиент Заменяющим аппаратно-независимым интерфейсом аудиоустройства является интерфейс AudioHardwareInterface, о котором нам необходимо знать.
говорит Руководство разработчика платформы Android. Кроме того, это самый низкоуровневый и простой аппаратно-независимый аудиоинтерфейс.
По сути, это поток для записи звука для воспроизведения.
Помимо аудиопотока, воспроизводимого Android, его реализация может предоставить и другую полезную информацию.
Можно было бы выполнить замену на более высоком уровне.
Например, заменить часть аудиофреймворка Android. Но анализ показал, что аудиофреймворк гораздо сложнее, чем AudioHardwareInterface. Таким образом, прокси-клиент в случае виртуализации аудиоустройства является реализацией AudioHardwareInterface. Основная обязанность прокси-клиента — отправлять аудиопоток Android и другую полезную информацию на прокси-сервер, который будет воспроизводить аудиопотоки всех Android-устройств.
Аудиопотоки воспроизводятся в несжатом виде, поэтому их передача с помощью копирования на прокси-сервер может привести к значительным накладным расходам.
Мы избегаем их, используя общую память между контейнерами для передачи аудиопотоков.
Информационные и управляющие сообщения передаются с использованием механизма передачи сообщений между контейнерами.
Прокси сервер Основная задача прокси-сервера — микшировать аудиопотоки, полученные от прокси-клиентов, и воспроизводить полученный аудиопоток на физическом аудиоустройстве.
Чтобы обеспечить максимальную переносимость прокси, микширование и воспроизведение звука должно быть независимым от устройства.
Интерфейсы аудиоплатформы Android не зависят от оборудования.
Кроме того, аудиофреймворк уже включает в себя возможности микширования аудиопотоков.
Аудиофреймворк Android не предоставляет внешний доступ к своему микшеру, поэтому для его использования необходимо либо внедриться в аудиофреймворк, либо неявно использовать микшер.
Архитектура нашего решения по виртуализации звука показана на рисунке.
Самое простое решение, позволяющее микшировать и воспроизводить аудио в Android, — использовать аудиоклассы из Android SDK. В нашем решении аудиопоток каждого пользователя воспроизводится отдельным объектом класса AudioTrack из Android SDK. Использование классов позволяет аудиоплатформе Android смешивать все воспроизводимые аудиопотоки и отправлять полученный аудиопоток для воспроизведения через динамик устройства или выход на наушники.
Следует отметить, что классы из Android SDK написаны на Java, и для их использования требуется запуск виртуальной машины Dalvik Java. Запуск Dalvik в случае Android означает запуск всей ОС благодаря используемому ею механизму начальной загрузки.
Здесь мы сталкиваемся с проблемой: работающий Android занимает 200–250 МБ оперативной памяти и потребляет вычислительные ресурсы.
Это непомерные накладные расходы для задачи воспроизведения и микширования аудиопотоков, но в данной работе нам удалось этого избежать.
Фактически мы используем не Java-классы из Android SDK, а их родной бэкенд, написанный на C++.
Вот почему запуск Dalvik и, следовательно, запуск полноценного контейнера Android не требуется.
Полностью нативные приложения, такие как прокси-сервер, не могут зарегистрироваться в системе контроля прав Android. При этом сервисы, к которым обращался прокси-сервер, спокойно игнорировали запросы из-за отсутствия прав.
Все решилось удалением проверок прав в этих сервисах.
Мы проделали этот трюк со спокойной душой, так как это удаление не влияет на безопасность.
Никакие внешние приложения никогда не запускаются в контейнере с прокси-сервером; он полностью находится под контролем технологии виртуализации.
Регулировка уровня звука Вероятно, пользователю хочется, чтобы громкость звука на разных Андроидах можно было регулировать.
Оказалось, что в Android 2.x нет аппаратной абстракции микшера, т.е.
микширование осуществляется через ЦП.
Поскольку микширование звука в каждом Android полностью независимо (нет общего аппаратного микшера), общий уровень громкости каждого Android можно регулировать внутри самого Android. Прокси просто не вносит изменений в уровни звука каждой ОС, а пользователь настраивает уровни звука каждого Android в своем пользовательском интерфейсе, как если бы на телефоне не было виртуализации.
Устройства вывода звука Мобильные устройства обычно имеют несколько устройств вывода звука.
Например, большой динамик, телефонная трубка, наушники, Bluetooth-гарнитура.
Одновременный запуск операционных систем может потребовать воспроизведения их аудиопотоков на разных устройствах вывода.
В некоторых случаях их требования будут несовместимы.
Например, нет смысла воспроизводить один звук на большом динамике, а другой — на наушниках или телефоне.
Также будет странно, если во время разговора вы сможете услышать не только голос собеседника, но и музыку, которая играла до звонка.
Поэтому была разработана политика маршрутизации аудиопотоков на различные устройства вывода, реализующая стратегию «наименьшего сюрприза» для пользователя.
Эта стратегия, в частности, иногда требует эмуляции воспроизведения звука Android. Для этого прокси-клиент переводится в режим фиктивного воспроизведения, в котором синхронные функции блокируются на время воспроизведения части аудиопотока, в результате чего Android думает, что он воспроизвел звук, хотя на самом деле он не был отправлен на прокси-сервер для воспроизведения.
Взаимодействие со службой телефонии В прокси-клиенте, который является реализацией AudioHardwareInterface, мы можем получить информацию о том, идет ли в данный момент телефонный разговор или нет. Если идет разговор, то необходимо настроить аудиоподсистему для записи и воспроизведения голоса и взаимодействия со службой телефонии.
Фактически для этого достаточно перевести поставляемую с устройством реализацию AudioHardwareInterface в режим вызова, вызвав метод setMode(MODE_IN_CALL) и задать маршрутизацию звука на трубку, иначе голос собеседника будет воспроизводиться текущим аудиовыходом устройство.
Таким образом, за реализацию взаимодействия со службой телефонии отвечает производитель устройства.
Телефония
Самой интересной и сложной технологией стала диспетчеризация телефонных звонков между контейнерами.Программный стек управления оборудованием для доступа к мобильным сетям на Android содержит следующие компоненты: 1. Пакет API com.android.internal.telephony. 2. Демон rild, мультиплексирующий запросы от пользовательских приложений в оборудовании доступа к мобильной сети.
3. Собственная библиотека доступа к оборудованию.
4. Драйвер GSM-модема.
Интерфейс между компонентами (2) и (3) документирован и называется уровнем радиоинтерфейса или RIL. Это описано в файле development/pdk/docs/porting/telephony.jd. Для виртуализации RIL пришлось решить следующие проблемы: Собственные реализации RIL в различных устройствах Android пытаются повторно инициализировать оборудование; Непонятно, какой Android должен принимать входящие звонки и СМС; Непонятно, как управлять звонками и СМС с разных Android-устройств.
Здесь также следует отметить, что реализация драйверов GSM-модема существенно различается на разных устройствах, поэтому существование универсального решения для виртуализации этого устройства в ядре невозможно.
Кроме того, фирменная библиотека RIL использует недокументированный протокол взаимодействия с GSM-модемом, что является препятствием для его виртуализации даже для конкретной модели смартфона.
Клиентская часть Конкретная реализация библиотеки RIL на телефоне неизвестна, но известен ее интерфейс.
Мы создали уровень абстракции в виде виртуального прокси-сервера RIL и клиента RIL. На стороне клиента демон rild вместо исходной библиотеки RIL загружает реализованный нами RIL-клиент. Клиент RIL, перехватывая обращения к интерфейсу, транслирует вызовы с помощью механизма межконтейнерного взаимодействия прокси-сервера RIL, который, в свою очередь, выполняет основную виртуализацию интерфейса, а для доступа к телефонии использует исходную библиотеку RIL. Серверная часть Серверная часть реализована как однопоточное приложение, которое загружает собственную реализацию RIL и, используя механизм межконтейнерной связи, получает сообщения от прокси-клиентов, работающих в пользовательских контейнерах.
В обработчике OnRequestComplete мы не знаем тип запроса, но от этого зависит способ упаковки фирменной реализации ответа RIL, поэтому при поступлении запроса сервер запоминает соответствие токена номеру запроса по порядку для вызова требуемого маршалера ответа в этом обработчике.
Прокси-сервер RIL должен обрабатывать ситуацию, когда от разных клиентов поступают запросы с одинаковыми токенами, поэтому при поступлении следующего запроса прокси-сервер просматривает список токенов запроса, обработанных собственной библиотекой RIL, и, если окажется, что запрос с таким токеном в данный момент обрабатывается, то сервер генерирует новый токен для входящего запроса.
Таким образом, прокси-сервер хранит свои настоящие и фиктивные токены для всех входящих запросов.
Запросить политику маршрутизации Для каждого типа запроса, поступающего в OnRequest, определяется политика обработки.
В настоящее время определены три политики:
- Безусловная блокировка запроса.
Политика настроена для всех запросов, которые никогда не встречались в процессе разработки прокси-сервера.
- Безоговорочная передача запроса в проприетарную библиотеку.
Политика распространяется на все запросы, не меняющие состояние фирменной библиотеки и GSM-модема.
- Передача запроса из активного контейнера в проприетарную библиотеку.
Служит для запросов, связанных с отправкой SMS и совершением звонков.
- Безусловная блокировка уведомлений.
- Маршрутизация в активный контейнер.
Политика настроена для уведомлений, связанных с приемом СМС и звонков.
- Маршрутизация ко всем контейнерам.
Для служебных уведомлений оборудования — например, об изменении уровня сигнала сотовой сети.
Подсистема ввода
Android использует подсистему evdev для сбора событий ввода ядра.Для каждого процесса, открывающего файл /dev/input/eventX, этот драйвер создает очередь событий, поступающих от ядра подсистемы ввода.
Таким образом, входящие события ввода могут быть доставлены во все контейнеры.
Функция evdev_event() является диспетчером событий ввода, поэтому, чтобы предотвратить доставку входных сообщений в неактивные контейнеры, эта функция была изменена таким образом, чтобы все входящие события ввода добавлялись только в очереди процессов активного контейнера.
Немного о тестировании
После того как нам удалось запустить наше решение на смартфонах, мы провели серию экспериментов, чтобы количественно оценить характеристики нашего решения.Скажу сразу, над оптимизацией мы не работали — эту работу еще предстоит сделать.
Основными целями тестирования были:
- демонстрация готовности разработанной технологии;
- измерение потребления памяти на виртуализированных телефонах;
- определение энергоемкости разработанной технологии.
Тестовые сценарии выполнялись на трех конфигурациях: 1. Оригинальная среда CyanogenMod 7 для Samsung Galaxy S II (1); 2. Один контейнер с CyanogenMod 7 (2); 3. Два контейнера с CyanogenMod 7: в одном контейнере проигрывалась музыка, в другом запускалась игра (3).
В каждом тестовом прогоне измерялись следующие параметры: 1. Объем свободной памяти и размер кэша файловой системы (согласно /proc/memрinfo); 2. Заряд аккумулятора (согласно /sys/class/power_supply/battery/capacity. Каждый тестовый прогон длился 30 минут, измерения проводились с периодичностью 2 с.
Вот что мы получили:
Может показаться странным, что потребление памяти в случае с контейнерами меньше, чем в реальной среде.
Точная причина не установлена (мы пока не пытались разобраться в этом вопросе), но такой же эффект наблюдается и в проекте Cells, который они описали.
Тестирование показало приемлемость разработанных решений и продемонстрировало незначительное потребление памяти и аккумулятора смартфона разработанной технологией, за исключением случая (последняя строка таблицы), при котором наблюдается увеличение энергопотребления в два раза.
контейнеры почти в два раза по сравнению с немодифицированным Android. В настоящее время ведутся работы по выяснению причин такого поведения.
Как видно из значений потребления памяти, при запуске второго контейнера оно увеличивается более чем в 2 раза, что является препятствием для запуска нескольких контейнеров на одном смартфоне: эксперименты показывают, что смартфон Google Nexus S, имеющий 380 МБ, невозможно запустить более одного контейнера без активации файла подкачки.
Заключение
Значительная часть технологических новостей сейчас генерируется вокруг мобильных устройств.Магистерский (или дипломный, как вам больше нравится) проект группы студентов показал жизнеспособность технологии виртуализации на мобильных устройствах и дал представление о том, как эту технологию можно использовать для создания продуктов.
Несколько интересных цифр и фактов о создании нашего решения:
- Основных разработчиков проекта трое, двое из них на момент завершения работы были студентами Академического университета в Санкт-Петербурге, а один руководил дипломным проектом;
- Проект длился 11 месяцев;
- Проект получил консультации инженеров московского офиса Parallels;
- В проекте были задействованы три Android-устройства.
Я постараюсь на них ответить.
Теги: #Android #Разработка Android #Виртуализация
-
Понимание Доступа К Удаленному Управлению
19 Oct, 24 -
Пишем Hello World Для Hololens
19 Oct, 24 -
Деревянные Игрушки, Часть Седьмая - 1993 Г.
19 Oct, 24 -
Создание Доменных Зон В Azuredns [Шпаргалка]
19 Oct, 24 -
Радиорынок Санкт-Петербурга Юнона
19 Oct, 24