Android linux kernel modules

Родственные связи. Собираем модули ядра и нативные Linux-приложения для Android

Содержание статьи

Введение

Как всем извес­тно, Android име­ет под собой фун­дамент в виде ядра Linux. Из это­го сле­дует, что в теории на смар­тфо­не мож­но запус­тить все те при­ложе­ния, что дос­тупны на дес­ктоп­ном Linux. На прак­тике же все слож­нее. Пос­коль­ку набор Native-биб­лиотек в Android отли­чает­ся от таково­го на дес­кто­пе (не говоря уже об архи­тек­туре плат­формы), при­ложе­ния тре­бует­ся ком­пилиро­вать ста­тичес­ки. А иног­да еще и пат­чить. Но и в этом слу­чае работос­пособ­ность при­ложе­ния не всег­да гаран­тирова­на.

Что каса­ется модулей ядра, которые могут быть весь­ма полез­ны на смар­тфо­не (под­дер­жка NTFS, нап­ример), то здесь все еще инте­рес­нее. Во мно­гих ядрах от вен­дора отклю­чена фун­кция заг­рузки модулей (начиная с Android 4.3, это фак­тичес­ки тре­бова­ние Google. — Прим. ред.). Поэто­му нам при­дет­ся не толь­ко подоб­рать пра­виль­ную вер­сию ядра для сбор­ки модулей, но и, воз­можно, пересоб­рать само ядро, вклю­чив такую под­дер­жку, или прос­то добавить модуль в сам образ ядра.

Да­лее в статье мы рас­смот­рим, как побороть эти проб­лемы, и поп­робу­ем соб­рать модули Linux-ядра и нес­коль­ко при­ложе­ний.

Подготовка

Для сбор­ки модулей (ядра) и при­ложе­ний нам пот­ребу­ется тул­чейн, то есть связ­ка из кросс‑ком­пилято­ра и лин­ковщи­ка, плюс набор стан­дар­тных инс­тру­мен­тов сбор­ки, которые мож­но уста­новить из репози­тория (при­мер для Ubuntu):

Те­перь мож­но уста­новить тул­чейн. Их сущес­тву­ет как минимум два — стан­дар­тный гуг­лов­ский NDK и тул­чейн от Linaro, куда силь­нее опти­мизи­рующий код. Раз­лича­ются они еще и набором target-биб­лиотек — если NDK содер­жит те биб­лиоте­ки, которые име­ются в Android и, соот­ветс­твен­но, могут не под­ходить для сбор­ки обыч­ных POSIX-сов­мести­мых при­ложе­ний, то Linaro вклю­чает минималь­ный набор стан­дар­тных POSIX-биб­лиотек под ARM, для исполь­зования которых в гуг­лооси понадо­бит­ся ста­тичес­кая лин­ковка.

Для сбор­ки ядра мы, в целях сов­мести­мос­ти, будем исполь­зовать пер­вый. Заходим на стра­нич­ку https://developer.android.com/tools/sdk/ndk/index.html и, выб­рав нуж­ную вер­сию NDK, ска­чива­ем его. Затем уста­нав­лива­ем на ска­чан­ный файл пра­во исполне­ния и рас­паковы­ваем:

А вот для сбор­ки прог­рамм понадо­бит­ся и тул­чейн от Linaro. Для его получе­ния про­ще все­го зай­ти на forum.xda-developers.com/showthread.php?t=2098133 и выб­рать билд. Лич­но я выб­рал Linaro GCC 4.6.4-2013.05 (пос­коль­ку про­цес­сор у меня не Cortex, то и качал я arm-unknown-linux-gnueabi-linaro_4.6.4-2013.05-build_2013_05_18.tar.bz2). Рас­паковы­ваем и для пущего удобс­тва пере­име­новы­ваем:

До­бавим путь к тул­чей­ну в

/.bashrc (и заод­но опре­делим отдель­ные перемен­ные, которые на вре­мя ком­пиляции ядра, воз­можно, и не при­годят­ся, но в даль­нейшем могут ой как понадо­бить­ся):

Компиляция модулей и ядра

