Назначение папок в андроид. Внутреннее устройство систем Android

    В определенных моделях планшетов на базе платформы Android могут отсутствовать некоторые компоненты из вышеприведенного списка.

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

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

    Итак, на самом нижнем уровне находятся сами аппаратные компоненты: процессоры, сенсоры, провода и печатные платы. Следующим слоем является ядро операционной системы. Ядро иногда еще называют встроенным (или фирменным) программным обеспечением. Более известно англоязычное определение «firmware». Это программное обеспечение осуществляет контроль над аппаратными ресурсами устройства, управление ими и их распределением.

    Эта часть операционной системы «переводит» на язык аппаратных компонентов те команды, которые отдает пользователь посредством удобного графического интерфейса. Образцом ядра для Android стала операционная система с открытым кодом Linux 2.6.

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

    На том же уровне программного стека располагаются корневые библиотеки, необходимые для поддержки приложений, написанных на языке Java. Java является языком программирования от Sun Microsystems. Еще сравнительно недавно телефоны с поддержкой Java-приложений были очень распространены. В настоящее время они все в большей степени вытесняются смартфонами.

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

    На следующем уровне располагается инфраструктура приложений (application framework). Она является основой для всех приложений «андроидного» девайса. Инфраструктура приложений является связующим звеном между приложениями и остальными частями операционной системы.

    Google рекомендует разработчикам создавать такие приложения, которые взаимодействуют с этим слоем в рамках интерфейса прикладного программирования () разработанной поисковым гигантом операционной системы. Разработчикам остается только ознакомиться с этими правилами, имеющими отношение к API. Им не нужно задумываться о технических характеристиках каждого «андроидного» планшета.

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

    Как и любая другая операционная система, и другие аппаратные ресурсы планшета.

    По материалам computer.howstuffworks.com

#факты | Как устроен Android? Олег Довбня

Тебя никогда не интересовало, как работают fastboot или ADB? Или почему смартфон под управлением Android практически невозможно превратить в кирпич? Или, может быть, ты давно хотел узнать, где кроется магия фреймворка Xposed и зачем нужны загрузочные скрипты /system/etc/init.d? А как насчет консоли восстановления (recovery)? Это часть Android или вещь в себе и почему для установки сторонней прошивки обычный рекавери не подходит? Ответы на все эти и многие другие вопросы ты найдешь в данной статье.

Как работает Android

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

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

Шаг первый. ABOOT и таблица разделов

Все начинается с первичного загрузчика. После включения питания система исполняет код загрузчика, записанного в постоянную память устройства. Затем он передает управление загрузчику aboot со встроенной поддержкой протокола fastboot, но производитель мобильного чипа или смартфона/планшета имеет право выбрать и любой другой загрузчик на его вкус. Например, компания Rockchip использует собственный, несовместимый с fastboot загрузчик, для перепрограммирования и управления которым приходится использовать проприетарные инструменты.

Протокол fastboot, в свою очередь, представляет собой систему управления загрузчиком с ПК, которая позволяет выполнять такие действия, как разлочка загрузчика, прошивка нового ядра и recovery, установка прошивки и многие другие. Смысл существования fastboot в том, чтобы иметь возможность восстановить смартфон в начальное состояние в ситуации, когда все остальные средства не работают. Fastboot останется на месте, даже если в результате экспериментов ты сотрешь со смартфона все разделы NAND-памяти, содержащие Android и recovery.

Получив управление, aboot проверяет таблицу разделов и передает управление ядру, прошитому в раздел с именем boot, после чего ядро извлекает в память RAM-образ из того же раздела и начинает загрузку либо Android, либо консоли восстановления. NAND-память в Android-устройствах поделена на шесть условно обязательных разделов:

  • boot - содержит ядро и RAM-диск, обычно имеет размер в районе 16 Мб;
  • recovery - консоль восстановления, состоит из ядра, набора консольных приложений и файла настроек, размер 16 Мб;
  • system - содержит Android, в современных девайсах имеет размер не менее 1 Гб;
  • cache - предназначен для хранения кешированных данных, также используется для сохранения прошивки в ходе OTA-обновления и поэтому имеет размер, сходный с размерами раздела system;
  • userdata - содержит настройки, приложения и данные пользователя, ему отводится все оставшееся пространство NAND-памяти;
  • misc - содержит флаг, определяющий, в каком режиме должна грузиться система: Android или recovery.
