Изучаем Android. Ядро (Kernel) — что это такое.
Многие владельцы Android устройств на различных форумах и сайтах часто встречают упоминание о чем-то непонятном, что называют ядром, или по-английски kernel. Его можно поменять и упоминание о нем встречается в меню настроек устройства, в разделе «О планшете (телефоне)».
Если копнуть поглубже, то окажется, что ядро – это часть операционной системы, и оно есть не только у Android, но и у других операционных систем: Windows, iOS, MacOS и прочих. Но нас будет интересовать ядро Android, и что это такое я попытаюсь объяснить на уровне начинающих пользователей.
Вы, наверное, знаете, что любая операционная система, и Android в том числе – это, по большому счету, набор программ, которые управляют работой всего устройства, и отвечают за запуск пользовательских приложений, таких как игры, менеджеры файлов, веб-браузеры и прочие.
А ядро Android является, практически, самой главной частью операционной системы, которая отвечает за взаимодействие между всем «железом» и программной частью системы. Ядро состоит из набора драйверов всего имеющегося в устройстве оборудования и подсистемы управления памятью, сетью, безопасностью, и прочих основных функций операционной системы.
Например, когда вы касаетесь экрана, чтобы запустить какое-либо приложение, драйвер сенсорной панели экрана определяет место, в котором произошло нажатие и сообщает координаты другим программам, которые опять же с помощью ядра найдут в памяти устройства нужное приложение и запустят его. Это конечно, очень упрощенная модель, но суть работы операционной системы она отражает.
Таким образом, мы выяснили, что когда любое программное обеспечение нуждается в том, чтобы оборудование планшета или телефона что-нибудь сделало, оно обращается за этим к ядру операционной системы.
Ядро управляет абсолютно всем оборудованием: Wi-Fi, Bluetooth, GPS, памятью и прочими устройствами. Не является исключением и «сердце» устройства – его процессор. Ядро может управлять его частотой и энергоснабжением.
Ядро операционной системы Android, позаимствовано ее разработчиками, компанией Google, у операционной системы Linux.
Так как ядро управляет всем оборудованием, а оборудование у всех планшетов и телефонов разное, базовое ядро Android дорабатывается производителем для каждого устройства отдельно.
Как и прошивки, ядра бывают стоковыми (заводскими) и кастомными – альтернативными, созданные независимыми разработчиками.
Зачем нужны кастомные ядра? Стоковое ядро максимально оптимизируется производителем для конкретного устройства, но в нем обычно заблокированы такие важные функции ядра, как, например, управление частотой процессора. И если вам понадобится разогнать процессор своего планшета, вам нужно будет сменить ядро на кастомное, в котором функция управления частотой процессора разблокирована.
Кроме того, кастомные ядра, обычно основаны на более свежих версиях Linux ядер. Вот примерный перечень возможностей, которые нам дают кастомные ядра:
- Изменение частоты процессора в широких пределах;
- Разгон графической подсистемы (GPU);
- Снижение частоты и напряжения питания процессора, что позволяет достичь более длительного времени работы от батареи;
- Более свежие и качественные драйверы, например, ускоряющие работу GPS или добавляющие новые функции;
- Широкие возможности по настройки и конфигурации звука и цветовой гаммы экрана;
- Поддержка альтернативных файловых систем (XFS, ReiserFS и прочих).
Так как альтернативные ядра создаются независимыми разработчиками, нет никакой гарантии, что после установки кастомного ядра ваш планшет или телефон будут работать без сбоев. Поэтому перед прошивкой нового ядра желательно сделать полную резервную копию системы.
Источник
Основы безопасности операционной системы Android. Уровень ядра
Вступление
Самой распространенной операционной системой для смартфонов на сегодняшний день является Android. Но не только этот факт подогревает интерес к ней. Открытость, возможность что-то настроить, подкрутить, и, естественно, сломать тоже в немалой степени способствуют увеличению популярности этой платформы. Я попробую поделиться опытом, как устроена эта операционная система, а так же рассмотреть систему безопасности. Всем, кому интересно, добро пожаловать! В этой статье я рассмотрю безопасность на уровне ядра.
Disclaimer
Термины я буду стараться писать на английком языке, так как боюсь ошибиться в их переводе. Если кто-то знает, как их красиво перевести на русский язык, напишите мне, и я дам перевод этих терминов. Желательно, чтобы у вас под рукой находились исходный код Android (хотя я и буду стараться давать ссылки на файлы в Интернете), потому что я иногда буду давать ссылки на файлы, где находится та или иная функциональность. Как загрузить исходный код, можно почитать здесь или вот в этой статье на Хабре.
Список статей
Стек Android
Ну никуда не деться от этой картинки. Я нашел её на просторах Интернета и нужна она для того, чтобы понять из чего состоит Android. Итак, в стеке Android выделяют четыре уровня (снизу-вверх):
- Linux kernel (Ядро Linux)
- Native Libraries
- Application Framework
- Applications (Приложения)
Linux kernel. Как неудивительно это звучит, но изначально, Android Inc. — это стартап. Как и во всех стартапах, в этой компании стояла задача максимально использовать уже существующие решения. Поэтому в качестве ядра этой платформы был выбран Linux из-за его открытости и наличия необходимой функциональности. В Android ядро Linux управляет памятью, процессами, а так же используется в качестве hardware abstraction layer (HAL). Насколько мне известно, в Linux драйвера либо встроены в ядро, либо разработаны в виде загружаемых модулей ядра. Так как в Android загрузка модулей ядра по умолчанию отключена, а если встраивать все драйвера, то ядро очень сильно разрастется, то было принято решение создать промежуточный слой (proxy) между ядром и драйверами, который и назвали HAL. Таким образом, HAL — это просто набор интерфейсов, имплементация которых реализована в драйверах. С другой стороны в ядро были добавлены некоторые системы, которые характерны только для Android систем. На данный момент, они пока не включены в основную ветку ядра Linux, поэтому просто скачать ядро Linux и заменить им ядро Android не получится. Среди них следует выделить, Binder (обеспечивает межпроцессное взаимодействие IPC/RPC), Asynchronous SHared MEMory — Ashmem (драйвер разделяемой памяти), Wakelocks (механизм, который позволяет предотвращать затемнение экрана и/или отключение процессора), Low Memory Killer, Alarm, Logger и т.д.
Native Libraries. К этому слою относятся различные нативные библиотеки, которые необходимы для работы Android. Они так же позаимствованы у open-source сообщества. Среди них мы можем найти SQLite, WebKit и т.д.
Android Framework. К этому слою относится то, с чем мы обычно взаимодействуем, когда пишем наши приложения для Android (PowerManager, ActivityManager, NotificationManager и т.д.).
Applications. Приложения бывают двух типов: те, что поставляются вместе с образом системы (системные) и приложения, которые мы загружаем из маркета или других источников. В первом случае, в устройстве приложения находятся в «/system/app» директории, во втором случае в «/data/app».
Безопасность на уровне ядра
Давайте рассмотрим процесс установки приложения на Android устройство. Существует несколько способов установить приложение на устройство (в общем случае):
- Используя приложение PackageInstaller
- Используя приложение Android Market
- Используя комманду adb install
На рисунке, например, приложение ex1.apk устанавливается с помощью PackageInstaller (используется в случае, если вам, например, по почте прислали приложение и вы хотите его установить с устройства), ex2.apk устанавливается с помощью Android Market (Google Play), и приложение ex3.apk устанавливается с помощью комманды adb install ex3.apk (обычно эта комманда используется разработчиками приложений для установки приложения с компьютера).
Во время установки, Android каждому приложению по умолчанию присваивает уникальные user ID (UID) и group ID (GID), таким образом каждому приложению в этой операционной системе соответсвует свой пользователь. Имя пользователя обычно имеет формат app_x, а идентификаторы пользователя вычисляется по формуле (Process.FIRST_APPLICATION_UID + x), Process.FIRST_APPLICATION_UID равен 10000. Эти идентификаторы приложения не изменяются. Список установленных приложений хранится в файле «/data/system/packages.list» и если у вас рутованый телефон, или вы работаете с эмулятором, то вы можете просмотреть этот файл, используя следующую комманду:
У каждого приложения есть своя домашняя директория, например /data/data/
— имя Android пакета, например com.ex.ex1 Имя Android пакета задается в свойстве package в файле AndroidManifest.xml Эта папка — Internal storage (внутреннее хранилище), директория, где приложение хранит все свои приватные данные, и к которому разработчики приложений получают доступ используя функции Context.getFilesDir() или Context.getDir() У этой папки права доступа определены как drwxr-x—x, т.е. только владелец и пользователи входящие в группу владельцев имеют полный доступ к этой папке. А так как каждое приложение определено как уникальный пользователь, то это означает, что приложения, по умолчанию, не имеют доступа к информации друг друга. Хотя при создании файла во внутреннем хранилище можно явно задать, что этот файл будет MODE_WORLD_READABLE и/или MODE_WORLD_WRITABLE
Кроме того, на уровне ядра уникальные UID и GID каждого приложения используются для разделения доступа к ресурсам системы (память и процессорное время). Таким образом, на уровне ядра для каждого приложения создается своя собственная песочница (Application Sandbox).
С другой стороны, разработчик приложения может указать, что некоторые ЕГО приложения должны иметь один и тот же UID. В AndroidManifest.xml файле для этого есть специальное свойство sharedUserId В этом случае, эти приложения будут иметь доступ к ресурсам друг-друга, но только если они подписаны одним и тем же ключом разработчика.
Некоторые permission (разрешения) так же работают на уровне ядра. Давайте, например, рассмотрим наиболее используемое разрешение android.permission.INTERNET Если приложение запрашивает это разрешение, то Android во время установки дополнительно включает это приложение в специальную группу «inet». Так же работают и некоторые другие разрешения. Список соответствия между этими разрешениями и соответствующими группами можно найти в файле frameworks/base/data/etc/platform.xml:
Список соответствия между именами этих групп и значениями (GID) задан в явном виде в файле system/core/include/private/android_filesystem_config.h в массиве структур android_ids[]:
Таким образом, если приложение пытается подключиться к Интернету, ядро проверяет, находится ли это приложение в группе с идентификатором AID_INET. Если нет, то приложению запрещается доступ. Код этой проверки очень тривиальный:
Заключение
Это моя первая статья на Хабре, так что не судите строго. Если сообществу интересно, то я продолжу в следующих статьях описывать внутренности Android. Я понимаю, что много не знаю, да и времени всегда не хватает, но я постараюсь поделиться тем, что уже пропустил через себя. Надеюсь, что узнаю что-то новое из комментариев! Если кому-то интересна какая-то определенная тема, то пишите в комментариях, постараюсь в будущих статьях учесть ваши пожелания.
Источник
F.A.Q по режимам работы ядра Android
Разное
Предисловие!
Вчера, я выложил здесь аналогичную статью, но(. ) посыпалась масса непонятной критики. Статью, я удалил дабы,не распыляться!Мне написал один человек, который попросил вернуть статью, т.к она актуальна!Спасибо ему за поддержку)))
У многих (как я думаю) ,на девайсе, сделан ROOT
, поставлена кастомная прошивка.
В некоторые прошивки, уже встроены элементы управления ядром.Есть программы, с помощью которых, меняется режим ,на подобие — SetCPU или System Tuner Pro(которой я и пользуюсь тк в ней очень богатый функционал).Когда-то, я столкнулся с вопросом :»а зачем это и что это». в последствии, некоторые мои знакомые, также, озадачивались этим вопросом, что это за режимы и зачем!?
В двух словах — режим активности ядра прошивки!
Вот, расшифровка, что дают эти режимы!
1. Ondemand — как можно быстрее меняет частоту процессора в зависимости от его использования. Является стандартным профилем в официально прошивке.
2. Conservative — модификация профиля ondemand. Отличие заключается в том, что частота изменяется более плавно, а не скачет вверх в момент сильной нагрузки. Направлен на сокращение энергопотребления.
3. Interactive — устанавливает частоту процессора в зависимости от нагрузки, примерно как это делает conservative и ondemand, но с использованием задержек.
4. Smartass — переписанный профиль interactive. По утверждению разработчиков, работает более отзывчиво, при этом большую часть времени аппарат работает на низких частотах. Сам снижает частоту во время сна.
5. Userspace — позволяет любой запущенной от рута программе изменять текущую частоту.
6. Performance — при самой минимальной нагрузке увеличивает частоту до установленного максимума.
7. Powersave — режим максимального энергосбережения.
Тут, дополнительно режимы для тех кто использует ядро (LorDModUE):
8. Brazilianwax — более быстрое переключение частот, но менее экономичный (улучшенный вариант режима Smartass).
9. InteractiveX — модифицированный режим Interactive, улучшен режим перехода в состояние сна и выхода их него (быстрее снижает частоту при засыпании и быстрее восстанавливает частоту процессора при выходе из сна).
10. OndemandX — модифицированный режим Ondemand, также как и у предыдущего режима улучшен режим перехода в сон и выход из сна.
11. Smartass2 — режим Smartass, с дополнительными фишками для экономии энергии.
Скрины на примере программы System Tuner Pro
Источник
Обзор особенностей ядра Андроида
“А я… карбюратор промываю!”
Анекдот
В детском садике мы с единомышленниками препарировали кузнечиков в надежде разобраться в их строении. В школе распаивали радиоприёмник “Россия”. В институте дошла очередь до автомобилей, гайки которых были многократно переставлены. Интересы поменялись, но желание “разбирать” иногда просыпается, и сегодня оно направлено на Андроид.
Сколько раз вас выручало наличие исходников Андроида? Меня — уже не счесть. Андроид — открытый проект, но, к сожалению, у нас есть возможность только читать; править код Андроида, не будучи сотрудником Google, практически невозможно. Погрустим над этим моментом и загрузим репозиторий. Как это сделать, отлично описано на официальном сайте.
Общая архитектура
Архитектуру Андроида можно схематично изобразить так:
Оригинальная схема не содержит информации об особенностях ядра и не акцентирует внимание на Binder-е и системных сервисах. А ведь Binder является “клеем”, связывающим все компоненты системы.
Как правило, в книгах описывается верхний левый синий прямоугольник, то есть API, которое доступно разработчику прикладных приложений. Нас же интересует всё, что ниже. Сегодня мы рассмотрим только ядро.
Ядро — центральная часть любого дистрибутива, называемого “Линукс”. Несмотря на доступность “чистого” ядра, многие разработчики (Ubuntu, Fedora, SuSe и т.д.) добавляют к нему свои патчи перед включением в дистрибутив. Андроид идёт той же дорогой, только ценой потери прямой совместимости: на “чистом” ядре он не заведётся. В настоящее время есть намерения включить “андроидизмы” в основную версию ядра, в 2011 году Линус Торвальдс давал на этот процесс 4-5 лет. Успех уже достигнут в рамках включения механизма wakelocks в версии ядра 3.5.
Рассмотрим “андроидизмы” более подробно.
История данного механизма эпична, потянет на сборник статей “Путь wakelock-ов в Линукс”: их обсуждение заняло порядка 2000 писем в рассылке LKML.
Настольные компьютеры и ноутбуки имеют устоявшуюся систему энергорежимов (у x86 процессоров таковых несколько): компьютер работает “на полных оборотах”, когда что-то делается, и уходит в энергоэффективный режим, когда система простаивает. Уход в “спящий” режим происходит либо после довольно длительного бездействия, либо вручную, например, при закрытии крышки ноутбука.
На телефонах требовался другой механизм: основное состояние системы — “спячка”, выход из него осуществляется только в случаях необходимости. Таким образом, система может уснуть, даже если какое-то приложение проявляет активность. В Андроиде был реализован механизм wakelock-ов: если приложение (или драйвер) выполняет что-то важное, что должно дойти до логического завершения, оно “захватывает” wakelock, предотвращая засыпание устройства.
Попытки портирования механизма wakelock-ов в ядро вызвали сопротивление многих разработчиков. Программисты Андроида решали конкретную проблему, решением которой стал определённый механизм. Условия задачи были весьма узки. Целевая платформа — ARM, поэтому использовались её особенности: ARM-процессоры изначально предполагают частую смену режимов работы “сна” и “бодрствования”, в отличие от x86. В Андроиде приложения общаются с системой управления питанием через PowerManager, а что делать клиентским Линукс-приложениям?
Разработчики Андроида даже не пытались найти общее решение “на будущее”, которое потом без проблем бы вливалось в основное ядро, не консультировались по этой проблеме с сообществом ядра Линукс. Можно ли их за это винить? Несмотря на все проблемы и обсуждения, как упоминалось выше, в ядре появилось API с идентичной функциональностью autosleep.
Программистам приложений под Андроид довольно редко приходится сталкиваться с wakelock-ами, так как платформа и драйверы обрабатывают возложенные на них обязательства с учётом “спящего” режима. Тем не менее, вмешаться в этот процесс поможет знакомый PowerManager. Кстати, автору приходит в голову только один сценарий: не дать телефону уснуть при запуске сервиса из BroadcastReceiver-а, что решается вспомогательным классом из Android Support Library WakefulBroadcastReceiver.
Low Memory Killer
В стандартном ядре Линукса есть Out of Memory Killer, который на основании параметра badness определяет убиваемый процесс:
badness_for_task = total_vm_for_task / (sqrt(cpu_time_in_seconds) *
sqrt(sqrt(cpu_time_in_minutes)))
Таким образом, чем больше процесс потребляет памяти и чем меньше живёт, тем меньше ему повезёт.
Все программисты, читавшие документацию или проходившие собеседования, знают, что, во-первых, процесс может быть “убит” и при наличии свободных ресурсов, во-вторых, кандидат на вытеснение выбирается по другим критериям: наличие “живых” Андроид-компонент, видимость пользователю и так далее.
Механизм довольно простой: каждому процессу присваивается приоритет от -17 до 16, при этом чем выше приоритет, тем выше вероятность убивания процесса, и, в зависимости от количества свободной памяти, выбирается приоритет, начиная с которого процессы будут завершены. Приоритеты описаны в ProcessList.java. Занимательно, что приоритет приложения домашнего экрана HOME_APP_ADJ довольно высок, а я-то думал: почему он постоянно перезапускается?
Массивы mOomAdj и mOomMinFreeLow/mOomMinFreeHigh как раз задают правила “когда что очистить”:
Таким образом, приложение домашнего экрана вытесняется при остатке свободной памяти в 73728 КБ на телефоне с экраном 1280×800 и ОЗУ в 700 МБ.
ProcessList передаёт соответствующие значения в ядро, что можно видеть в его методе updateOomLevels.
Приоритеты процессам выставляет Activity Manager Service, один из многих системных сервисов, общаться с которым можно через Activity Manager.
Binder, наряду с другими решениями (Files, Sigmals, Sockets, Pipes, Semaphores, Shared Memory и т.д.), решает задачу межпроцессного взаимодействия. Ноги у данного решения растут из проекта OpenBinder, разработчики которого в своё время перешли в команду Андроида.
Bionic (реализация libc) не использует System V IPC, так как в андроидовском окружении стандартные средства приведут к утечкам ресурсов.
Особенности:
- Управление потоками (мы все помним, что сервис, поддерживающий AIDL, должен работать в многопоточном окружении). Максимальное число потоков — 15 (ProcessState.c, метод open_driver), поэтому не стоит блокировать Binder-потоки в большом количестве без лишней необходимости.
- Механизм информирования о смерти процесса, держащего объект Binder “Link to Death”. Например, через него Window Manager узнаёт о смерти приложения и удаляет связанные с ним окна. Также LocationManager при смерти всех своих слушателей перестаёт опрашивать GPS-приёмник. Lowmemorykiller доволен. 🙂
- 2 режима вызова: блокирующий и неблокирующий (oneway). В первом случае вызывающий поток блокируется и ждёт отработки метода в потоке процесса-обработчика. Программисты просто вызывают методы через точку, взаимодействие потоков берёт на себя платформа.
- Передача UID и PID для безопасности. Через них системные сервисы определяют, есть ли у вызывающего процесса права совершать запрашиваемые действия.
- Для Java-программистов — средства создания Proxy и Stub-ов для конвертирования вызовов Java-методов в транзакции Binder-а.
Рассмотрим как это работает на примере LocationManager-а.
Когда мы хотим получить информацию о GPS, происходит следующее:
- Наше приложение вызывает соответствующий метод у LocationManager-а.
- LocationManager делегирует вызов прокси-объекту, преобразующему Java-методы и объекты в Binder-транзакцию (прокси-объектом у LocationManager-а является mService).
- Транзакция посылается драйверу ядра, который перенаправляет её LocationManagerService-у, отнаследованному от .LocationManager.Stub.
- .LocationManager.Stub делает обратные действия: разворачивает транзакцию в вызов Java-метода.
- .LocationManagerService обрабатывает запрос (используя, например, GPS-драйвер).
- Stub-объект пакует ответ в транзакцию, и процесс идёт в обратном направлении.
- Драйвер пересылает ответ обратно.
- Прокси-объект распаковывает результат вызова метода в Java-объекты.
Как видим, за вызовом методов системных сервисов скрывается довольно большая логика.
Anonymous Shared Memory (ashmem) — механизм разделяемой памяти. В Линуксе, как правило, данный механизм реализован через POSIX SHM. Разработчики Андроида сочли его недостаточно защищённым, что могло сыграть на руку вредоносному ПО. Особенностями ashmem-а являются счётчик ссылок, при обнулении которого разделяемая память может быть освобождена (например, память освобождается при завершении всех процессов, использующих её), и сокращение разделяемого региона при нехватке памяти в системе.
Ярким примером использования ashmem-а является процесс zygote, в котором загружается стартовая версия Dalvik VM с загруженными базовыми классами и ресурсами, а остальные приложения просто ссылаются на эту память.
Binder имеет ограничение на размер транзакции в 1МБ (иначе будет выброшено исключение TransactionTooLargeException). Если нам надо передать из одного процесса в другой большой объём данных, можно как раз воспользоваться Ashmem-ом: создать MemoryFile и передать дескриптор файла в другой процесс.
Обычные дистрибутивы, как правило, используют две системы логирования: лог ядра, доступный через команду dmesg, и системные логи, располагающиеся обычно в директории /var/log.
Система Андроида включает несколько циклических буферов для хранения сообщений пользовательских программ (что продлевает время жизни карт памяти, так как циклы чтения-записи не расходуются впустую) и не имеет дополнительных задержек от работы с сокетами, которые применяются в стандартном syslog-е.
На диаграмме представлена общая система логирования Андроида. Драйвер логирования предоставляет доступ к каждому буферу через /dev/log/*. Приложения имеют доступ к ним не напрямую, а через библиотеку liblog. С библиотекой liblog общаются классы Log, Slog и EventLog. Команда adb logcat показывает содержимое буфера “main”.
В данной заметке мы кратко рассмотрели некоторые особенности Андроида как Линукс-системы. За скобками остались некоторые другие части (pmem, RAM console и т.д.), а также такие важные аспекты платформы в целом, как System Service, процесс запуска системы и другие. Если данная тема будет интересна, в следующих статьях мы рассмотрим и их.
Источник