Для начала опре­делим, под­держи­вает ли сто­ковое ядро модули. Для это­го смот­рим, есть ли на устрой­стве файл /proc/modules. В зависи­мос­ти от это­го мы пой­мем, что делать даль­ше. В слу­чае если модули под­держи­вают­ся, мы берем ваниль­ное ядро той же вер­сии (но луч­ше, конеч­но, взять от вен­дора), кон­фигури­руем его, ком­пилиру­ем толь­ко модули, закиды­ваем их в /system/lib/modules и заг­ружа­ем с помощью коман­ды insmod на устрой­стве. Если же ядро модулей не под­держи­вает, мож­но либо взять готовое кас­томное ядро с под­дер­жкой модулей (об этом читай в статье «Выбира­ем кас­томное ядро для сво­его Android-аппа­рата»), либо соб­рать свое, вклю­чив нуж­ные модули в образ ядра.

В слу­чае сам­сунгов­ских устрой­ств (у меня как раз такое) исходни­ки ядер лежат на opensource.samsung.com. Для сбор­ки ядра нам понадо­бит­ся его кон­фиг. В некото­рых устрой­ствах он находит­ся в фай­ле /proc/config.gz, но, к сожале­нию, не во всех, поэто­му раз­берем дру­гой метод его получе­ния. Пос­ле ска­чива­ния и рас­паков­ки перехо­дим в соот­ветс­тву­ющий каталог, смот­рим фай­лы, находя­щиеся в arch/arm/configs/, и выбира­ем под­ходящий по архи­тек­туре. В моем слу­чае там был толь­ко один файл — n1a_00_defconfig. Перехо­дим обратно в каталог, куда мы пер­воначаль­но рас­пакова­ли ядро, и набира­ем сле­дующую коман­ду:

Читайте также:  Windows get kerberos ticket

Да­лее нас­тра­иваем ядро с помощью стан­дар­тной коман­ды make menuconfig, что­бы вклю­чить нуж­ные нам модули. Затем собира­ем:

Хакер #192. ZeroNights–2014

Сборка модулей

Для сбор­ки исклю­читель­но модулей без самого ядра мож­но исполь­зовать либо коман­ду make modules, либо, если ты вклю­чил все­го один модуль, сле­дующие коман­ды (вмес­то net/netfilter под­ставь каталог собира­емо­го модуля):

Пос­ле сбор­ки нам нуж­но все получив­шиеся фай­лы ско­пиро­вать в еди­ный каталог:

За­тем, в слу­чае пол­ной ком­пиляции, нуж­но соб­рать фай­лы в ZIP-архив. Не абы какой, а сфор­мирован­ный опре­делен­ным обра­зом (речь идет о фай­ле обновле­ния для кас­томной кон­соли вос­ста­нов­ления. — Прим. ред.). Для это­го кло­ниру­ем с гит­хаба шаб­лон для дан­ного фай­ла:

Пос­коль­ку те ути­литы, что име­ются в этом авто­мати­чес­ком апдей­тере, нем­ного уста­рели (во вся­ком слу­чае, на моем план­шете они завер­шались с сег­фолтом), нуж­но их заменить рабочи­ми, которые берем на d-h.st/RgI, и, рас­паковав, заменя­ем ими фай­лы с теми же наз­вани­ями в катало­ге AnyKernel/kernel/. Кро­ме того, нуж­но изме­нить скрипт для авто­апдей­тера, находя­щий­ся в AnyKernel/META-INF/com/google/android/updater-script. В конеч­ном ито­ге дол­жно получить­ся при­мер­но сле­дующее:

Путь /dev/block/mmcblk0p9 здесь — та часть, которую необ­ходимо изме­нить. Это раз­дел boot, и поч­ти на всех устрой­ствах он будет пред­став­лен раз­ными фай­лами. Что­бы узнать имя фай­ла на сво­ем устрой­стве, выпол­ни сле­дующую коман­ду:

Пос­ле прав­ки запако­выва­ем каталог:

За­тем кида­ем файл на устрой­ство и уста­нав­лива­ем его с помощью кас­томно­го рекаве­ри (TWRP или CWM).

