Конспекты материалов по операционной системе Android

Загрузка ОС на ARM

Как работает Android, часть 1

Один из исходной команды разработчиков Android - Robert Love.

Android построен поверх слегка модифицированного ядра Linux. Небольшой список доработок, которых нет в оригинальном ядре Linux:

  • ashmem - anonymous shared memory,
  • Binder driver - часть большого и важного фреймворка Binder,
  • wakelocks - управление спящим режимом,
  • low memory killer.

Всё программное окружение, работающее поверх ядра, распространяется в основном по лицензии ASL-2.0 (Apache Software License). В остальных случаях предпочтение отдаётся лицензиям BSD, MIT и только потом LGPL.

Вместо glibc (GNU C Library) используется библиотека bionic, оптимизированная для встраиваемых систем.

В качестве утилит командной строки, начиная с Android 6.0 Marshmallow, используется Toybox. По умолчанию доступа к ним нет, но из Google Play Store можно лекго установить приложение-эмулятор терминала, например Terminal Emulator for Android. Также получить доступ можно через оболочку для отладки ADB Shell.

Кроме этих компонентов в Android входят библиотеки FreeType, OpenGL ES, EGL, Vulkan, SQLite. В качестве движка для просмотра веб-страниц ранее использовалась библиотека WebKit, но начиная с Android 7.0 используется приложение Chrome, построенное на базе Blink, являющегося ответвлением WebKit.

Приложения для Android не имеют функции main().

В ядре Linux, используемом в Android, отсутствуют классические механизмы межпроцессного взаимодействия. Вместо них используется устройство /dev/binder, библиотека libbinder. Изначально Binder был разработан в Be Inc для операционной системы Be OS, а затем портирован на Linux.

Для описания интерфейсов программ используется специальный язык AIDL - Android Interface Definition Language, по которым автоматически генерируются объекты Proxy и Stub для клиентской и серверной стороны соответственно.

Другие компоненты приложения для Android базируются на объектах Activity, Intent и Context.

Как работает Android, часть 2

В 1999 Эди Рубин стал сооснователем фирмы Danger Inc, которая занималась разработкой мобильной операционной системы Danger.

В 2003 он же стал сооснователем фирмы Android Inc, которая стала заниматься разработкой мобильной операционной системы Android, в которой были использованы многие решения, опробованные на Danger.

В 2005 году Android Inc была куплена Google.

Программы для Android пишутся в основном на Java. Для запуска Java-приложений в Android используется собственная реализация виртуальной Java-машины. Поначалу это была реализация, которая называлась Dalvik. Начиная с Android 5.0 Lollipop виртуальная машина Dalvik была заменена на новую реализацию - ART или Android Runtime.

В отличие от оригинальной Java, в Dalvik и ART используется собственный формат Java-кода - DEX (Dalvik Executable). Классы приложения компилируются сначала в родной формат Java, использующий расширение .class, а затем все классы приложения собираются в один файл с расширением .dex. Утилита для преобразования .class-файлов в .dex-файлы называется D8, а для оптимизации полученного байт-кода используется утилита R8.

Dalvik и ART для ускорения работы приложений используют компиляцию фрагментов байт-кода в машинный код при помощи технологии JIT (Just In Time). Кроме того, ART умеет компилировать байт-код в машинный код ещё до запуска приложения, а для точной оптимизации приложения может использоваться статистика, собранная во время его работы.

В некоторых случаях может возникнуть необходимость использовать низкоуровневый язык. Для сопряжения с Java библиотек, написанных на низкоуровневых языках, используется JNI - Java Native Interface, я для облегчения разработки предусмотрен набор инструментом NDK - Native Development Kit, в который входят заголовочные файлы, компилятор Clang, отладчик LLDB и инструменты сборки.

Unix-системы изначально проектировались как многопользовательские системы с текстовыми терминалами. Как правило, программы тогда поставлялись либо разработчиком операционной системы, либо писались самим пользователем, поэтому охранять пользователя от запущенных им же программ не было нужды. Для достижения безопасности достаточно было разграничить права и ресурсы пользователей.

