Linux Mobile або “emerge world” для PinePhone. Частина 2

💡 Усі статті, обговорення, новини про Mobile — в одному місці. Приєднуйтесь до Mobile спільноти!

Всім привіт. Дана стаття є продовженням першої частини в якій ми робили мінімальний 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 і доступні нам по мережі. Якщо якогось пакету нема в бінарному вигляді, то будем використовувати один із варіантів наведених нижче (в порядку пріоритету):

  1. кросс-компіляція на oster
  2. qemu-chroot на oster
  3. нативна компіляція на oak
  4. нативна компіляція на телефоні

Другий і третій варіант +/- рівнозначні з точки зору часу компіляції. Хоча деякі великі пакети, як от 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 пристрої:

  1. swap, 3GB, lz4 компресія
  2. /tmp, 1GB, zstd компресія
  3. /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. А саме:

  1. файлові дані — файл завантажений в пам’ять (фактично, прокешований файл).
  2. анонімні дані — 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

Робочий стіл SXMO

Для більш зручної навігації по меню можна встановити:

(linden)# emerge -va gui-apps/wofi

і визначити:

(linden)$ echo "export SXMO_MENU=wofi" >> ~/.config/sxmo/profile

SXMO меню

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

Термінал в SXMO із запущеним htop

Також можна встановити:

(linden)# emerge -va media-video/mpv media-video/celluloid media-sound/audacious media-sound/shortwave net-news/liferea

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

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

RSS feed з новинами

RSS feed з новинами

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

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 запущений в контейнері на Linux

Браузер в Android

Браузер в 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 на мобільних платформах.

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному4
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Сумно, що у 2026 на платформі убогий Mali 400, могла б бути платформа для smart camera з вбудованим Yolo та стрімінгом

Підписатись на коментарі