Развлечение на выходные: собираем Android для Raspberry Pi из исходного кода

от автора

Привет, Хабр! В этой статье я хочу поделиться пошаговой инструкцией по компиляции 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, нам понадобится сделать следующее:

  1. Раскомментировать первую строчку в init.rpi4.rc. init.rc — это init-процесс в терминах Linux, то есть процесс с PID 1, запускающий все остальные процессы. В Android init помимо всего прочего отвечает за мониторвание USB-FFS и запуск adbd.

  2. Добавить сборку модуля ядра dwc2 в <kernel_dir>/common/build.config.arpi

  • В MAKE_GOALS добавить строку overlays/dwc2.dtbo

  • В FILES добавить строку arch/arm64/boot/dts/overlays/dwc2.dtbo

  1. Раскомментировать две строки после комментария enable adb over usb в моём скрипте выше.


ссылка на оригинал статьи https://habr.com/ru/articles/749724/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *