23 сентября 2008 г . ; 12 лет назад ( 2008-09-23 )
Репозиторий
Bionic — это реализация стандартной библиотеки C , разработанной Google для своей операционной системы Android . Она отличается от библиотеки GNU C (glibc) тем, что предназначена для устройств с меньшим объемом памяти и процессором, чем типичная система Linux . Он основан на коде OpenBSD, выпущенном под лицензией BSD , а не на glibc, который использует GNU Lesser General Public License . Эта разница была важна на заре Android, когда статическое связывание было обычным явлением, и до сих пор полезно при представлении Android программным компаниям, использующим проприетарные операционные системы, которые могут опасаться LGPL и не понимать различий между ним и полная Стандартная общественная лицензия GNU (GPL).
Bionic — это библиотека C для использования с ядром Linux , которая предоставляет libc , libdl , libm и libpthread . Это отличается от библиотек BSD C, для которых требуется ядро BSD .
СОДЕРЖАНИЕ
Оригинальные цели
Первоначально публично заявленные цели Bionic были следующими:
Лицензия BSD : Google хотел изолировать приложения Android от воздействия лицензий с авторским левом, чтобы создать проприетарную экосистему пользовательского пространства и приложений, но:
Android основан на ядре Linux, на которое распространяется действие Стандартной общественной лицензии GNU (GPL) версии 2 с авторским левом.
Наиболее распространенной стандартной библиотекой C для ядра Linux является библиотека GNU C (glibc), на которую распространяется стандартная общественная лицензия ограниченного применения GNU (LGPL), которая также является лицензией с авторским левом. В отличие от GPL, LGPL явно разрешает динамическое связывание, но не позволяет статическое связывание проприетарного программного обеспечения без предоставления исходного кода или связанных объектных файлов.
Разрешительная лицензия BSD является не- копилефта лицензии , которая является совместимой в обоих направлениях. Заменитель glibc под лицензией BSD мог действовать как изоляционный слой между ядром (ядром) с авторским левом и приложениями без него, и поэтому был выбран Google для своего Bionic в качестве замены glibc.
Маленький размер: Bionic был намного меньше библиотеки GNU C; что еще более важно, его требования к памяти были (и остаются) намного ниже.
Скорость: Bionic был разработан для процессоров с относительно низкими тактовыми частотами.
Поддерживаемые архитектуры
Bionic поддерживает только ядра Linux, но в настоящее время поддерживает архитектуры arm, arm64, x86 и x86-64. Сама платформа требует armv7 с Neon начиная с Marshmallow , хотя Android Native Development Kit (NDK) продолжал поддерживать armv5 (который он называл armeabi) до NDK r16. NDK по-прежнему поддерживает armv7 как с Neon, так и без него. Исторически в платформе была частичная поддержка SH-4 , но никакие устройства никогда не поставлялись, и с тех пор поддержка не была прекращена. NDK никогда не поддерживал SH-4, а поддержка MIPS и MIPS64 была удалена из NDK в r17.
Компоненты
Некоторые части исходного кода libc, такие как stdio , взяты из BSD (в основном OpenBSD ), тогда как другие, такие как реализация pthread , были написаны с нуля.
Реализация распределителя динамической памяти со временем изменилась. До Lollipop был единственный собственный распределитель памяти, dlmalloc Дуга Ли . Для Lollipop и Marshmallow было две реализации: dlmalloc и jemalloc . jemalloc дает гораздо более высокую производительность, чем dlmalloc, но за счет дополнительной памяти, необходимой для бухгалтерского учета. Большинство устройств использовали jemalloc, но устройства с низким объемом памяти по-прежнему использовали dlmalloc. Для Nougat через Android 10 все устройства используют jemalloc. Устройства с низким объемом памяти используют «стройную» конфигурацию jemalloc, которая отключает tcache, чтобы почти соответствовать меньшим накладным расходам памяти dlmalloc, сохраняя при этом большую часть скорости jemalloc. В Android 11 распределитель памяти для большинства устройств был переключен на Scudo, что жертвует высокой производительностью jemalloc ради дополнительных функций повышения безопасности. Однако устройствам с низким объемом памяти по-прежнему разрешено использовать jemalloc.
Некоторые 64-битные устройства, такие как Nexus 9 , по сути, являются устройствами с низким объемом памяти из-за дополнительных требований к пространству для 64-битных указателей и размещения двух зигот. ( Zygote — это системная служба Android, которая является родительской для всех процессов приложений Android.)
Libm источник в значительной степени FreeBSD «s, но с оптимизированным ассемблером , вносимым различными SoC поставщиками.
Динамический компоновщик (и libdl) были написаны с нуля.
Bionic не включает libthread_db (используется gdbserver ), но NDK включает. Платформа Android включает статически связанный gdbserver, поэтому разработчики могут использовать последнюю версию gdb даже на старых устройствах.
На Android нет отдельных libpthread, libresolv или librt — вся функциональность находится в libc. Для libpthread нет попытки оптимизации для однопоточного случая, потому что приложения находятся в многопоточной среде даже до того, как первая инструкция стороннего кода когда-либо будет запущена.
Платформа Android использует libc ++ для стандартной библиотеки C ++ (в выпусках до Lollipop включительно используется stlport). NDK исторически предлагал stlport и GNU libstdc ++, но они были удалены в NDK r18. Обратите внимание: если какой-либо собственный код в приложении Android использует C ++, весь C ++ должен использовать один и тот же STL . STL не предоставляется ОС Android и должен быть включен в каждое приложение.
Отличия от POSIX
Хотя Bionic стремится реализовать все C11 и POSIX , в libc все еще (по состоянию на Oreo) отсутствует около 70 функций POSIX. Существуют также функции POSIX, такие как семейство endpwent / getpwent / setpwent, которые неприменимы к Android, поскольку в нем отсутствует база данных passwd . Что касается Oreo , libm завершена.
Некоторые функции намеренно не соответствуют стандартам POSIX или C по соображениям безопасности, например printf, который не поддерживает %n строку формата.
Многие из наиболее часто используемых расширений GNU реализованы в Bionic, как и различные расширения BSD.
Отношение к NDK
Код платформы напрямую использует Bionic, но сторонние разработчики используют Android Native Development Kit (NDK). Многие сторонние разработчики по-прежнему нацелены на более старые выпуски ОС, что способствует широко распространенному мнению, что в бионике не хватает многих функций. Gingerbread экспортировал 803 функции из libc, но Oreo экспортирует 1278 функций (увеличение в 1,6 раза).
Исторически NDK и платформа расходились, но NDK r11 и более поздние версии заменили вилки NDK на их текущие эквиваленты платформы. Первоначально эта работа была сосредоточена на компиляторах GCC и Clang .
До NDK r14, когда «унифицированные» заголовки впервые предлагались на основе согласия, NDK создавал копии заголовков платформы для разных уровней API. Это означало, что исправления только для заголовков (например, исправления для определений констант или структур) были недоступны для большинства пользователей NDK, потому что они были нацелены на более старый уровень API, но исправления платформы входили только в текущие заголовки платформы. В период разработки Oreo заголовки платформы были аннотированы информацией об уровне API, так что один и тот же набор заголовков можно было использовать для всех уровней API, при этом были видны только те функции, которые доступны на целевом уровне API разработчика. Это так называемые «унифицированные» заголовки, которые используются по умолчанию с NDK r15.
До NDK r16 NDK связывал библиотеку libandroid_support.a с кодом, использующим libc ++. Это предоставило функции, необходимые для libc ++, которых не было в старых выпусках ОС. Это был не тот код, который использовался платформой, и он привел к многочисленным ошибкам (например, нарушение позиционных аргументов семейства printf в любом коде, который использовал libc ++). В NDK r16 libandroid_support.a все еще существует, но теперь создается непосредственно из исходных кодов платформы (текущих на момент сборки NDK).
Укрепите источник
На Android Jelly Bean MR1 (4,2), Bionic поддерживает подобную функциональность GLibC — х _FORTIFY_SOURCE , которая является функцией , где небезопасная струнная и память функция (например strcpy() , strcat() и memcpy() ) включает в себя проверку на переполнение буфера. Эти проверки выполняются во время компиляции, если размеры буфера могут быть определены во время компиляции, или во время выполнения в противном случае. Поскольку fortify полагается на поддержку среды выполнения со стороны libc, его переносимость на более старые версии Android ограничена. Сама платформа построена с _FORTIFY_SOURCE включенным.
Исторически сложилось так, что одним из недостатков fortify было то, что он тесно связан с GCC, что затрудняет его поддержку другими компиляторами, такими как Clang. Это означало, что когда Android перешел на Clang в качестве компилятора по умолчанию, реализация Bionic fortify стала существенно менее полезной. В Android Oreo (8.0) функция Bionic fortify была переработана с учетом Clang, в результате чего fortify на Clang обеспечил возможности наравне с fortify на GCC. После этого капитального ремонта, помимо glibc, были добавлены некоторые проверки, чтобы отловить код, который, хотя и не обязательно вызывает неопределенное поведение, явно неверен. Поскольку эта новая реализация не требует большей поддержки libc, чем предыдущая, специфичные для Clang улучшения доступны для приложений, ориентированных на версии Android до Oreo.
Споры
Для создания Bionic Google использовал файлы заголовков ядра Linux под лицензией GPLv2 . Чтобы избавиться от GPL, Google заявил, что очистил файлы заголовков от любой работы, защищенной авторским правом, уменьшив их до не охраняемых авторским правом «фактов». Создатель Linux Линус Торвальдс считал поведение Google приемлемым, но интерпретация Google GPL была оспорена, например, Раймондом Ниммером, профессором права в Юридическом центре Хьюстонского университета .
Источник
Изучаем принципы взаимодействия Ubuntu Touch и Android
Привет, хабр.
Пару месяцев назад я занимался портированием Ubuntu Touch на платформу Allwinner A10 , в процессе делал заметки себе на память. Сейчас, на мой взгляд, они всё ещё актуальны, пока Ubuntu Touch окончательно не переехала на свой графический сервер Mir и так далее.
Данная статья поможет заинтересованным лицам найти стартовую точку, с которой можно начать близкое знакомство с UT.
Стиль изложения далёк от технического, но если вы не против, то приглашаю под кат.
Введение
Что такое libhybris
libhybris — прослойка, позволяющая подгружать в Glibc userspace библиотеки из Bionic userspace, на лету заменяя некоторые символы вариантами из Glibc. Проще говоря, данное решение позволяет использовать проприетарные библиотеки для Android в Linux-пространстве. Наибóльшая польза, конечно же, в возможности использовать проприетарные GPU-драйвера, собранные производителем только под Android.
Ubuntu Touch Developer Preview сама по себе основана на Android, заимствует необходимые сервисы для работы с железом. Общий обзор зависимости можно почитать здесь — Ubuntu Touch Porting или в заметке на OpenNet.
В качестве базовой операционной системы используется обычный Android JB 4.2 , а точнее CyagenMod-10.1 (репозиторий подпроектов CM — phablet.ubuntu.com/gitweb). Из него удалено всё что связано с dalvik и java — оставлена только нативная часть, состоящая из системных сервисов и HAL . При желании можно использовать AOSP 4.1 , но будьте готовы к адаптации под нативное API от 4.1, оно не покрыто никакой документацией и тем более спецификацией и меняется от релиза к релизу.
Компоненты UT располагаются в chroot , используется самописная утилита uchroot, отрывок:
Для взаимодействия Android-окружения и chroot-окружения Ubuntu задействован механизм libhybris .
Компоненты Ubuntu Touch
phablet-team. Нас интересуют следующие два компонента, отвечающие за работу платформы на Android устройствах:
platform-api
qtubuntu
Скачаем последнюю версию исходников:
Ubuntu Platform API
Ubuntu platform API — низкоуровневый API для выполнения базовых операций с использованием возможностей платформы (Android).
Примеры методов:
ubuntu_application_ui_show_surface
ubuntu_application_ui_hide_surface
ubuntu_application_ui_move_surface_to
ubuntu_application_ui_resize_surface_to
Из файла документации doc/mainpage.md узнаём, что дерево исходников platform-api можно разбить на две части:
include — абстрактная декларация platform API
android — реализация platform API под Android (я бы уточнил — под Android 4.2)
И то единственное, на что может полагаться сторонний разработчик при работе с этим API — это заголовки из директории includes/ubuntu/application, а всё остальное предполагает изменяться со временем.
Из файла debian/control узнаём, что:
Ага, значит, судя по android/hybris/Android.mk, реализация platform API собирается в виде библотеки libubuntu_application_api с линковкой с нативными либами андроида и помещается в android userspace:
Без внимания осталась директория platform-api/src/android, рассмотрим её в деталях. Судя по наличию файла CMakeLists.txt , сборка идёт уже для glibc.
Есть один-единственный файл с кодом — ubuntu_application_api.cpp, заглянув в которой мы увидим: — использование процедур libhybris для динамической загрузки символов из shared-либы из android userspace.
— нехитрый мост для подгрузки символов из libubuntu_application_api.so , которая ладит с нативными сервисами андроида, и которую мы совсем недавно мысленно «собрали» с помощью android/hybris/Android.mk.
— куча обёрток для символов API, реализованных в libubuntu_application_api.so .
Итак, во избежание путаницы:
libubuntu_application_api.so — библиотека под bionic, живёт в android userspace;
libubuntu_application_api.so — библиотека под glibc, живёт в linux userpace (chroot), грузит символы из первой через libhybris.
Разработчики решили уменьшить энтропию вселенной путём создания одноимённых библиотек. Если посмотреть их дебаты по поводу именования компонентов merge-153874 discussion, то уши вянут.
Ubuntu Application Manager
В platform-api/android/hybris помимо реализации Ubuntu platform API находятся исходники ubuntuappmanager — сервиса приложений Ubuntu, он живёт в android userspace и, судя по Android.mk, активно использует libubuntu_application_api и общается через Binder IPC с сервисами андроида.
Решает кучу задач управления приложениями и сессиями, быстрый взгляд на default_application_manager.h:
QtUbuntu
Разбираемся с частью UT, отвечающей за взаимодействие между Ubuntu platform API и Qt/QML приложениями.
Если вы не знакомы с Qt Platform Abstraction, то, в кратце, это возможность абстрагироваться от платформы, на которой запускаются приложения Qt с помощью специально написанных QPA-плагинов.
В QPA-плагине реализуются базовые методы вроде createPlatformWindow , а затем Qt приложение, когда захочет создать окошко, использует символ createPlatformWindow из плагина абстракции и в ус не дует, куда оно там дальше пошло.
В данном случае мы будем иметь дело с QPA плагином для работы с Ubuntu application API.
Судя по содержимому ubuntu.pro, платформа линкуется с glibc-версией libubuntu_application_api.so Обратим внимание на следующие вызовы методов из набора platform API, использованные в integration.cc и window.cc:
Теперь понятно, что когда наше Qt приложение захочет создать окошко, то оно вызовет метод из QPA платформы qubuntu — QUbuntuIntegration::createPlatformWindow из файла integration.cc:
Заглядывая в конструктор QUbuntuWindow в файле window.cc, находим вызов метода QUbuntuWindow::createWindow() :
Это крайне урезанный код, но суть ясна — делаются вызовы к Ubuntu platform API , которое у нас реализовано в glibc-версии libubuntu_application_api.so , которая, на самом деле, является мостом к bionic-версии libubuntu_application_api.so , код которой лежит в platform-api/android.
Нам осталось открыть матрёшку и найти, как же реализованы ubuntu::application::ui::Session и, соответственно, ubuntu::application::ui::Surface . А реализованы они в этом файле — ubuntu_application_api_for_hybris.cpp:
Перематываем, находим UbuntuSurface :
Получаем некий объект типа android::SurfaceControl , который является результатом вызова android::SurfaceComposerClient()->createSurface() . Через него проходят все обращения к android::SurfaceComposerClient (frameworks/native/libs/gui/Surface.cpp), такие как: изменение размеров, перемещение, изменение порядка слоёв и так далее.
Возвращаясь назад по цепочке, понимаем, что же на самом деле происходит, когда мы запускаем очередное Qt приложение с QPA платформой Ubuntu.
Заключение
На этом моменте я вынужден себя остановить, поскольку, на мой взгляд, рассмотренный принцип взаимодействия Ubuntu Touch и Android является самодостаточным. Дальнейшие рассуждения могут идти уже в отрыве от всего вышеописанного. Нерасмотренными остались вопросы взаимодействия qmlscene и ubuntuappmanager , принцип контроля ввода с помощью сервисов SurfaceFlinger и InputDispatcher и другие вопросы из уголков этой простороной темы. Но это уже совсем другая история.
Через неделю приедет телефон на Firefox OS, распотрошу его…