Кроме них, также могут существовать и другие разделы, однако общая разметка определяется еще на этапе проектирования смартфона и в случае aboot зашивается в код загрузчика. Это значит, что: 1) таблицу разделов нельзя убить, так как ее всегда можно восстановить с помощью команды fastboot oem format; 2) для изменения таблицы разделов придется разлочить и перепрошить загрузчик с новыми параметрами. Из этого правила, однако, бывают исключения. Например, загрузчик того же Rockchip хранит информацию о разделах в первом блоке NAND-памяти, так что для ее изменения перепрошивка загрузчика не нужна.

Часть кода загрузчика, определяющая таблицу разделов


Особенно интересен раздел misc. Существует предположение, что изначально он был создан для хранения различных настроек независимо от основной системы, но в данный момент используется только для одной цели: указать загрузчику, из какого раздела нужно грузить систему - boot или recovery. Эту возможность, в частности, использует приложение ROM Manager для автоматической перезагрузки системы в recovery с автоматической же установкой прошивки. На ее же основе построен механизм двойной загрузки Ubuntu Touch, которая прошивает загрузчик Ubuntu в recovery и позволяет управлять тем, какую систему грузить в следующий раз. Стер раздел misc - загружается Android, заполнил данными - загружается recovery… то есть Ubuntu Touch.

Шаг второй. Раздел boot

Если в разделе misc не стоит флаг загрузки в recovery, aboot передает управление коду, расположенному в разделе boot. Это не что иное, как ядро Linux; оно находится в начале раздела, а сразу за ним следует упакованный с помощью архиваторов cpio и gzip образ RAM-диска, содержащий необходимые для работы Android каталоги, систему инициализации init и другие инструменты. Никакой файловой системы на разделе boot нет, ядро и RAM-диск просто следуют друг за другом. Содержимое RAM-диска такое:

  • data - каталог для монтирования одноименного раздела;
  • dev - файлы устройств;
  • proc - сюда монтируется procfs;
  • res - набор изображений для charger (см. ниже);
  • sbin - набор подсобных утилит и демонов (adbd, например);
  • sys - сюда монтируется sysfs;
  • system - каталог для монтирования системного раздела;
  • charger - приложение для отображения процесса зарядки;
  • build.prop - системные настройки;
  • init - система инициализации;
  • init.rc - настройки системы инициализации;
  • ueventd.rc - настройки демона uventd, входящего в состав init.
Это, если можно так выразиться, скелет системы: набор каталогов для подключения файловых систем из разделов NAND-памяти и система инициализации, которая займется всей остальной работой по загрузке системы. Центральный элемент здесь - приложение init и его конфиг init.rc, о которых во всех подробностях я расскажу позже. А пока хочу обратить внимание на файлы charger и ueventd.rc, а также каталоги sbin, proc и sys.

Файл charger - это небольшое приложение, единственная задача которого - вывести на экран значок батареи. Он не имеет никакого отношения к Android и используется тогда, когда устройство подключается к заряднику в выключенном состоянии. В этом случае загрузки Android не происходит, а система просто загружает ядро, подключает RAM-диск и запускает charger. Последний выводит на экран иконку батареи, изображение которой во всех возможных состояниях хранится в обычных PNG-файлах внутри каталога res.

Файл ueventd.rc представляет собой конфиг, определяющий, какие файлы устройств в каталоге sys должны быть созданы на этапе загрузки системы. В основанных на ядре Linux системах доступ к железу осуществляется через специальные файлы внутри каталога dev, а за их создание в Android отвечает демон ueventd, являющийся частью init. В нормальной ситуации он работает в автоматическом режиме, принимая команды на создание файлов от ядра, но некоторые файлы необходимо создавать самостоятельно. Они перечислены в ueventd.rc.

Каталог sbin в стоковом Android обычно не содержит ничего, кроме adbd, то есть демона ADB, который отвечает за отладку системы с ПК. Он запускается на раннем этапе загрузки ОС и позволяет выявить возможные проблемы на этапе инициализации ОС. В кастомных прошивках в этом каталоге можно найти кучу других файлов, например mke2fs, которая может потребоваться, если разделы необходимо переформатировать в ext3/4. Также модеры часто помещают туда BusyBox, с помощью которого можно вызвать сотни Linux-команд.

Каталог proc для Linux стандартен, на следующих этапах загрузки init подключит к нему procfs, виртуальную файловую систему, которая предоставляет доступ к информации обо всех процессах системы. К каталогу sys система подключит sysfs, открывающую доступ к информации о железе и его настройкам. С помощью sysfs можно, например, отправить устройство в сон или изменить используемый алгоритм энергосбережения.