Пос­ле сбор­ки и уста­нов­ки ядра дол­жна получить­ся при­мер­но такая кар­тинка

Сборка приложений

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

И лишь затем мож­но прис­тупать.

Bash собирать с помощью тул­чей­на Linaro очень лег­ко — ска­чива­ем исходни­ки c офи­циаль­ного FTP и рас­паковы­ваем:

Вы­пол­няем скрипт configure и собира­ем:

Пос­ле сбор­ки появит­ся файл bash, который мы и копиру­ем на устрой­ство в /system/xbin.

Bash, запущен­ный под Android

Сто­ит дать ком­мента­рии, почему bash нуж­но ком­пилиро­вать с помощью тул­чей­на Linaro. В Bionic, стан­дар­тной реали­зации биб­лиоте­ки libc в Android, отсутс­тву­ют некото­рые POSIX-сов­мести­мые фун­кции, исполь­зуемые bash (такие, нап­ример, как mkfifo() или wctomb()). Соот­ветс­твен­но, соб­рать bash с исполь­зовани­ем этой биб­лиоте­ки без тан­цев с буб­ном не вый­дет. В Linaro же, с дру­гой сто­роны, исполь­зует­ся стан­дар­тная POSIX-сов­мести­мая биб­лиоте­ка glibc. Пос­коль­ку мы собира­ем bash ста­тичес­ки, нам все рав­но, что исполь­зует­ся в Android, — глав­ное, что­бы вер­сия glibc, с которой мы собира­ем, подош­ла к ядру. Впро­чем, сегод­ня обратное малове­роят­но.

Lshw — удоб­ная кон­соль­ная ути­лита, поз­воля­ющая быс­тро соб­рать информа­цию о дос­тупном железе. Ком­пилиро­вать ее (опять же исполь­зуя Linaro) дос­таточ­но прос­то. Ска­чива­ем пос­леднюю вер­сию, рас­паковы­ваем и заменя­ем в фай­лах src/Makefile и src/core/Makefile ком­пилятор C++ на ком­пилятор от Linaro (перемен­ной CXX нуж­но прис­воить зна­чение arm-unknown-linux-gnueabi-g++), добавив так­же опцию —static в CXXFLAGS. Затем собира­ем обыч­ным обра­зом.

Читайте также:  Mac os мониторинг трафика

Это дос­таточ­но удоб­ный кон­соль­ный менед­жер про­цес­сов для Linux. Для вывода информа­ции он исполь­зует биб­лиоте­ку ncurses, так что для его ком­пиляции пот­ребу­ется чуть боль­ше вре­мени. Соз­даем каталог htop, перехо­дим в него и ска­чива­ем ncurses:

Ус­танав­лива­ем перемен­ную $SYSROOT_ADDITIONS, запус­каем configure с нуж­ными парамет­рами и собира­ем:

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

Ска­чива­ем и рас­паковы­ваем сам htop, пред­варитель­но перей­дя на уро­вень выше:

Вновь пере­опре­деля­ем перемен­ные окру­жения для сбор­ки:

Кон­фигури­руем и собира­ем:

Все бы хорошо, но пос­ле попыт­ки запус­ка на устрой­стве вывали­вает­ся ошиб­ка «Error opening terminal: screen». Лечит­ся это прос­то — дос­таем отку­да‑нибудь каталог terminfo (я его выдер­нул из Terminal IDE, прос­то потому, что он ока­зал­ся под рукой), копиру­ем в /system/etc и выпол­няем в тер­минале на гад­жете сле­дующую коман­ду:

Пос­ле это­го htop запус­тится без заморо­чек.

Htop, запущен­ный под Android

Tmux — менед­жер тер­миналов, более прод­винутая аль­тер­натива извес­тно­го всем адми­нам screen, соз­данная раз­работ­чиками OpenBSD. В слу­чае с Android его удоб­но исполь­зовать для работы с устрой­ством через adb shell или SSH (нап­ример, ходить на TV Box или HDMI-стик под управле­нием Android. — Прим. ред.).

