Budowanie jąder

Na tej stronie szczegółowo opisano proces tworzenia niestandardowych jąder dla urządzeń z systemem Android. Te instrukcje poprowadzą Cię przez proces wybierania właściwych źródeł, budowania jądra i osadzania wyników w obrazie systemu zbudowanym na podstawie projektu Android Open Source Project (AOSP).

Możesz uzyskać nowsze źródła jądra, korzystając z Repo ; zbuduj je bez dalszej konfiguracji, uruchamiając build/build.sh z katalogu głównego kasy źródłowej.

Pobieranie źródeł i narzędzi do tworzenia

W przypadku najnowszych jąder użyj repo , aby pobrać źródła, zestaw narzędzi i skrypty kompilacji. Niektóre jądra (na przykład jądra Pixela 3) wymagają źródeł z wielu repozytoriów Git, podczas gdy inne (na przykład zwykłe jądra) wymagają tylko jednego źródła. Korzystanie z metody repo zapewnia poprawną konfigurację katalogu źródłowego.

Pobierz źródła dla odpowiedniego oddziału:

mkdir android-kernel && cd android-kernel
repo init -u https://android.googlesource.com/kernel/manifest -b BRANCH
repo sync

Aby zapoznać się z listą gałęzi repo ( BRANCH ), których można użyć z poprzednim poleceniem `repo init`, zobacz Gałęzie jądra i ich systemy kompilacji .

Aby uzyskać szczegółowe informacje na temat pobierania i kompilowania jąder dla urządzeń Pixel, zobacz Tworzenie jąder Pixel .

Budowa jądra

Budowanie z Bazelem (Kleafem)

W Androidzie 13 wprowadzono budowanie jąder za pomocą Bazela .

Aby zbudować jądro GKI dla architektury aarch64, sprawdź gałąź Android Common Kernel nie wcześniejszą niż Android 13, a następnie uruchom następującą komendę:

tools/bazel build //common:kernel_aarch64_dist

Aby utworzyć dystrybucję, uruchom:

tools/bazel run //common:kernel_aarch64_dist -- --dist_dir=$DIST_DIR

Następnie plik binarny jądra, moduły i odpowiadające im obrazy znajdują się w katalogu $DIST_DIR . Jeśli --dist_dir nie jest określona, ​​zobacz dane wyjściowe polecenia, aby poznać lokalizację artefaktów. Szczegółowe informacje można znaleźć w dokumentacji AOSP .

Budowanie za pomocą build.sh (starsza wersja)

W przypadku oddziałów z systemem Android 12 lub starszym LUB oddziałów bez Kleafa:

build/build.sh

Plik binarny jądra, moduły i odpowiadający im obraz znajdują się w katalogu out/ BRANCH /dist .

Tworzenie modułów dostawcy dla urządzenia wirtualnego

W Androidzie 13 wprowadzono budowanie jąder za pomocą Bazela (Kleaf), zastępując build.sh .

Aby zbudować moduły virtual_device , uruchom:

tools/bazel build //common-modules/virtual-device:virtual_device_x86_64_dist

Aby utworzyć dystrybucję, uruchom:

tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist -- --dist_dir=$DIST_DIR

Więcej szczegółów na temat budowania jądra Androida za pomocą Bazela znajdziesz w artykule. Kleaf — Budowanie jądra Androida za pomocą Bazela .

Aby uzyskać szczegółowe informacje na temat obsługi Kleafa dla poszczególnych architektur, zobacz Wsparcie Kleafa dla urządzeń i jąder .

Tworzenie modułów dostawcy dla urządzenia wirtualnego za pomocą build.sh (starsza wersja)

W Androidzie 12 Mątwy i Złota Rybka są zbieżne, więc mają to samo jądro: virtual_device . Aby zbudować moduły tego jądra, użyj tej konfiguracji kompilacji:

BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 build/build.sh

W systemie Android 11 wprowadzono GKI , które dzieli jądro na obraz jądra utrzymywany przez Google i moduły obsługiwane przez dostawcę, które są budowane osobno.

Ten przykład pokazuje konfigurację obrazu jądra:

BUILD_CONFIG=common/build.config.gki.x86_64 build/build.sh

Poniższy przykład pokazuje konfigurację modułu (mątwa i emulator):

BUILD_CONFIG=common-modules/virtual-device/build.config.cuttlefish.x86_64 build/build.sh

Uruchamianie jądra