В мобильных операционных системах пользователь всего один, но он может устанавливать множество приложений из самых разных источников. В большинстве случаев эти приложения поставляются не разработчиками операционной системы и написаны не пользователем устройства, поэтому более актуальной становится задача ограничивать не права пользователей, а права отдельных приложений.

В Android существующий механизм разграничения прав UID/GID используется для разграничения прав приложений, а не пользователей. Каждое приложение работатет от имени собственного пользователя, а группы используются для предоставления приложению определённых прав. При установке приложения создаётся новый пользователь и он помещается в группы, соответствующие правам, необходимым приложению для работы. Например, если для работы приложению нужен доступ к радиоприёмнику, оно должно получить разрешение ACCESS_FM_RADIO. Приложения, имещющие такое разрешение, помещаются в группу media, а эта группа, в свою очередь, позволяет получить доступ к файлу устройства /dev/fm.

Некоторые сервисы в Android работают от имени пользователя root, но большая часть для получения прав root использует механизм POSIX Capabilities. Кроме того, в Android используется собственная версия SELinux, которая называетя SEAndroid.

Как работает Android, часть 3

Обычно приложения для настольных компьютеров противопоставляются веб-приложениям:

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

Однако, на самом деле в случае с Android разница не столь велика, как может показаться:

  • приложения для Android пишутся на языке Java и не требуют пересборки для запуска на другом устройстве,
  • для Android существуют "мгновенные" приложения, которые можно запустить и опробовать, не устанавливая,
  • приложения для Android строятся на принципах, сходными с веб-приложениями.

Последний пункт нуждается в пояснении. Приложение для Android состоит из отдельных экранов (activity), которые могут вызывать друг друга при помощи сообщений (intents).

Одно и то же сообщение может обрабатываться несколькими разными приложениями. Если в системе есть несколько приложений для обработки одних и тех же сообщений, пользователю системы предоставляется меню, в котором он может выбрать либо программу, которая должна обрабатывать это событие по умолчанию, либо выбрать приложение для обработки этого события в этот раз.

Например, приложение для загрузки изображений в интернет может генерировать сообщение с запросом изображения. Среди программ, обрабатывающих это событие, могут быть как файловый менеджер, позволяющий выбрать картинку в файловой системе телефона, так и приложение, работающее с камерой, которое может сделать снимок и передать картинку запросившему приложению.

Мобильные устройства обынчо снабжены относительно небольшим объёмом оперативной памяти. При нехватке оперативной памяти операционная система Android может попросить экран-активность завершить свою работу. При завершении работы экран-активность может сохранить своё состояние, которое может быть с лёгостью восстановлено при следующем запуске. Операционная система может завершать отдельные экраны-активности одного и того же приложения, не завершая других. Все эти механизмы создают у пользователя системы впечатление постоянно запущенных приложений.

Если приложению нужно делать какую-то фоновую работу, не связанную ни с одним из экранов-активностей, приложение может запускать сервисы. Например, музыкальный проигрыватель может содержать экран-активность для управления воспроизведением звука, а сам звук при этом может воспроизводиться отдельным сервисом. При переходе к другому экрану музыка будет воспроизводиться в фоновом режиме, а операционная система будет иметь возможность завершить экран-активность при нехватке оперативной памяти. Аналогичным образом может быть устроен, например, SSH-клиент. Сервис может поддерживать связь с SSH-серверами, а экраны-активности отображать экраны отдельных подключений по SSH.

Сервисы делятся на интерактивные (foreground), фоновые (background) и обслуживающие Binder-запросы (bound). Первые сервисы завершаются операционной системой только в крайнем случае, вторые могут завершаться так же, как и экраны-активности, третьи могут завершаться операционной системой при отсутствии запросов и автоматически запускаться при их появлении. Например, упомянутый сервис, входящий в состав музыкального проигрывателя, разумно сделать интерактивным. Упомянутый сервис, поддерживающий подключения к SSH-серверам, лучше всего сделать фоновым.

