- PVSM.RU - https://www.pvsm.ru -
В пятницу на Хабре было опубликовано видео [1] о том, как работает виртуализация на смартфонах Android. Ее разработали и довели до стадии прототипа в Parallels Labs [2] два студента Академического университета Санкт-Петербурга. Мне посчастливилось узнать, что у технологии под капотом, а также спросить участников проекта, какие задачи они решали, как преодолевали возникающие трудности и к чему в результате пришли. Обзор запланирован в двух частях. В этом посте будет короткий обзор существующих решений для виртуализации на Android, понятные схемы архитектуры нашего решения, короткое видео того, как все работает. Во второй части будет больше конкретики. Речь пойдет о виртуализации телефонной части смартфонов, звуковой подсистемы и системы ввода.
Я покажу, что у нашего решения под капотом. Расскажу, какие задачи решала группа разработчиков, как преодолевались возникающие трудности и какой результат был достигнут. Статья состоит из двух частей. В первой (под катом) будет короткий обзор существующих решений для виртуализации на Android, понятные схемы архитектуры решения, короткое видео того, как все работает. Во второй части будет больше конкретики. Речь пойдет о виртуализации телефонной части смартфонов, звуковой подсистемы и системы ввода.
Концепция Bring Your Own Device (или BYOD), когда сотруднику разрешено работать с самым удобным для него «железом», — палка о двух концах. С одной стороны, юзеру удобно использовать на службе то, чем он привык пользоваться дома. Это теоретически повышает его производительность труда. С другой — BYOD добавляет головной боли системным администраторам и IT-директорам, которые вынуждены каким-то образом решать задачу защиты корпоративных приложений и данных, которые теперь крутятся на смартфоне. Один из основных подводных камней – пользовательское поведение. Часто юзеры игнорируют запрет на закачку и установку демо-версий стороннего ПО, хотя внутри таких приложений может прятаться вирус или «троянец».
Очевидный способ оградиться от такого рода угроз – создать для ненадежного ПО специальную «песочницу»; либо, наоборот, создать такую «песочницу» для корпоративного софта и бизнес-данных. Оба подхода должны быть реализованы деликатно, то есть без посягательств на частную (SMS, фотки с вечеринок и др.) информацию сотрудника. Такие «песочницы» встречаются сплошь и рядом в индустрии разработки и тестирования ПО и создаются с помощью виртуализации. Мы решили сделать нечто подобное, но – на смартфонах.
Прежде чем погружаться в технические детали, рассмотрим весь зоопарк существующих решений и технологий виртуализации. Это нужно, чтобы понять, какой же конкретно подход может быть интересен для реализации нашей технологии. Первые известные попытки виртуализации мобильных устройств были начаты в 2008 году, и к настоящему моменту имеется несколько успешных подходов и проектов. Конечно, мы рассматривали наиболее зрелые и жизнеспособные подходы. Все они собраны для наглядности на одной на картинке, о каждой будет несколько слов отдельно.
Cells – первый проект, в рамках которого создана технология контейнерной виртуализации для платформы Android. (Что такое контейнеры и почему Android удобнее всего виртуализировать с помощью контейнеров, мы разберем немного позже.) Технология обеспечивает совместный доступ одновременно работающих окружений Android к устройствам ввода, графическому ускорителю, модулю сотовой связи и сетевым устройствам, а также позволяет ограничивать доступ контейнера к каждому системному устройству. Измерения показывают, что требования этой технологии к вычислительным ресурсам, а также расход заряда батареи устройства компонентами этой технологии незначительны.
VMware Horizon Mobile — полноценный гипервизор второго типа, виртуализирующий аппаратное обеспечение абстрактной машины. Под проект было создано ядро Linux с патчами Android, поверх которого запускается созданное VMware пользовательское окружение Android. Гипервизор работает на распространенных типах процессоров ARM, не имеющих расширений для аппаратной виртуализации, и является процессом в хостовой (основной) ОС — например, в родной для Android-девайса операционке. Очевидно, что в данном случае виртуализация всего аппаратного обеспечения требует достаточно много вычислительных ресурсов. Но, что еще важнее, запуск более чем одного гипервизора будет слишком быстро «высаживать» батарейку. Планшет, разряжающийся за полчаса, никому не нужен. К тому же подход VMware показался существенно сложнее в реализации, чем подход Cells.
TrustDroid является прототипом системы изоляции приложений для платформы Android, основанной на доменах доверия. Каждому приложению (в том числе стандартным приложениям Android) назначается домен. Приложения из разных доменов не могут взаимодействовать между собой и не могут работать с данными, опубликованными приложениями из других доменов. TrustDroid не использует виртуализацию аппаратного обеспечения или пространства пользователя. Для поддержки политики доменов изменения вносятся в ядро и в стандартные системные приложения Android. Данная система является самой нетребовательной к ресурсам по сравнению с двумя предыдущими.
Реализация сценариев BYOD и создание песочницы различна: в случае Cells и VMware политики настраиваются на уровне пользовательских окружений Android; при использовании же TrustDroid пользователю необходимо настраивать политики и домены вручную для каждого приложения. Это сложнее и муторнее для пользователя, потому что пользовательских окружений может быть несколько. У TrustDroid не все ОК с безопасностью. Предполагается, что стандартные системные приложения Android и ядро ОС никогда не скомпрометированы, но это может быть неверно, т.к. при получении прав суперпользователя их можно подменить.
Недостатки можно преодолеть, значительно доработав TrustDroid. Тем не менее, TrustDroid решает только задачу обеспечения безопасности на устройстве, в то время как пользователю также важна возможность изоляции данных, находящиеся в разных окружениях.
EmbeddedXEN — проект по портированию XEN на платформу ARM. Проект, насколько мне известно, пока не вышел из стадии активной разработки, а посему не может рассматриваться как законченное решение. В настоящее время в проекте уже адаптированы версии ядра Linux HTC Desire HD для работы в качестве Dom0.
Разобравшись с возможными решениями, и попытками виртуализации, мы пришли к выводу что именно контейнерная виртуализация – то, что нам подходит больше всего. Во-первых, мы хотим использовать максимум готовых существующих решений, а ядро операционной системы Linux, поверх которого работает Android, имеет встроенный механизм разделения системных ресурсов. Этот механизм широко используется провайдерами для реализации VPS-хостинга и называется контейнерами Linux (или LXC — от Linux Containers). Он выполняет несколько функций: работает как интерфейс инфраструктуры пространств имен ядра Linux для изоляции идентификаторов процессов, виртуализации сети, а также как «точка доступа» к инфраструктуре управления ресурсами cgroup.
Портирование такого количества изменений на ядро 2.6.35 показалось нам чрезмерным. Но, отказавшись от OpenVZ, мы лишились готового решения по виртуализации sysfs: при создании нового виртуального окружения OpenVZ копирует дерево системных объектов (kobject) корневого пользовательского окружения, что потребовало от нас дополнительных усилий.
Итак, решено было использовать стандартные Linux-контейнеры LXC и всю инфраструктуру ядра, отвечающую за реализацию пространств имен (namespaces) и разграничение групп ресурсов.
На рисунке показана архитектура нашего решения.
Драйвер ядра binder — это механизм IPC, разработанный в рамках проекта AOSP. Наличие оригинального, отличного от стандартного IPC до конца не ясно, однако детали реализации binder были одним из препятствий для запуска нескольких виртуальных окружений Android. Проблема состояла в следующем. В этом драйвере есть статические переменные, значения которых можно установить системным вызовом ioctl. Этот системный вызов делает программа servicemanager, запускаемая в процессе инициализации Android. Драйвер binder проверяет, инициализированы ли эти переменные и, если да, то возвращает ошибку, что приводит к завершению программы servicemanager, а поскольку эта программа необходима для работы Android – то и к прекращению инициализации Android.
Таким образом, потребовалось создавать экземпляры упомянутых выше переменных для каждого контейнера и обращаться к экземпляру виртуального состояния, принадлежащему контейнеру, в контексте которого был сделан системный вызов ioctl().
Большой задачей виртуализации Android является виртуализация периферийных устройств и мультиплексирование потоков данных. Почти везде мы использовали один и тот же подход, который можно назвать виртуализацией состояний.
Android предполагает, что использует периферийные устройства монопольно. Драйверы этих устройств часто написаны исходя из предположения, что их использует только одна ОС. При запуске нескольких Android на одном устройстве в периферийных устройствах, их драйверах, программном стеке Android возникают критические ошибки.
Таким образом, для работы нескольких Android в контейнерах требуется обеспечить возможность одновременного использования периферийных устройств всеми операционками.
Главное, что требуется для этого, — иметь возможность управлять доступом Android к периферийным устройствам, чтобы они не могли использовать периферийные устройства произвольным образом.
Далее мы рассмотрим как будет выполнена виртуализация графического экрана, а в следующей статье поговорим о виртуализации телефонии, звука и тачскрина.
Необходимость в разделении доступа контейнеров к экрану очевидна. При запуске нескольких контейнеров каждый из них начинает отображать свой UI на экране. Естественно, если не договориться о том, какой контейнер обладает эксклюзивным правом использовать экран, то на экране получится смешение пикселей и элементов интерфейса. Чтобы такого не происходило, экран надо виртуализовать. Необходимо, чтобы физическое устройство было подменено на виртуальное.
Согласно Android Porting Guide [3], для доступа к экрану используется драйвер типа Linux Framebuffer, и для портирования необходимо реализовать данный драйвер. Linux framebuffer имеет простой интерфейс, состоящий из двух десятков функций, большинство из которых имеют реализацию по умолчанию. Драйвер используется из пространства пользователя.
Кроме драйвера фреймбуфера к физическому экрану имеет доступ GPU. Чтобы неактивные ОС не отображали свой UI на экране, требуется подменить операцию отображения их кадров. Выяснилось, что в случае с подопытными Google Nexus S и Samsung Galaxy SII экраны смартфонов копируют кадр для отображения из RAM при помощи DMA. Драйвер фреймбуфера сообщает экрану адрес, по которому находится кадр, предназначенный для отображения (память экрана). Таким образом, операция отображения кадра на экране выглядит как операция записи кадра в RAM устройства по определенному адресу.
Чтобы подменить операцию записи в RAM, требуется установить кем она может выполняться. В случае с обработкой графики запись кадра могут выполнять GPU или CPU. Современные GPU и CPU имеют в своем составе MMU. Для того чтобы кадры неактивных Android не записывались в память экрана, достаточно подменить отображение адресов в MMU так, чтобы адреса неактивных Android, отображаемые в память экрана, фактически указывали на обычный буфер в RAM устройства. Назовем его теневым буфером.
Android отрисовывает свой UI по мере его изменения, а не по таймеру. Поэтому если просто перенаправить MMU на память экрана при переключении активного Android, то активный Android может не перерисовать кадр на экране и изображение на нем окажется от предыдущего активной ОС.
Если выделить теневой буфер для каждого Android, то при переключении активной ОС достаточно скопировать кадр на экране в теневой буфер предыдущего активного Android. Чтобы отобразить Android, ставший активным, требуется скопировать содержимое его теневого буфера в память экрана. Но теневой буфер занимает от 2 до 4 Мб физической памяти. Имея возможность вызывать перерисовку кадра при переключении активного Android, можно избавиться от выделения теневого буфера для каждого Android, оставив единственный теневой буфер.
Такая возможность предоставляется механизмом fb_early_suspend. Теневой буфер теперь становится не местом хранения кадра Android, а местом куда все неактивные ОС пишут свою картинку. Кроме того благодаря наличию MMU можно сократить размер теневого буфера до одной страницы физической памяти, отобразив все 2−4 Мб адресов в единственную страницу.
Типичный сценарий использования драйвера Linux Framebuffer заключается в отображении памяти экрана в адресное пространство пользовательского процесса системным вызовом mmap() и вызовах стандартных и специальных IOCTL.
Стандартные IOCTL обрабатываются стандартным обработчиком IOCTL подсистемы Linux Framebuffer в ядре ОС. Специальные IOCTL имеют нестандартную семантику и могут быть обработаны только драйвером физического Linux Framebuffer. Так как физический Linux Framebuffer был подменен на виртуальный, то mmap() и IOCTL вызываются у драйвера виртуального Linux Framebuffer.
Все вызовы mmap() обрабатываются полностью в драйвере виртуального Linux Framebuffer без использования драйвера физического Linux Framebuffer, т.к. семантика этого системного вызова стандартна. Процессы активного Android при вызове mmap() получают доступ к памяти экрана. Процессы неактивных Android при вызове mmap() получают доступ к теневому буферу вместо памяти экрана. Для всех запущенных Android создается виртуальное состояние драйвера Linux Framebuffer. Для активного Android все вызовы в драйвер виртуального Linux Framebuffer немедленно перенаправляются в драйвер физического Linux Framebuffer, который изменяет состояние физического драйвера Linux Framebuffer. Для неактивных Android стандартные IOCTL'ы изменяют их виртуальные состояния Linux Framebuffer. Нестандартные IOCTL'ы для неактивных Android возвращают ошибку. На устройствах Google Nexus S и Samsung Galaxy SII этого было достаточно.
Технология виртуализации Android, построенная на контейнерах Linux, доказала свою работоспособность на нескольких моделях смартфонов. Мы смогли добиться одновременного выполнения любых приложений одновременно с микшированием звука и приемом входящих сообщений и звонков, так как это делал бы каждый их виртуализированных телефонов. Например, наш демо-сценарий показывает, что мы одновременно играем в Andgy Birds и воспроизводим музыку в разных контейнерах. Вот как это происходит, если кто не видел.
О том, как была реализована виртуализация звука, телефонии и ввода пользователя — в следующей статье, которую я опубликую завтра.
Автор: master1981
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android/30863
Ссылки в тексте:
[1] опубликовано видео: http://www.youtube.com/watch?v=rf5RUOO7gsM
[2] Parallels Labs: http://www.parallels.com/ru/education
[3] Согласно Android Porting Guide: http://www.netmite.com/android/mydroid/development/pdk/docs/display_drivers.html#androidDisplayDriversSourceTemplate
[4] Источник: http://habrahabr.ru/post/174211/
Нажмите здесь для печати.