Файл build.prop предназначен для хранения низкоуровневых настроек Android. Позже система обнулит эти настройки и перезапишет их значениями из недоступного пока файла system/build.prop.

Корневой раздел ТВ-приставки OUYA


Шаг второй, альтернативный. Раздел recovery

В том случае, если флаг загрузки recovery в разделе misc установлен или пользователь включил смартфон с зажатой клавишей уменьшения громкости, aboot передаст управление коду, расположенному в начале раздела recovery. Как и раздел boot, он содержит ядро и RAM-диск, который распаковывается в память и становится корнем файловой системы. Однако содержимое RAM-диска здесь несколько другое.

В отличие от раздела boot, выступающего в роли переходного звена между разными этапами загрузки ОС, раздел recovery полностью самодостаточен и содержит миниатюрную операционную систему, которая никак не связана с Android. У recovery свое ядро, свой набор приложений (команд) и свой интерфейс, позволяющий пользователю активировать служебные функции.

В стандартном (стоковом) recovery таких функций обычно всего три: установка подписанных ключом производителя смартфона прошивок, вайп и перезагрузка. В модифицированных сторонних recovery, таких как ClockworkMod и TWRP, функций гораздо больше. Они умеют форматировать файловые системы, устанавливать прошивки, подписанные любыми ключами (читай: кастомные), монтировать файловые системы на других разделах (в целях отладки ОС) и включают в себя поддержку скриптов, которая позволяет автоматизировать процесс прошивки и многие другие функции.

С помощью скриптов, например, можно сделать так, чтобы после загрузки recovery автоматически нашел на карте памяти нужные прошивки, установил их и перезагрузился в Android. Эта возможность используется инструментами ROM Manager, auto-flasher, а также механизмом автоматического обновления CyanogenMod и других прошивок.

Кастомные рекавери также поддерживают скрипты бэкапа, располагающиеся в каталоге /system/addon.d/. Перед прошивкой recovery проверяет наличие скриптов и выполняет их перед тем, как произвести прошивку. Благодаря таким скриптам gapps не исчезают после установки новой версии прошивки.

Шаг третий. Инициализация

Итак, получив управление, ядро подключает RAM-диск и по окончании инициализации всех своих подсистем и драйверов запускает процесс init, с которого начинается инициализация Android. Как я уже говорил, у init есть конфигурационный файл init.rc, из которого процесс узнает о том, что конкретно он должен сделать, чтобы поднять систему. В современных смартфонах этот конфиг имеет внушительную длину в несколько сот строк и к тому же снабжен прицепом из нескольких дочерних конфигов, которые подключаются к основному с помощью директивы import. Тем не менее его формат достаточно простой и по сути представляет собой набор команд, разделенных на блоки.

Каждый блок определяет стадию загрузки или, выражаясь языком разработчиков Android, действие. Блоки отделены друг от друга директивой on, за которой следует имя действия, например on early-init или on post-fs. Блок команд будет выполнен только в том случае, если сработает одноименный триггер. По мере загрузки init будет по очереди активировать триггеры early-init, init, early-fs, fs, post-fs, early-boot и boot, запуская таким образом соответствующие блоки команд.

Часть конфига init.rc из CyanogenMod


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

Наиболее примечательный из дополнительных конфигов носит имя initrc.имя_устройства.rc, где имя устройства определяется автоматически на основе содержимого системной переменной ro.hardware. Это платформенно-зависимый конфигурационный файл, который содержит блоки команд, специфичные для конкретного устройства. Кроме команд, отвечающих за тюнинг ядра, он также содержит примерно такую команду:

mount_all ./fstab.имя_устройства

Она означает, что теперь init должен подключить все файловые системы, перечисленные в файле./fstab.имя_устройства, который имеет следующую структуру:

имя_устройства_(раздела) точка_монтирования файловая_система опции_фс прочие опции

Обычно в нем содержатся инструкции по подключению файловых систем из внутренних NAND-разделов к каталогам /system (ОС), /data (настройки приложений) и /cache (кешированные данные). Однако слегка изменив этот файл, мы можем заставить init загрузить систему с карты памяти. Для этого достаточно разбить карту памяти на три 4 раздела: 1 Гб / ext4, 2 Гб / ext4, 1 Гб / ext4 и оставшееся пространство fat32. Далее необходимо определить имена разделов карты памяти в каталоге /dev (для разных устройств они отличаются) и заменить ими оригинальные имена устройств в файле fstab.