Istnieje wiele sposobów uruchomienia niestandardowego jądra. Poniżej przedstawiono znane sposoby odpowiednie dla różnych scenariuszy rozwoju.

Osadzanie w kompilacji obrazu Androida

Skopiuj plik Image.lz4-dtb do odpowiedniej lokalizacji binarnej jądra w drzewie AOSP i odbuduj obraz rozruchowy.

Alternatywnie zdefiniuj zmienną TARGET_PREBUILT_KERNEL podczas korzystania z make bootimage (lub dowolnego innego wiersza poleceń make , który tworzy obraz startowy). Ta zmienna jest obsługiwana przez wszystkie urządzenia, ponieważ jest skonfigurowana w device/common/populate-new-device.sh . Na przykład:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Flashowanie i uruchamianie jądra za pomocą fastboot

Najnowsze urządzenia mają rozszerzenie programu ładującego, które usprawnia proces generowania i uruchamiania obrazu rozruchowego.

Aby uruchomić jądro bez flashowania:

adb reboot bootloader
fastboot boot Image.lz4-dtb

Korzystając z tej metody, jądro w rzeczywistości nie jest flashowane i nie będzie zachowywane po ponownym uruchomieniu.

Uruchamianie jądra na mątwie

Możesz uruchamiać jądra w wybranej architekturze na urządzeniach mątwy .

Aby uruchomić urządzenie mątwy z określonym zestawem artefaktów jądra , uruchom komendę cvd start z docelowymi artefaktami jądra jako parametrami. Poniższe przykładowe polecenie wykorzystuje artefakty jądra dla celu arm64 z manifestu jądra common-android14-6.1 .

cvd start \
    -kernel_path=/$PATH/$TO/common-android14-6.1/out/android14-6.1/dist/Image \
    -initramfs_path=/$PATH/$TO/common-android14-6.1/out/android14-6.1/dist/initramfs.img

Aby uzyskać więcej informacji, zobacz Tworzenie jądra na mątwie .

Dostosowywanie kompilacji jądra

Aby dostosować kompilacje jądra do kompilacji Kleafa, zobacz dokumentację Kleafa .

Dostosowywanie kompilacji jądra za pomocą build.sh (starsza wersja)

W przypadku build/build.sh na proces i wynik kompilacji mogą wpływać zmienne środowiskowe. Większość z nich jest opcjonalna i każda gałąź jądra powinna mieć odpowiednią domyślną konfigurację. Tutaj wymieniono najczęściej używane. Pełną (i aktualną) listę można znaleźć w build/build.sh .

Zmienna środowiskowa Opis Przykład
BUILD_CONFIG Kompiluj plik konfiguracyjny, z którego inicjujesz środowisko kompilacji. Lokalizacja musi być zdefiniowana względem katalogu głównego Repo. Domyślnie jest to build.config .
Obowiązkowe dla popularnych jąder.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Zastąp kompilator, który ma być używany. Wraca do domyślnego kompilatora zdefiniowanego przez build.config . CC=clang
DIST_DIR Podstawowy katalog wyjściowy dla dystrybucji jądra. DIST_DIR=/path/to/my/dist
OUT_DIR Podstawowy katalog wyjściowy dla kompilacji jądra. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG Pomiń make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER Pomiń make mrproper SKIP_MRPROPER=1

Niestandardowa konfiguracja jądra dla kompilacji lokalnych

W Androidzie 14 i nowszych możesz używać fragmentów defconfig do dostosowywania konfiguracji jądra. zobacz dokumentację Kleafa na temat fragmentów defconfig .

Niestandardowa konfiguracja jądra dla kompilacji lokalnych z konfiguracjami kompilacji (starsza wersja)

W systemie Android 13 i starszych zobacz poniższe informacje.

Jeśli musisz regularnie zmieniać opcję konfiguracji jądra, na przykład podczas pracy nad funkcją, lub jeśli potrzebujesz opcji do ustawienia w celach programistycznych, możesz osiągnąć tę elastyczność, zachowując lokalną modyfikację lub kopię konfiguracji kompilacji.

Ustaw zmienną POST_DEFCONFIG_CMDS na instrukcję, która będzie oceniana zaraz po wykonaniu zwykłego kroku make defconfig . Ponieważ pliki build.config są pobierane ze środowiska kompilacji, funkcje zdefiniowane w build.config można wywoływać w ramach poleceń post-defconfig.

