Привет, Хабр! В этой статье я хочу поделиться пошаговой инструкцией по компиляции Android Open Source Project для Raspberry Pi. Эта статья поможет разобраться в первых шагах разработки ОС на базе Android. В тех местах, где можно обойтись ссылкой на официальную документацию или документацию форка AOSP для Raspberry Pi, я так и поступлю.
Если вы решите повторить мой эксперимент, вам понадобится следующее оборудование:
-
Raspberry Pi 4
-
Компьютер с Linux (официально рекомендуется использовать Ubuntu)
-
USB-C кабель
-
картридер для microSD-карт и сама карта
-
(опционально, но очень желательно) Raspberry Pi Debug probe или другой UART-переходник
Настройка окружения для сборки
На этом этапе нам понадобится установить пакеты, необходимые для сборки. Все они доступны в стандартных репозиториях, поэтому ничего интересного в этом разделе не будет.
Дополнительно к пакетам из документации мне понадобилось установить pkg-config, meson и модуль mako для python3.
Клонирование репозитория
AOSP состоит из более чем тысячи git-репозиториев + репозиториев, специфичных для конкретного устройства (в нашем случае это проект android-rpi). Для управления локальной копией git-репозиториев используется утилита repo.
Ключевые команды, которые нам понадобятся:
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r66 git clone https://github.com/android-rpi/local_manifests .repo/local_manifests -b arpi-13 repo sync
Первая команда клонирует репозиторий с манифестом AOSP, в котором хранится информация обо всех репозиториях, предоставляемых Google.
Вторая команда добавляет манифест с репозиториями, специфичными для устройства, а третья выполнит git clone для всех репозиториев, указанных в одном из манифестов.
Сборка Android
Инициализация окружения
В документации команды описаны более подробно, здесь я приведу только те, которые понадобятся нам для сборки образа ОС.
. build/envsetup.sh
Lunch target
Одна и та же копия исходного кода AOSP поддерживает варианты сборки для произвольного количества устройств. Достигается это при помощи lunch targets (или lunch combos, pun intended), которые состоят из названия устройства и типа прошивки (eng, userdebug или user).
lunch rpi4-eng
Компиляция
В процессе компиляции используются несколько систем сборки: make, soong, ninja, а начиная с Android 13 к этому зоопарку добавился ещё и Bazel. В этой статье мы не будем вдаваться в детали, как эти системы взаимодействуют между собой, и просто вызовем цели make для сборки конечных образов ОС:
make ramdisk systemimage vendorimage
На моём стареньком i5-9600k чистая сборка занимает около двух с половиной часов, поэтому на этом этапе можно прерваться и сходить пообедать 🙂
Также на этом этапе могут возникать ошибки компиляции, но обычно они связаны с отсутствующими в системе зависимостями. После получения сообщения «Build completed successfully» можно переходить к следующему этапу — разметке SD-карты.
Сборка ядра Linux
Обычно ядро в Android-проектах не собирается одновременно с остальной ОС, а поставляется в виде предсобранного бинарного артефакта. В нашем случае такого артефакта нет, а дальше в статье мы увидим, что нам понадобится собрать дополнительный модуль ядра.
mkdir kernel cd kernel repo init -u https://github.com/android-rpi/kernel_manifest -b arpi-5.15 repo sync build/build.sh
Поскольку ядро обычно собирается отдельно, у него есть свой манифест и свой набор репозиториев.
Структура разделов
В отличие от традиционного Linux, где и ОС, и пользовательские файлы могут находиться на одном разделе, Android требует наличия нескольких разделов с разным назначением:
-
bootсодержит образ ядра Linux -
systemсодержит Android Framework, который включает в себя всё, с чем мы привыкли работать из обычных приложений — системные сервисы, Java-библиотеки и системные ресурсы. -
vendorсодержит (обычно) проприетарные сервисы, разработанные вендором SoC, на котором работает устройство -
dataсодержит пользовательские данные, включая установленные приложения и их данные
Для того чтобы разметить всю SD-карту одной командой, я написал небольшой shell-скрипт, который использует артефакты, собранные на предыдущих шагах:
#!/usr/bin/env bash set -ex AOSP_ROOT="android-rpi" AOSP_OUT="android-rpi/out/target/product/rpi4" KERNEL_OUT="kernel/out/arpi-5.15/dist" DEVICE=${1:?Device not set} SYSTEM_PARTITION="${DEVICE}2" VENDOR_PARTITION="${DEVICE}3" BOOT_MOUNTPOINT=/media/$USER/android_boot wipefs -a $DEVICE* sfdisk /dev/sdb < partitions.sfdisk mkfs -t vfat /dev/sdb1 mkfs -t ext4 -L userdata /dev/sdb4 dd if=$AOSP_OUT/system.img of=$SYSTEM_PARTITION bs=1M dd if=$AOSP_OUT/vendor.img of=$VENDOR_PARTITION bs=1M mkdir -p $BOOT_MOUNTPOINT mount /dev/sdb1 $BOOT_MOUNTPOINT # copy firmware & ramdisk cp $AOSP_ROOT/device/arpi/rpi4/boot/* $BOOT_MOUNTPOINT cp $AOSP_OUT/ramdisk.img $BOOT_MOUNTPOINT # copy kernel binaries cp $KERNEL_OUT/Image.gz $BOOT_MOUNTPOINT cp $KERNEL_OUT/bcm2711-rpi-*.dtb $BOOT_MOUNTPOINT mkdir $BOOT_MOUNTPOINT/overlays cp $KERNEL_OUT/vc4-kms-v3d-pi4.dtbo $BOOT_MOUNTPOINT/overlays # enable adb over usb # cp $KERNEL_OUT/dwc2.dtbo $BOOT_MOUNTPOINT/overlays # echo 'dtoverlay=dwc2,dr_mode=peripheral' >> $BOOT_MOUNTPOINT/config.txt umount $BOOT_MOUNTPOINT rmdir $BOOT_MOUNTPOINT
Схема разделов хранится рядом в partitions.sfdisk:
label: dos label-id: 0xa35ef4be device: /dev/sdb unit: sectors sector-size: 512 /dev/sdb1 : start= 2048, size= 262144, type=c, bootable /dev/sdb2 : start= 264192, size= 2097152, type=83 /dev/sdb3 : start= 2361344, size= 262144, type=83 /dev/sdb4 : start= 2623488, size= 58493952, type=83
Вот и всё! После этого можно вставить SD-карту в Raspberry Pi, подключить питание и HDMI и дождаться окончания загрузки.
Бонус-трек: включаем adb over USB
Когда я писал эту статью, мне никак не удавалось подключиться к Pi по adb, хотя в eng-прошивке adb всегда доступен, и подключиться по сети при помощи Ethernet я смог. Оказалось, что разработчики android-rpi выключили поддержку USB device mode по дефолту, из-за чего и компьютер, и Raspberry Pi считали, что они могут быть только USB-хостом.
Для того чтобы включить поддержку device mode, нам понадобится сделать следующее:
-
Раскомментировать первую строчку в init.rpi4.rc.
init.rc— это init-процесс в терминах Linux, то есть процесс с PID 1, запускающий все остальные процессы. В Android init помимо всего прочего отвечает за мониторвание USB-FFS и запуск adbd. -
Добавить сборку модуля ядра
dwc2в<kernel_dir>/common/build.config.arpi
-
В
MAKE_GOALSдобавить строкуoverlays/dwc2.dtbo -
В
FILESдобавить строкуarch/arm64/boot/dts/overlays/dwc2.dtbo
-
Раскомментировать две строки после комментария
enable adb over usbв моём скрипте выше.
ссылка на оригинал статьи https://habr.com/ru/articles/749724/
Добавить комментарий