Типичное содержимое файла fstab


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

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

Шаг четвертый. Zygote и app_process

На определенном этапе загрузки init встретит в конце конфига примерно такой блок:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class default
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

Это описание службы Zygote, ключевого компонента любой Android-системы, который ответственен за инициализацию, старт системных служб, запуск и остановку пользовательских приложений и многие другие задачи. Zygote запускается с помощью небольшого приложения /system/bin/app_process, что очень хорошо видно на приведенном выше куске конфига. Задача app_proccess - запустить виртуальную машину Dalvik, код которой располагается в разделяемой библиотеке /system/lib/libandroid_runtime.so, а затем поверх нее запустить Zygote.

Когда все это будет сделано и Zygote получит управление, он начинает формирование среды исполнения Java-приложений с помощью загрузки всех Java-классов фреймворка (сейчас их более 2000). Затем он запускает system_server, включающий в себя большинство высокоуровневых (написанных на Java) системных сервисов, в том числе Window Manager, Status Bar, Package Manager и, что самое важное, Activity Manager, который в будущем будет ответственен за получение сигналов о старте и завершении приложений.

После этого Zygote открывает сокет /dev/socket/zygote и уходит в сон, ожидая данные. В это время запущенный ранее Activity Manager посылает широковещательный интент Intent.CATEGORY_HOME, чтобы найти приложение, отвечающее за формирование рабочего стола, и отдает его имя Zygote через сокет. Последний, в свою очередь, форкается и запускает приложение поверх виртуальной машины. Вуаля, у нас на экране появляется рабочий стол, найденный Activity Manager и запущенный Zygote, и статусная строка, запущенная system_server в рамках службы Status Bar. После тапа по иконке рабочий стол пошлет интент с именем этого приложения, его примет Activity Manager и передаст команду на старт приложения демону Zygote

Все это может выглядеть несколько непонятно, но самое главное - запомнить три простые вещи:

Системные службы и потоки ядра


Выводы

Во многом Android сильно отличается от других ОС, и с наскоку в нем не разобраться. Однако, если понять, как все работает, открываются просто безграничные возможности. В отличие от iOS и Windows Phone, операционка от гугла имеет очень гибкую архитектуру, которая позволяет серьезно менять ее поведение без необходимости писать код. В большинстве случаев достаточно подправить нужные конфиги и скрипты.
  • Перевод

В этой статье мы рассмотрим архитектуру Android-приложений.

Откровенно говоря, официальную Google по этой теме я считаю не очень полезной. Детально отвечая на вопрос «как», она совсем не объясняет «что» и «почему». Итак, вот моя версия, и, я надеюсь, она внесёт некоторую ясность. Да, кстати, я полностью одобряю чтение статей Google, поскольку они содержат полезную информацию, повторять которую я не собираюсь.

Архитектура ОС Android - немного истории

Как это часто бывает в IT, многие вещи не могут быть объяснены в отрыве от истории возникновения конкретного программного обеспечения. Вот почему мы должны обратиться к истокам ОС Android.

Разработка ОС Android была начата в 2003 молодой компанией Android Inc. В 2005 году эта компания была куплена Google. Я считаю, что главные особенности архитектуры Android были определены именно в этот период. Это заслуга не только Android Inc; архитектурные концепции и финансовые ресурсы Google оказали решающее влияние на архитектуру Android. Далее я приведу несколько примеров.

Если вы помните, 2003-2005 года были ознаменованы повышенным вниманием к AJAX приложениям. Я думаю, это оказало основополагающее влияние на архитектуру Android: во многих аспектах она ближе к архитектуре типичного AJAX приложения, нежели к десктопному GUI приложению, написанному на Java, C#, C++, VB и тп.

Не знаю, почему так произошло. Моя догадка - это придумал кто-то из Google в тот период, когда насыщенные интернет-приложения (Rich Internet Applications, RIA) в духе Google Docs или Gmail считались решением всех проблем. По-моему, эту идею нельзя назвать ни плохой, ни хорошей. Просто помните, что Android-приложения очень сильно отличаются от десктопных.

Влияние архитектурной философии Eclipse заметно в выборе принципа реализации GUI, который больше похоже на SWT, нежели на Swing.

В стандартах оформления кода Android присутствует «венгерская нотация», рождённая в стенах MS. Можно предположить, что тот, кто писал эти стандарты, ранее занимался разработкой под Windows.

