Linux Mobile або “emerge world” для PinePhone. Частина 2
Всім привіт. Дана стаття є продовженням першої частини в якій ми робили мінімальний bootable image з Gentoo Linux для PinePhone. На даний момент у нас є підготовлена microSD картка, яку ми можемо вставити в слот телефона і робити перший запуск системи.
Перший запуск
Тут може стати в нагоді вже згаданий в першій частині USB-to-TTL конвертор з 3.5mm штекером, який ми вставляємо в аудіо гніздо телефона, переключаємо 6й діп-свіч в положення OFF. Підключаємо конвертор до комп’ютера, визначаємо його послідовний порт, і запускаємо, щось типу:
(oster)# screen /dev/ttyUSB0 115200
Стартуємо...

Перше завантаження
Через послідовний порт ми можемо бачити логи u-boot, ядра, OpenRC.
Після успішного завантаження має автоматично встановитись WiFi підключення, яке ми сконфігурували раніше, а також запуститись sshd сервер.
(oster)# ssh genpp@<pinephone-ip> (oster)# password:
Логін для root відключений за умовчанням, тому логінимось під genpp і далі робимо
su -
Тепер у нас є live система і ми можемо збирати пакети безпосередньо на ній, або ж використовувати бінарні пакети доступні по мережі з oak та/або oster машин.
Саме час дати ім’я нашому телефону:
(pinephone)# echo "hostname=\"linden\"" > /etc/conf.d/hostname
Виберемо потрібні нам локалі в /etc/locale.gen і виконаємо:
(linden)# locale-gen
З цього моменту ми будемо встановлювати пакети на linden в звичний спосіб по можливості використовуючи бінарні пакети, попередньо зібрані на oster або oak і доступні нам по мережі. Якщо якогось пакету нема в бінарному вигляді, то будем використовувати один із варіантів наведених нижче (в порядку пріоритету):
- кросс-компіляція на oster
- qemu-chroot на oster
- нативна компіляція на oak
- нативна компіляція на телефоні
Другий і третій варіант +/- рівнозначні з точки зору часу компіляції. Хоча деякі великі пакети, як от firefox, нативно на oak збираються швидше ніж на емуляторі в oster.
Zram
Для пристроїв з обмежними ресурсами, доволі корисним є використання zram для віртуального збільшення оперативної пам’яті. Також zram може бути корисним у випадках, коли є необхідність інтенсивного використання жорсткого диску (в нашому випадку microSD), наприклад під час компіляції. Так, замапивши відповідний директорій з диску в пам’ять ми не тільки суттєво піднімаємо продуктивність (RAM значно швидше за microSD), а і продовжуємо життя самій microSD зменшуючи кількість записів.
До прикладу, oak, який має 8GB фізичної пам’яті, з відповідною конфігурацією zram може зібрати firefox повністю в пам’яті, не використовуючи диск взагалі. Це при тому, що розпакований і скомпільований код firefox важить більше 10GB.
Як це працює?
Zram може використовуватись для «збільшення» оперативної пам’яті, шляхом мапінгу swap файлу на zram пристрій. Тобто, коли у нас починає закінчуватись оперативна пам’ять ядро приймає рішення вивантажити частину даних в swap, який, в свою чергу, використовує ту ж саму оперативну пам’ять, але при цьому здатен робити архівування даних «на льоту». Іншими словами, ядро буде періодично архівувати частину оперативної пам’яті. В середньому рівень стиснення становить 1:3, тобто в 1GB фізичної пам’яті ми зможемо розміщувати до 3GB фактичних даних.
Інший варіант застосування — це мапінг певного директорія на zram пристрій. Відповідно, все що пишеться в цей директорій буде, фактично, писатись в пам’ять і архівуватись на льоту. В нашому випадку корисно змонтувати /var/tmp/portage на zram. Це директорій який використовує portage при компіляції всіх пакетів.
Отже, встановлюємо:
(linden)# emerge -va sys-block/zram-init
Додаємо наступну конфігурацію в /etc/conf.d/zram-init:
rc_before="systemd-tmpfiles-setup bootmisc" load_on_start=no unload_on_stop=no num_devices=3 type0=swap size0=3072 algo0=lz4 labl0=zram_swap type1=/tmp flag1=ext4 size1=1024 opts1="noatime" mode1=1777 algo1=zstd para1="level=3" labl1=zram-tmp type2=/var/tmp/portage flag2=ext4 size2=4096 opts2="noatime" mode2=1775 owgr2="portage:portage" algo2=zstd labl2=zram-tmp-portage
Тут ми конфігуруємо 3 zram пристрої:
- swap, 3GB, lz4 компресія
/tmp, 1GB, zstd компресія/var/tmp/portage, 4GB, zstd компресія
Також, ми відключаємо завантаження zram модуля через zram-init сервіс, натомість будем його завантажувати в стандартний спосіб через /etc/modules-load.d. Тому зробимо:
(linden)# mkdir -p /etc/modules-load.d (linden)# echo "zram" > /etc/modules-load.d/zram.conf (linden)# echo "options zram num_devices=3" > /etc/modprobe.d/zram.conf
Додаємо zram-init сервіс в boot runlevel:
(linden)# rc-update add zram-init boot
В результаті, після перевантаження, маємо отримати:
(linden)# zramctl NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT /dev/zram2 zstd 4G 2.1M 28.9K 196K /var/tmp/portage /dev/zram1 zstd 1G 632K 7.5K 124K /tmp /dev/zram0 lz4 3G 4K 73B 12K [SWAP]
swappiness
Створений swap є відносно «дешевим», оскільки він мапиться на RAM, тому є сенс використовувати його більш інтенсивно.
Загалом, ядро розрізняє 2 види даних, що зараз завантажені в RAM. А саме:
- файлові дані — файл завантажений в пам’ять (фактично, прокешований файл).
- анонімні дані — heap + stack програм.
В першому випадку, не є проблемою вивантажити ці дані з пам’яті і «забути» про них, на певний час. Пізніше, за необхідності, ядро зможе їх завантажити ще раз. В другому ж випадку, неможливо просто «викинути» ці дані з пам’яті, оскільки відновити їх пізніше буде неможливо. Тому другий тип може бути лише вивантажений в swap файл, якщо він є. Так от, кожного разу, ядро приймає рішення яким саме типом даних «пожертвувати» цього разу. Ми можемо впливати на це рішення до певної міри за допомогою параметра vm.swappiness. Це ціле число від 0 до 200. Де 0 — мінімальна «свопливість», тобто кожного (чи майже кожного) разу ядро буде вивантажувати з пам’яті файлові дані, відповідно, swap використовуватись не буде. А 200 — максимальна «свопливість», тобто в більшості випадків будуть вивантажуватись анонімні дані в swap файл. Дефолтне значення — 60. Збільшимо його до 120:
(linden)# sysctl -w vm.swappiness=120 (linden)# echo "vm.swappiness=120" > /etc/sysctl.d/50-swappiness.conf
SXMO
Для початку встановимо Display Manager який буде запускати графічну сесію. Ми будемо використовувати tinydm.
(linden)# emerge -va tinydm
За умовчанням користувач з uid=1000 буде автоматично логінитись в графічне середовище при старті.
Встановлюємо Window Manager для Wayland. SXMO використовує sway:
(linden)# emerge -va sway
Встановлюємо мета-пакет SXMO, який має підтягнути необхідний мінімум залежностей:
(linden)# emerge -va sxmo-meta
Додамо користувача в pipewire групу:
(linden)# usermod -a -G pipewire genpp
Тепер майже все готово для старту SXMO. Створюємо дефолтну сесію для tinydm:
(linden)# tinydm-set-session -s /usr/share/wayland-sessions/swmo.desktop
додаємо необхідні сервіси у відповідні runlevels:
(linden)# rc-update add tinydm default (linden)# rc-update add elogind boot (linden)# rc-update add bluetooth default
і запускаємо Display Manager:
(linden)# /etc/init.d/tinydm start

