Как установить Linux в chroot на любой Android

Как я думаю все знают, Android – операционная система, построенная на базе ядра Linux. Однако от этого самого Linux-а там осталось крайне мало чего. Свой дисплейный сервер, свой HAL, свой SDK для разработки приложений. А что если мы хотим большего? Что если я хочу получить на своём девайсе относительно полноценный Linux-терминал с возможностью ставить любой нужные мне софт?

Зачем? Ну как зачем, просто потому что хочу. Зачем вообще задаваться вопросом “Зачем?”, если ответ очевиден. Возможно, вы уже собрались написать в коментах что-то вроде “Дак есть же Termux”. Вот только далеко не все нативные приложения собраны под него, а попытка их собрать превращается в тот ещё квест. Да и у Termux есть системные требования – Android 7.0 как минимум. А у метода в этом гайде требований по сути нет, не считая рут-прав.

Дисклеймер

Здесь и далее предполагается, что у следующего этому гайду человека есть базовое понимание работы в терминале, а также все бекапы данные с устройства и съёмного диска (если для установки выбран оный). Я не несу никакой ответственности за окирпиченные девайсы, потерянные данные или иные последствия ВАШИХ действий с ВАШИМ девайсом.

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

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

Ограничения

Тут нужно понимать, что Linux в chroot имеет некоторые особенности, которые могут помешать нормальной работе софта в нём. Если вы работали с Docker, то набор ограничений там примерно такой же.

  • Нет systemd, то есть управление службами через systemctl, просмотр логов через journalctl и прочее, вам недоступно;
  • Вы по-прежнему запущены поверх ядра Android, а в нём имеются далеко не все стандартные функции и модули, да и свои загрузить не выйдет;
  • Ваш процессор не стал x86-совместимым, так что про бинарный софт а-ля Steam можно забыть (хотя если вы достаточно извращенец, можно попробовать поднять qemu, но смысла в этом мало).

Что нам понадобится?

  • Устройство на базе Android. Версия Android значения не имеет, но вот версия ядра – да, об этом позже;
  • ROOT-доступ на этом самом устройства;
  • Какой-нибудь терминал. Если есть возможность использовать ADB, рекомендую его. Если нет, можно взять любое и тысяч приложений для этой задачи, например это (использовать терминалы со своим софтом а-ля Termux не рекомендуется);
  • Какое-то количество свободного места на нём, либо же карта памяти, USB флэшка и т. п.
  • Пара рук, способных набивать команды в упомянутом выше терминале, и немного мозга чтоб адаптироваться под особенности своего девайса

На старых устройствах также имеет смысл установить базовый пакет консольных утилит — BusyBox, хотя на Android 11 я обошёлся без него. Скачиваете приложение, ждёте пока оно что-то-там проверит, нажимаете Install внизу экрана. Ну и всё впринципе.

Далее по гайду предполагается что терминал у вас запущен от имени рута (то есть после запуска вы сделали команду su), и напоминать о необходимости этого я не намерен.

Подготовка

Для начала, следует определиться со следующими вещами:

Какая у вас архитектура процессора и версия ядра? Точнее даже не архитектура процессора непосредственно, а под какую архитектуру собрано ядро вашего Android. Ответ на оба вопроса можно узнать, выполнив в терминале uname -a. вывод uname

Эти вводные нам нужны, чтобы определиться с дистрибутивом, который будем разворачивать. Собственно я рекомендую смотреть в сторону ArchLinuxARM, поскольку его можно скачать сразу в виде архива для установки в chroot, что значительно упрощает нам задачу. Но если вы достаточно понимаете тему, можете взять любой другой. Но тут надо оговориться, что этот дистрибутив не запустится на ядре версии ниже, чем 3.2, и доступен только для arm64 и armv7. Так что если у вас ядро старее или архитектура armv6, придётся смотреть в сторону других дистрибутивов (причём в сторону довольно древних версий).

Идём на страницу загрузки и качаем файл под вашу архитектуру процессора. А какой, зависит от архитектуры:

  • Если у вас aarch64 / arm64 / armv8 (это всё одно и то же), то качаем “ARMv8 AArch64 Multi-platform”;
  • Если armv7, то “ARMv7 Multi-platform”

Скачиваем файл и переносим на устройство, не распаковывая.

Далее, следует определиться, куда мы будем его ставить.

Будем ставить раздел USB/SD-карты

Для начала, нужно разбить этот накопитель на 2 раздела: первый — в файловой системе FAT32 или exFAT для стандартного использования, второй — в ext2 / ext3 / ext4 для нашего недо-linux-а. Второй раздел рекомендую сделать размером хотя бы в 2 ГБ, а лучше — больше.

Как это сделать? Уже не моя проблема =) Тут вариантов куча. Если у вас на устройстве имеется кастомный Recovery (вроде TWRP, OrangeFox, CWM), можете воспользоваться им. Если такого нет, можете использовать любой софт для ПК, на подобии GParted. Файловые системы выбирайте из тех, что сможет прочитать ваш Android, для второго раздела рекомендую ext3. В моём случае конфигурация была примерно такая (swap-раздел создаём по желанию):

Почему бы не отдать всю флэшку под систему? Потому что Android будет сыпать уведомления об ошибках и слёзно умолять нас переформатировать флэшку. Так что оставить основной раздел стоит.

Далее, нужно найти это блочное устройство в /dev/block. Сделать это можно различными путями, самый тупой из возможных: посмотреть через терминал содержимое этой папки и сориентироваться по названиям и количеству разделов:

ls /dev/block

Ну или если ваш диск можно подключать и отключать “на горячую”, то можно тупо вывести содержимое папки до и после подключения, и посмотреть какое устройство появилось.

Нашли, в моём случае это /dev/block/mmcblk1p2. В вашем случае название устройства может отличаться, далее по гайду будет указано куда вставлять этот найденный путь.

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

…или будем ставить в образ диска

Этот метод несколько проще и безопаснее, пусть и скучнее.

Для начала создадим образ через dd, сохранять его буду во встроенной памяти телефона по пути /data/linux.img. Если хотите хранить образ где-либо ещё, просто замените этот путь в последующих командах.

dd if=/dev/zero of=/data/linux.img bs=1M count=2048

После count= указан размер нового образа в мегабайтах, можете изменить по необходимости. Теперь нужно отформатировать этот образ, советую выбрать ext3:

mkfs.ext3 /data/linux.img

Далее по гайду вместо пути к блочному устройтсву просто используйте /data/linux.img (или где вы там его создали).

Монтируем наш целевой диск

Собственно тут всё просто, создадим папку, например /data/linux:

mkdir /data/linux

И смонтируем туда образ или раздел, в который собираемся ставить систему:

mount -t ext3 РАЗДЕЛ_ИЛИ_ОБРАЗ /data/linux

Строку РАЗДЕЛ_ИЛИ_ОБРАЗ нужно заменить на путь к разделу, который вы создали и нашли выше (например /dev/block/mmcblk1p2), либо полный путь к образу (например /data/linux.img).

Представим, что всё завершилось без ошибок. Проверим содержимое смонтированного тома и его размер:

ls -l /data/linux
df -h /data/linux

Распаковка, первый вход

Для начала, распакуем нашу базовую систему. Переходим в /data/linux и распаковываем туда ранее скачанный пакет:

cd /data/linux
tar xzf /sdcard/ArchLinuxARM-aarch64-latest.tar.gz
# Имя архива и путь могут отличаться, я-то без понятия куда вы его скачали

После того, как архив распакуется, остаётся примонтировать основные системные виртуальные папки и войти в chroot.

Примечание: монтировать эти папки нужно один раз после перезагрузки. Повторный вызов этих команд mount --bind... может привести к их размонтированию в основной ОС, что приведёт к аварийному ребуту девайса

# Монтируем ведро папок
mount -o bind /dev /data/linux/dev
mount -o bind /dev/pts /data/linux/dev/pts
mount -o bind /proc /data/linux/proc
mount -o bind /sys /data/linux/sys

# ПО ЖЕЛАНИЮ, если хотим иметь доступ к встроенной памяти из arch-а
mkdir -p /data/linux/sdcard
mount -o bind /data/media/0 /data/linux/sdcard/

# Входим в арч. Если команды выше уже выполнялись после ребута, то достаточно сразу выполнить chroot как указано ниже
chroot /data/linux /bin/bash

После вызова последней команды можно заметить, что консоль несколько изменилась =)

Рекомендую сразу выполнить команду . /etc/profile, чтоб не было ошибок “Команда не найдена”. Можно заметить, что теперь корневая директория ведёт на наш раздел/образ, и файлов Adnrdoid-а в ней больше не видать. Значит всё прошло успешно, добро пожаловать в ArchLinux.

Немного донастройки

Этот раздел специфичен для ArchLinux, если вы ставили другой дистрибутив, разбирайтесь сами =)

Для начала глянем, если ли инет:

ping google.com

Если видимо ошибку а-ля “Could not resolve hostname”, то нужно создать файл /etc/resolv.conf с примерно таким содержимым:

nameserver 8.8.8.8
nameserver 8.8.4.4

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

pacman-key --init
pacman-key --populate archlinuxarm

# Удалим ядро и прошивки, ибо они не нужны, а иначе он их будет обновлять
# Минус пол гига занятого места =)
pacman -Rc linux-firmware

# Обновимся до упора
pacman -Suy

Поднимаем доступ по SSH

Для начала, убедимся, что он установлен (по идее должен):

pacman -S openssh
# Видми надпись "Already up to date", можно отменить переустановку на Ctrl-C

Далее выберем какой-нибудь пароль для ROOT-пользователя командой passwd. Плюс, чтобы мы смогли войти в систему от его имени, нужно в файле /etc/ssh/sshd_config добавить в конец строку:

PermitRootLogin yes

ВАЖНО: Если ваше устройство является “подвижным”, то есть предполагается его вывод за пределы вашей личной Wi-Fi сети и подключение к иным (особенно общественным), включать доступ по ssh от имени рута будет не лучшей идеей. Лучше будет создать отдельного пользователя, и входить от его имени. Но для гайда и вход от рута пойдёт, указанную донастройку оставлю на ваше усмотрение.

Осталось генерировать ключи хоста и запустим сервер:

ssh-keygen -A
/bin/sshd

После описанных действий вы сможете войти в archlinux на вашем устройстве через ssh root@IP_АДРЕС, в рамках локальной сети понятное дело.

А теперь автоматизация

Остаётся один нюанс: после каждой перезагрузки устройства нужно заново монтировать над раздел/образ, все подразделы, и заново запускать sshd. Автоматизируем это дело пожалуй =)

Для начала создадим скрипт start_linux.sh для Android-а, который будет всё монтировать и запускать SSH-сервер. По сути можно создать его прямо в chroot, затем выйти из него переместить в требуемое место в системе Android. Либо же воспользоваться любым текстовым редактором и проводником в самом Android. Содержание скрипта примерно такое (не забываем делать корректировки под специфику вашей установки):

#!/system/bin/sh
mkdir -p /data/linux

# Простенькая функция для защиты от повторного монтирования =)
bind_if_not() {
    if grep -qs "$2 " /proc/mounts
    then
        echo "$2 already mounted"
    else
        mount -o bind $1 $2
    fi
}

# Монтируем раздел/образ
# ЗАМЕНИТЕ /dev/block/mmcblk1p2 на свой вариант
mount -t ext3 /dev/block/mmcblk1p2 /data/linux

# Монтируем системные виртуальные ФС
bind_if_not /dev /data/linux/dev
bind_if_not /dev/pts /data/linux/dev/pts
bind_if_not /proc /data/linux/proc
bind_if_not /sys /data/linux/sys

# Опционально, пробрасываем встроенную память
bind_if_not /data/media/0 /data/linux/sdcard/

# Запускаем sshd внутри арча
chroot /data/linux /bin/bash -c ". /etc/profile; /sbin/sshd"

Далее нужно сделать этот скрипт исполняемым chmod +x start_linux.sh и поместить… куда-то, откуда система сможет его запустить при включении. Само собой нужно выйти из chroot и вернуться в обычный Android, прежде чем проверять, куда его поместить

Этот момент также специфичен для вашего девайса и его настроек, вот пара вариантов:

  • Если рут-права у вас получены через Magisk, то можно поместить его в папку /data/adb/service.d/, тогда Magisk выполнит его при включении телефона;
  • Если у вас кастомная прошивка с поддержкой init.d, то можно кинуть его в /system/etc/init.d;
  • Либо же можно найти сторонние приложения для запуска скриптов при включении устройства;
  • Либо же можно поместить его куда-нибудь в /data/ (например по пути /data/start_linux.sh) и руками запускать после перезапуска устройства через терминал (сначала su, затем /data/start_linux.sh).

А насколько далеко можно зайти?

В начале было сказано, что данный метод годится для любого Android-а. Но насколько любого?

Пользуясь описанным выше методом, я тупо взял и поднял Debian на Samsung Galaxy Ace, ядро 2.6, Android 2.3.7. Само собой это было не особо просто, поскольку процессор данного девайса работает на архитектуре armv6, и современные дистрибутивы подобное не поддерживают. Да и ядро 2.6 мешало процессу. Но, при желании и дольки безумия, всё возможно.

Пожалуйста, Debian 6 с рабочим SSH на (по нынешним меркам) простой звонилке.

thumb_up 7 thumb_down 0 chat Комментарии (2) favorite Донат