Архитектурные уровни Android
Операционная система Android имеет три весьма различных и сильно отделённых друг от друга уровня:
  1. В основе лежит модифицированная и урезанная версия Linux, как я и упоминал в одной из моих предыдущих статей .
  2. Над уровнем Linux находится уровень инфраструктуры приложения, содержащий виртуальную машину Dalvik , веб-браузер, базу данных SQLite , некие инфраструктурные «костыли» и Java API.
  3. И, наконец, уровень написанных в Google Android-приложений. Вообще говоря, они являются расширением уровня инфраструктуры, поскольку разработчик может использовать эти приложения или их части как строительные блоки для собственных разработок.
Рассмотрим эти слои один за другим и более подробно.

Уровень Linux

Представьте себе, что вы - архитектор в молодой компании. Вы должны разработать ОС для нового типа устройств. Что вы будете делать?

Грубо говоря, у вас два пути: реализовывать собственные идеи, начав с нуля или же использовать существующую ОС и адаптировать её под свои устройства.

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

Тем не менее, это не всегда практично. Например, использование ядра Linux заметно уменьшило стоимость разработки (возможно где-то и без того чрезмерно большую). Согласитесь, если кто-то решит создать нечто, напоминающее ядро Linux в его сегодняшнем состоянии, ему потребуется несколько миллионов долларов.

Если вы руководите Android Inc, то у вас по определению не может быть столько денег. Если вы руководите Google, то у вас такие деньги найдутся, но вы, скорее всего, подумаете дважды, прежде чем потратить их на создание собственной ОС. Так же вы потратите несколько лет, прежде чем достигните сегодняшнего состояния Linux; несколько лет задержки могут стать слишком большим опозданием при выходе на рынок.

В подобной ситуации компания Apple решила построить Mac OS на основе Free BSD. Android Inc приняла решение использовать Linux как основу для Android. Исходники как Free BSD, так и Linux, находятся в свободном доступе и предоставляют собой хорошую основу для любых разработок, будь то Apple или Google.

Но в то время запустить стандартный Linux на мобильном устройстве было невозможно (сейчас это уже не так). Устройства имели слишком мало оперативной и энергонезависимой памяти. Процессоры были значительно медленнее по сравнению с процессорами компьютеров, где обычно используется Linux. Как результат, разработчики Android решили минимизировать системные требования Linux.

Если рассматривать Linux на высоком уровне, то это комбинация ядра (без которого нельзя обойтись) и множества других, необязательных частей. Можно даже запустить одно ядро, без чего бы то ни было ещё. Так, Google вынуждена в любом случае использовать ядро Linux как часть ОС Android. Кроме того, были рассмотрены необязательные части и из них выбрано самое необходимое. Например, были добавлены сетевой фаервол IPTables и оболочка Ash. Любопытно, что добавили именно Ash, а не Bash, не смотря на то, что последний на порядок мощнее; вероятно, это решение было основано на том, что Ash менее требователен к ресурсам.

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

Выбор Linux в качестве основы оказал огромное влияние на все аспекты ОС Android. Сборка Android, по сути, есть вариация процесса сборки Linux. Код Android находится под управлением git (инструмент, разработанный для управления кодом Linux). И так далее.

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

Вы можете спросить, как же быть, если необходимо разработать нативное приложение для Android? Google настоятельно не рекомендует делать этого. Технически, конечно, это возможно, но в дальнейшем у вас не будет возможности распространять это приложение нормальным способом. Так что подумайте дважды, прежде чем начать нативную разработку под Android, если конечно, вы не работает над Android Open Source Project (AOSP), т.е. собственно ОС Android.

Уровень инфраструктуры приложения

Несмотря на некоторое сходство Apple iOS и Android ОС, существуют значительные отличия между архитектурными решениями на инфраструктурном уровне обоих ОС.

Apple решила использовать Objective-C как язык программирования и среду выполнения приложения iOS. Objective-C выглядит более или менее естественным выбором для ОС, в основе которой лежит Free BSD. Можно рассматривать Objective-C как обычный C++ с кастомным препроцессором, который добавляет некоторые специфические лингвистические конструкции. Почему же нельзя использовать стандартный C++, на котором написана Free BSD? Мне кажется причина в том, что Apple старается всё делать в своём, «эппловском» стиле.

Основная идея в том, что приложения iOS написаны более или менее на том же языке, что и стоящая за ними ОС.