Робочий стіл SXMO
Для більш зручної навігації по меню можна встановити:
(linden)# emerge -va gui-apps/wofi
і визначити:
(linden)$ echo "export SXMO_MENU=wofi" >> ~/.config/sxmo/profile

SXMO меню
Також будуть корисними додаткові udev rules специфічні для pinephone:
(linden)# emerge -va sys-libs/device-pine64-pinephone
За умовчанням, кнопка живлення на телефоні буде виключати телефон (робити poweroff), нам це не потрібно. Тому відключимо це в elogind:
(linden)# echo "HandlePowerKey=ignore" >> /etc/elogind/logind.conf.d/10-elogind.conf
Додаткові програми
Встановимо ще ряд корисних програм:
(linden)# emerge -va app-admin/logrotate app-admin/syslog-ng app-editors/vim app-misc/mc app-misc/screen net-misc/ntp sys-apps/mlocate sys-process/htop
Термінал для SXMO:
(linden)# emerge -va gui-apps/foot

Термінал в SXMO із запущеним htop
Також можна встановити:
(linden)# emerge -va media-video/mpv media-video/celluloid media-sound/audacious media-sound/shortwave net-news/liferea

Прослуховування радіо

RSS feed з новинами

RSS feed з подкастами
Docker
Звісно, куди ж без нього. Це Linux, а тому ми маємо first class support, і багато корисних речей можна використовувати під Docker-ом:
(linden)# emerge -va app-containers/docker app-containers/docker-buildx app-containers/docker-compose (linden)# usermod -a -G docker genpp

Тестовий запуск докераFirefox
Для firefox корисним також буде встановити додаткові конфіги, які зроблять більш зручним UX на телефоні:
(linden)# emerge -va www-client/firefox app-mobilephone/mobile-config-firefox