Typowym przykładem jest wyłączenie optymalizacji czasu łącza (LTO) dla jąder crosshatch podczas programowania. Chociaż LTO jest korzystne dla wydanych jąder, obciążenie w czasie kompilacji może być znaczące. Poniższy fragment dodany do lokalnego build.config trwale wyłącza LTO podczas korzystania z build/build.sh .

POST_DEFCONFIG_CMDS="check_defconfig && update_debug_config"
function update_debug_config() {
    ${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config \
         -d LTO \
         -d LTO_CLANG \
         -d CFI \
         -d CFI_PERMISSIVE \
         -d CFI_CLANG
    (cd ${OUT_DIR} && \
     make O=${OUT_DIR} $archsubarch CC=${CC} CROSS_COMPILE=${CROSS_COMPILE} olddefconfig)
}

Identyfikacja wersji jądra

Właściwą wersję do zbudowania można zidentyfikować na podstawie dwóch źródeł: drzewa AOSP i obrazu systemu.

Wersja jądra z drzewa AOSP

Drzewo AOSP zawiera prekompilowane wersje jądra. Dziennik git ujawnia poprawną wersję jako część komunikatu zatwierdzenia:

cd $AOSP/device/VENDOR/NAME
git log --max-count=1

Jeśli wersja jądra nie jest wymieniona w dzienniku git, uzyskaj ją z obrazu systemu, jak opisano poniżej.

Wersja jądra z obrazu systemu

Aby określić wersję jądra używaną w obrazie systemu, uruchom następującą komendę w stosunku do pliku jądra:

file kernel

W przypadku plików Image.lz4-dtb uruchom:

grep -a 'Linux version' Image.lz4-dtb

Tworzenie obrazu rozruchowego

Możliwe jest zbudowanie obrazu rozruchowego przy użyciu środowiska kompilacji jądra.

Tworzenie obrazu rozruchowego dla urządzeń za pomocą init_boot

W przypadku urządzeń z partycją init_boot obraz rozruchowy jest budowany wraz z jądrem. Obraz initramfs nie jest osadzony w obrazie startowym.

Na przykład za pomocą Kleafa możesz zbudować obraz rozruchowy GKI za pomocą:

tools/bazel run //common:kernel_aarch64_dist -- --dist_dir=$DIST_DIR

Za pomocą build/build.sh (legacy) możesz zbudować obraz rozruchowy GKI za pomocą:

BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

Obraz rozruchowy GKI znajduje się w $DIST_DIR .

Tworzenie obrazu rozruchowego dla urządzeń bez init_boot (starsza wersja)

W przypadku urządzeń bez partycji init_boot potrzebny jest plik binarny ramdysku, który można uzyskać, pobierając obraz rozruchowy GKI i rozpakowując go. Każdy obraz rozruchowy GKI z powiązanej wersji Androida będzie działał.

tools/mkbootimg/unpack_bootimg.py --boot_img=boot-5.4-gz.img
mv $KERNEL_ROOT/out/ramdisk gki-ramdisk.lz4

Folder docelowy to katalog najwyższego poziomu drzewa jądra (bieżący katalog roboczy).

Jeśli programujesz przy użyciu głównego AOSP, możesz zamiast tego pobrać artefakt kompilacji ramdisk-recovery.img z kompilacji aosp_arm64 na ci.android.com i użyć go jako pliku binarnego ramdysku.

Kiedy masz plik binarny ramdysku i skopiowałeś go do gki-ramdisk.lz4 w katalogu głównym kompilacji jądra, możesz wygenerować obraz rozruchowy, wykonując:

BUILD_BOOT_IMG=1 SKIP_VENDOR_BOOT=1 KERNEL_BINARY=Image GKI_RAMDISK_PREBUILT_BINARY=gki-ramdisk.lz4 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

Jeśli pracujesz z architekturą opartą na x86, zamień Image na bzImage i aarch64 na x86_64 :

BUILD_BOOT_IMG=1 SKIP_VENDOR_BOOT=1 KERNEL_BINARY=bzImage GKI_RAMDISK_PREBUILT_BINARY=gki-ramdisk.lz4 BUILD_CONFIG=common/build.config.gki.x86_64 build/build.sh

Plik ten znajduje się w katalogu artefaktów $KERNEL_ROOT/out/$KERNEL_VERSION/dist .

Obraz rozruchowy znajduje się w out/<kernel branch>/dist/boot.img .