Android-приложения сильно отличаются в этом смысле. Они написаны на Java, а это совсем другая технология, нежели C++ (хотя синтаксис и унаследован от C++).

Я думаю, основная причина состоит в необходимости одному и тому же приложению работать на различном аппаратном обеспечении. Эта проблема имеет место лишь для ОС Android; у ребят из Apple такой проблемы нет. iOS работает только на оборудовании собственного производства, и Apple полностью контролирует весь процесс. Для Android же всё наоборот: Google не контролирует производителей аппаратных средств. Например, ОС Android работает на процессорах с архитектурой x86, ARM и Atom (в комментах подсказывают, что x86 включает в себя Atom, и Android работает на x86, ARM, PPC и MIPS - примечание переводчика ). На бинарном уровне эти архитектуры несовместимы.

Если бы архитекторы ОС Android выбрали тот же путь, что и архитекторы из Apple, разработчики приложений под Android были бы вынуждены распространять несколько версий одного и того же приложения одновременно. Это стало бы серьёзной проблемой, которая могла бы привести к краху всего проекта Android.

Для того, чтобы одно и то же приложение могло работать на разном аппаратном обеспечении, компания Google использовала контейнер-ориентированную архитектуру (container-based architecture). В такой архитектуре двоичный код выполняется программным контейнером и изолируется от деталей конкретного аппаратного обеспечения. Примеры всем знакомы - Java и C#. В обоих языках двоичный код не зависит от специфики аппаратного обеспечения и выполняется виртуальной машиной.

Конечно, есть и другой способ достигнуть независимости от аппаратного обеспечения на уровне двоичного кода. Как один из вариантов, можно использовать эмулятор аппаратного обеспечения, так же известный как QEMU . Он позволяет эмулировать, например, устройство с процессором ARM на платформе x86 и так далее. Google могла бы использовать C++ как язык для разработки приложений внутри эмуляторов. Действительно, Google использует такой подход в своих эмуляторах Android, которые построены на основе QEMU.

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

Как бы то ни было, компания Google пришла к решению использовать Java как основной язык разработки приложений и среды их выполнения.

Я думаю, это было критически важное архитектурное решение, которое поставило Android в стороне от остальных мобильных ОС на основе Linux, представленных в настоящее время. Насколько мне известно, ни у одной из них нет совместимости двоичного кода на уровне приложений. Возьмём для примера MeeGo . Она использует C++ и фреймворк Qt ; не смотря на то, что Qt кроссплатформенный, необходимость делать разные сборки для разных платформ не исчезает.

Выбрав Java, нужно было решить, какую виртуальную машину (JVM) использовать. Ввиду ограниченности ресурсов использование стандартной JVM было затруднено. Единственным возможным выбором было использование Java ME JVM, разработанной для мобильных устройств. Однако счастье Google было бы неполным без разработки собственной виртуальной машины, и появилась Dalvik VM .

Dalvik VM отличается от других виртуальных Java-машин следующим:

  • Она использует специальный формат DEX для хранения двоичных кодов, в противовес форматам JAR и Pack200, которые являются стандартом для других виртуальных Java-машинах. Компания Google заявила, что бинарники DEX меньше, чем JAR. Я думаю, с тем же успехом они могли бы использовать Pack200, но они решили пойти своим путём.
  • Dalvik VM оптимизирована для выполнения нескольких процессов одновременно.
  • Dalvik VM использует архитектуру, основанную на регистрах против стековой архитектуры в других JVM, что приводит к увеличению скорости выполнения и уменьшению размеров бинарников.
  • Она использует собственный набор инструкций (а не стандартный байткод JVM)
  • Возможен запуск (если необходимо) нескольких независимых Android-приложений в одном процессе
  • Выполнение приложения может охватывать несколько процессов Dalvik VM «естественным образом» (позже мы обсудим, что это значит). Для поддержи этого добавлено:
    • Специальный механизм сериализации объектов, основанный на классах Parcel и Parcelable. Функционально преследуются те же цели, что и Java Serializable, но в результате данные имеют меньший объём и потенциально более терпимы к версионным изменениям классов.
    • Особый способ для выполнения вызовов между процессами (inter process calls, IPC), основный на Android Interface Definition Language (AIDL).
  • До Android 2.2 Dalvik VM не поддерживала JIT-компиляцию, что было серьёзным ударом по производительности. Начиная с версии 2.2, скорость выполнения часто используемых приложений