Кроме этого для выполнения периодических задач у приложения могут иметься компоненты, вызываемые через планировщик задач (job scheduler). Эти компоненты могут подписываться на различные события, когда их запуск может быть наиболее уместным, а планировщик задач будет планировать запуск этих компонентов так, чтобы они не отнимали много ресурсов системы. Такие компоненты могут запускаться:

  • при наличии подключения к сети интернет,
  • при зарядке устройства,
  • во время бездействия,
  • при обновлении информации. Например, при появлении новой фотографии,
  • с указанной периодичностью и крайним сроком запуска.

Кроме рассмотренных разновидностей компонентов существует ещё два вида:

  • широковещательные приёмники (broadcast receiver) - обрабатывают сообщения, посылаемые всем приложениям. В настоящее время такие компоненты заменяются компонентами, вызываемыми через планировщик задач.
  • хранилища данных (content provider) - например, адресная книга или список контактов. Приложение, желающее воспользоваться хранилищем, использует для доступа к хранилищу компонент ContentResolver, который соединяется с нужным хранилищем. Подобные хранилища могут предоставлять доступ не только к данным, хранимым локально, но и к данным, располагающимся в облачных хранилищах.

Как работает Android, часть 4

Координацией работы приложений занимается activity manager, для работы с которым предусмотрена консольная утилита am.

Установкой и удалением приложений в системе занимается package manager, для работы с которым предусмотрена консольная утилита pm.

Пакеты распространяются в формате APK и идентифицируются именем в обратной нотации DNS, например приложение Youtube идентифицируется именем com.google.android.youtube. Каждый пакет сопровождаетя цифровой подписью. При обновлении приложения проверяется не только соответствие подписи содержимому пакета, но и соответствие открытого ключа подписи из старой версии пакета открытому ключу подписи из новой версии пакета, чтобы защититься от подмены пакетов другим автором.

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

В качестве корневой файловой системы Android использует ext4. В отдельных случаях, в основном в любительских сборках, используется F2FS.

Ядро операционной системы и загрузочный образ initramfs хранятся в отдельном разделе файловой системы, который не монтируется в основную файловую систему.

Назначение каталогов в файловой системе:

  • /data - изменяемые данные приложений,
  • /data/app - приложения, установленные пользователем,
  • /data/app/приложение/shared_pref - настройки приложения,
  • /data/app/приложение/cache - кэшированные данные приложения,
  • /system - системные файлы,
  • /system/apps - предустановленные приложения,
  • /system/app - предустановленные приложения,
  • /system/priv-apps - предустановленные приложения,
  • /vendor - системные файлы, добавленные производителем прошивки и не входящие в состав основной системы,
  • /dev - виртуальная файловая система устройств,
  • /sdcard - "внешнее" хранилище, общедоступное для всех приложений,
  • /mnt/sdcard
  • /storage/self/primary
  • /mnt/runtime
  • /data/media/UID,
  • /storage/emulated/UID,
  • /sdcard/Android/data/приложение/ - некоторые приложения помещают сюда объёмные данные.

Каталоги /data и /system располагаются на разных разделах флеш-памяти. Первый монтируется в режиме чтения-записи, а второй доступен только для чтения. При сбросе устройства к заводским настройкам происходит полная очистка первого раздела.

Приложения, установленные в /system/app, имеют особые привилегии, недоступные приложениям, установленным пользователем. Поскольку раздел /system монтируется в режиме только для чтения, при обновлении приложений, установленных в этом каталоге, новые версии приложений помещаются в каталог /data.

При необходимости освободить место в файловой системе, Android может удалять файлы из каталогов /data/app/*/cache.

SD-карту, вставленную в слот, можно использовать в качестве "внешнего" хранилища. Такое хранилище называется adopted storage, данные на нём шифруются.

Свободная реализация сервисов Google называется microG. Для их установки через F-Droid нужно подключить репозиторий NanoDroid companion F-Droid repository

Приложения LineageOS для запуска поверх microG

Xposed - приложение-фреймворк.

XPrivacyLua - модуль для Xposed, ограничение доступа приложений.