Для ком­пиляции tmux нам понадо­бит­ся все та же ncurses — ее мож­но взять из пре­дыду­щей сбор­ки, ско­пиро­вав каталог rootdir. Помимо ncurses, пот­ребу­ется биб­лиоте­ка libevent. Соз­даем каталог tmux, уста­нав­лива­ем перемен­ную $SYSROOT_ADDITIONS и ска­чива­ем libevent и сам tmux:

Под­готав­лива­емся к сбор­ке tmux:

И наконец, собира­ем сам tmux:

Пос­ле сбор­ки и залив­ки исполня­емо­го фай­ла перед запус­ком tmux, помимо перемен­ной TERMINFO, нуж­но опре­делить перемен­ную TMPDIR — лич­но я исполь­зовал /data/local/tmp.

Сто­ит заметить, что tmux может работать толь­ко от рута, потому что пра­ва дос­тупа не поз­воля­ют писать в выше­ука­зан­ную пап­ку кому попало.

Се­анс SSH-соеди­нения с Android. Для раз­деления тер­минала исполь­зует­ся tmux. В левой час­ти мож­но уви­деть вывод lshw

Ngrep

А это край­не полез­ная ути­лита, поз­воля­ющая отлавли­вать пакеты с задан­ным пат­терном (может быть нуж­но, нап­ример, для отладки RESTful-при­ложе­ний). Для ее сбор­ки пот­ребу­ется соб­рать еще и libpcap. Как обыч­но, соз­даем каталог, куда и ска­чива­ем libpcap, рас­паковы­ваем его и собира­ем:

Ска­чива­ем сам ngrep, рас­паковы­ваем, собира­ем:

Раз­берем опции обо­их configure. В слу­чае с libpcap мы отклю­чили под­дер­жку DBUS по понят­ной при­чине отсутс­твия его в Android и ука­зали тип зах­вата пакетов (пос­коль­ку ком­пилиру­ем мы в конеч­ном ито­ге под Linux, то и тип зах­вата ста­вим соот­ветс­тву­ющий). Для ngrep же мы ука­зали путь к заголо­воч­ным фай­лам libpcap и отклю­чили пониже­ние при­виле­гий по при­чине отсутс­твия фай­ла /etc/passwd в Android, куда эта фун­кци­ональ­ность смот­рит.

Пе­рех­ватыва­ем пакеты, содер­жащие сло­во google, исполь­зуя ngrep

Linux Deploy

Ком­пиляция прог­рамм может занять немало вре­мени, да и не вся­кое при­ложе­ние мож­но с лег­костью соб­рать (нап­ример, тек­сто­вый torrent-кли­ент rtorrent пот­ребу­ет сбор­ку libtorrent, а уж эта биб­лиоте­ка, в свою оче­редь, потянет за собой Boost). И если для пары‑трой­ки при­ложе­ний это не столь кри­тич­но, то в слу­чае сбор­ки боль­шего количес­тва тру­дозат­раты ста­новят­ся слиш­ком велики. Да и сами при­ложе­ния в слу­чае ста­тичес­кой ком­понов­ки могут раз­дувать­ся до нево­обра­зимых раз­меров. Одна­ко есть решение и для этой ситу­ации — Linux Deploy, который с лег­костью мож­но най­ти в Google Play.

Читайте также:  Linux chmod recursive all

Пос­коль­ку Android пос­тро­ен на базе ядра Linux, а изме­нения в нем не нас­толь­ко силь­ны, что­бы мешать запус­ку обыч­ных POSIX-при­ложе­ний (что и было про­демонс­три­рова­но выше), сущес­тву­ет воз­можность раз­верты­вания chroot-окру­жения (с проб­росом соот­ветс­тву­ющих псев­дофай­ловых сис­тем) и уста­нов­ки в нем userland-час­ти дис­три­бути­вов, под­держи­вающих архи­тек­туру ARM. При­ложе­ние Linux Deploy дела­ет имен­но это, соз­давая образ и мон­тируя его как loop-устрой­ство.

Под­держи­вают­ся сле­дующие дис­три­бути­вы:

  • Ubuntu;
  • OpenSUSE;
  • Fedora;
  • Arch Linux;
  • Gentoo;
  • и, наконец, Kali Linux (его наличие, несом­ненно, обра­дует пен­тесте­ров).

Пос­ле раз­верты­вания и запус­ка сис­темы в нее необ­ходимо каким‑то обра­зом вой­ти. Для это­го сущес­тву­ет два метода: по SSH и через VNC. При наличии SSH-сер­вера в самом Android в Linux Deploy нуж­но либо его отклю­чить, либо пере­опре­делить порт. А если исполь­зовать VNC, необ­ходимо доус­тановить в Android VNC-кли­ент (рекомен­дую bVNC). Стан­дар­тные имя поль­зовате­ля / пароль — android/changeme соот­ветс­твен­но.

За­пуск окру­жения Ubuntu в Linux Deploy Ubuntu в Linux Deploy по виду неот­личим от дес­ктоп­ного

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

Заключение

В статье были опи­саны два (а если счи­тать ком­пиляцию ядра с модуля­ми, то три) метода рас­ширения фун­кци­ональ­нос­ти на Android. Под­ведем ито­ги.

Ком­пиляция ядра и модулей име­ет смысл толь­ко в тех слу­чаях, ког­да тебе нуж­на низ­коуров­невая фун­кци­ональ­ность — будь то под­дер­жка ФС или, допус­тим, модуль iptables. В сов­ремен­ных сто­ковых ядрах под­дер­жка заг­рузки модулей чаще все­го отклю­чена, так что для добав­ления фун­кци­ональ­нос­ти вся­ко пот­ребу­ется ком­пиляция все­го ядра.

В слу­чае с ком­пиляци­ей неболь­ших POSIX-при­ложе­ний мож­но попытать­ся исполь­зовать гуг­лов­ский NDK, иду­щий с Bionic и прак­тичес­ки несов­мести­мый с POSIX, а мож­но исполь­зовать сто­рон­ний тул­чейн для архи­тек­туры ARM, в котором, как пра­вило, есть биб­лиоте­ка glibc, и ком­пилиро­вать при­ложе­ния ста­тичес­ки. Одна­ко сле­дует пом­нить, что ста­тичес­ки слин­кован­ное при­ложе­ние весит дос­таточ­но мно­го, таким обра­зом, нелиш­ним будет еще раз под­чер­кнуть, что этот метод годит­ся лишь для неболь­ших при­ложе­ний.

Для запус­ка круп­ных при­ложе­ний мож­но исполь­зовать Linux Deploy, поз­воля­ющий раз­вернуть на Android пол­ноцен­ную userland-часть популяр­ных дис­три­бути­вов. Одна­ко и у него есть недос­татки. Во‑пер­вых, он изрядно куша­ет батарею, а во‑вто­рых, раз­мер обра­за с дан­ной userland-частью не может быть боль­ше 4 Гб, так что, если рас­катал губу на кучу при­ложе­ний, закатай ее обратно.

В целом же запуск POSIX-при­ложе­ний в Android впол­не воз­можен — что и было показа­но в статье. А уж каким спо­собом ты будешь что‑то делать, ты волен выбирать сам. Stay freedom.

Библиотеки, портированные на Android

Нес­мотря на то что Android не явля­ется в пол­ной мере POSIX-сов­мести­мой ОС, под него все же были пор­тирова­ны некото­рые из биб­лиотек, дос­тупных под дес­ктоп­ной Linux. Пос­мотрим, что это за биб­лиоте­ки:

  • SDL — удоб­ная «обер­тка» вок­руг низ­коуров­невых муль­тимеди­афун­кций; исполь­зует­ся в основном для раз­работ­ки игр;
  • FFmpeg — кон­верта­ция боль­шинс­тва аудио- и виде­офор­матов;
  • Qt — начиная с пятой вер­сии, Qt дос­тупна и под Android;
  • Unity — игро­вой дви­жок;
  • Ogre — «обер­тка» вок­руг OpenGL для работы с 3D-гра­фикой.

В общем, с точ­ки зре­ния пор­тирова­ния при­ложе­ний выб­рать есть из чего.

Источник

Оцените статью