Firefox на PinePhone
Waydroid
Waydroid може бути доволі корисним інструментом для забезпечення більш плавної міграції з Android на Linux. Він дозволяє завантажити Android в контейнері під Linux-ом. Встановимо:
(linden)# emerge -va app-containers/waydroid (linden)# rc-update add waydroid default
Перед першим запуском необхідно завантажити імідж Android-а. Це буде імідж вже згаданої LineageOS:
(linden)# waydroid init
або
(linden)# waydroid init -s GAAPS
якщо нам потрібен Android з встановленими Google Applications.
За умовчанням, Android контейнер не має доступу до інтернету. Для виходу в Світ необхідно додати відповідний раут.
Спочатку визначимо IP адресу waydroid інтерфейсу
(linden)# ip addr show dev waydroid0
і додамо маршрут:
(linden)# echo "ip route add default via 192.168.240.1" | waydroid shell

Android запущений в контейнері на Linux

Браузер в Android
Bootable image
Ну от, тепер ми маємо робочу live систему, з потрібним набором програм, налаштувань. Було б непогано мати можливість легкого клонування її. Для цього ми можемо зробити зворотну процедуру і створити bootable image з робочої системи.
Для цього, спочатку встановимо:
(linden)# emerge -va sys-apps/autoexpand-root
це нам дозволить, при першому старті системи, збільшити / розділ до максимального розміру. Натомість bootable image, при створенні, буде зменшений до мінімального розміру.
Тепер, як і на початку, створюємо файл в якому ініціалізуємо таблицю розділів, копіюємо туди весь вміст нашої live системи за виключенням файлів, які можуть бути відтворенні на новій інсталяції (наприклад Gentoo репозиторій, overlays, distfiles, etc), інсталюємо завантажувач, далі зменшуємо / до мінімального розміру, зменшуємо розділ і обрізаємо файл з іміджем. Виглядати це буде приблизно так:
(oster)# mount -t btrfs -o subvol=rootfs-btrfs /dev/mmcblk0p2 /mnt/gentoo
(oster)# mount /dev/mmcblk0p1 /mnt/gentoo/boot
(oster)# fallocate -l 16GiB gentoo.img
(oster)# losetup -f gentoo.img
(oster)# echo -e "1M,256M,L,*\n,+,L\n" | sfdisk /dev/loop0
(oster)# partprobe /dev/loop0
(oster)# mkfs.ext4 -L boot /dev/loop0p1
(oster)# mkfs.btrfs -L rootfs /dev/loop0p2
(oster)# mkdir -p dst
(oster)# mount /dev/loop0p2 dst
(oster)# btrfs subvolume create dst/rootfs-btrfs
(oster)# umount dst
(oster)# mount -t btrfs -o subvol=rootfs-btrfs,compress=zstd:3 /dev/loop0p2 dst
(oster)# mkdir -p dst/boot
(oster)# mount /dev/loop0p1 dst/boot
(oster)# dd if=/path/to/u-boot-sunxi-with-spl.bin of=/dev/loop0 bs=1024 seek=8
(oster)# rsync -avr --include-from=rsync-include --exclude-from=rsync-exclude /mnt/gentoo/ dst/
(oster)# umount -R /mnt/gentoo
(oster)# min_size=$(btrfs inspect-internal min-dev-size dst | awk '{print $1}')
(oster)# btrfs filesystem resize ${min_size} dst
(oster)# umount -R dst
(oster)# min_size_k=$(($min_size / 1024 + 1))
(oster)# echo ",${min_size_k}K" | sfdisk -N 2 /dev/loop0
(oster)# image_size=$(( ($(sfdisk -l /dev/loop0 | grep /dev/loop0p2 | awk '{print $3}') + 1)*512 ))
(oster)# losetup -d /dev/loop0
(oster)# truncate -s ${image_size} gentoo.img
(oster)# xz -v gentoo.img
(oster)# sha256sum gentoo.img.xz > gentoo.img.xz.sha256
Тут приймаємо, що:
- microSD з робочою системою знаходиться на
/dev/mmcblk0і змонтована в/mnt/gentoo - loopback device іміджу замаплений на
/dev/loop0 - в поточному директорії є файли
rsync-includeтаrsync-excludeякі містять список файлів/директорій які ми включаємо/виключаємо з іміджу. Наприкладrsync-exclude:
/var/cache/binpkgs/* /var/cache/distfiles/* /var/db/repos/* /var/log/* ....................
Скрипт для виконання вищенаведених дій можна знайти тут
В результаті, ми маємо отримати gentoo.img.xz імідж, який, власне, і є bootable image з Gentoo для PinePhone.
Ну і для тих, хто все ж не наважився повторити все вищеописане самостійно, готовий імідж можна завантажити ось тут.
Обіцяний «emerge world» на завершення
Gentoo — це rolling release система, а це значить — встановлюємо один раз, оновлюємось скільки завгодно. Все просто як:
(linden)# emerge --sync (linden)# emerge -uDn world
P.S.
В наступних серіях (якщо автор буде мати час і натхнення) ми розглянемо деякі аспекти практичного використання даного пристрою. А поки, діліться в коментарях своїми цікавими історіями використання Linux на мобільних платформах.
1 коментар
Додати коментар Підписатись на коментаріВідписатись від коментарівСумно, що у 2026 на платформі убогий Mali 400, могла б бути платформа для smart camera з вбудованим Yolo та стрімінгом