Kompilowanie jąder

Na tej stronie znajdziesz szczegółowe informacje o procesie tworzenia niestandardowych jąder na urządzenia z Androidem. Te instrukcje przeprowadzą Cię przez proces wybierania odpowiednich źródeł, kompilowania jądra i osadzania wyników w obrazie systemu utworzonym na podstawie projektu Android Open Source (AOSP).

Najnowsze źródła jądra możesz pobrać za pomocą Repo. Aby je skompilować bez dalszej konfiguracji, uruchom build/build.sh w katalogu głównym źródła.

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

W przypadku najnowszych jąder użyj repo, aby pobrać źródła, zestaw narzędzi i skrypty kompilacji. Niektóre jądra (np. jądra Pixela 3) wymagają źródeł z kilku repozytoriów Git, a inne (np. wspólne jądra) wymagają tylko jednego źródła. Korzystanie z metody repo zapewnia prawidłową konfigurację katalogu źródeł.

Pobierz źródła dla odpowiedniej gałęzi:

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

Listę gałęzi repozytorium (BRANCH), które można używać z poprzednim poleceniem `repo init`, znajdziesz w sekcji Gałęzie jądra i ich systemy kompilacji.

Szczegółowe informacje o pobieraniu i kompilowaniu jąder na urządzeniach Pixel znajdziesz w artykule Kompilowanie jąder Pixel.

Skompilowanie jądra

Kompilowanie za pomocą Bazel (Kleaf)

Android 13 wprowadził kompilowanie jąder za pomocą Bazel.

Aby utworzyć dystrybucję jądra GKI dla architektury aarch64, pobierz gałąź wspólnego jądra Androida, która nie jest starsza niż Android 13, a potem uruchom to polecenie:

tools/bazel run //common:kernel_aarch64_dist [-- --destdir=$DIST_DIR]

Następnie binarny jądro, moduły i odpowiednie obrazy znajdują się w katalogu $DIST_DIR. Jeśli parametr --destdir nie jest określony, informacje o lokalizacji artefaktów znajdziesz w wyjściu tego polecenia. Szczegółowe informacje znajdziesz w dokumentacji AOSP.

Kompilowanie za pomocą build.sh (starsza wersja)

W przypadku gałęzi na Androidzie 12 lub starszych LUB gałęzi bez Kleaf:

build/build.sh

Plik binarny jądra, moduły i odpowiednie obrazy znajdują się w katalogu out/BRANCH/dist.

Kompilowanie modułów dostawcy na potrzeby urządzenia wirtualnego

W Androidzie 13 wprowadzono jądra budowania: Bazel (Kleaf) zastąpił build.sh.

Aby utworzyć dystrybucję dla modułów usługi virtual_device, uruchom:

tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist [-- --destdir=$DIST_DIR]

Więcej informacji o tworzeniu jąder Androida za pomocą usługi Bazel znajdziesz tutaj. Kleaf – tworzenie jąder Androida za pomocą Bazel

Szczegółowe informacje o obsługiwanych przez Kleaf architekturach znajdziesz w artykule Obsługa Kleaf w przypadku urządzeń i jąder.

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

W Androidzie 12 Mątwa i Goldfish są z sobą zbliżone, więc mają ten sam jądro: virtual_device. Aby skompilować moduły jądra, użyj tej konfiguracji kompilacji:

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

Android 11 wprowadził GKI, który dzieli jądro na obraz jądra obsługiwany przez Google i moduły obsługiwane przez producenta, które są kompilowane osobno.

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

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

Ten przykład pokazuje konfigurację modułu (Cuttlefish i Emulator):

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

Uruchamianie jądra

Istnieje kilka sposobów uruchamiania niestandardowego jądra. Poniżej znajdziesz znane metody odpowiednie do różnych scenariuszy programistycznych.

Umieszczenie w kompilacji obrazu Androida

Skopiuj Image.lz4-dtb do odpowiedniej lokalizacji binarnej jądra w drzewie AOSP i utwórz ponownie obraz rozruchowy.

Możesz też zdefiniować zmienną TARGET_PREBUILT_KERNEL, używając polecenia make bootimage (lub dowolnego innego polecenia wiersza poleceń make, które tworzy obraz rozruchowy). Ta zmienna jest obsługiwana na wszystkich urządzeniach, ponieważ jest konfigurowana za pomocą device/common/populate-new-device.sh. Na przykład:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

flash i uruchamianie jąder w trybie szybkiego rozruchu;

Najnowsze urządzenia mają rozszerzenie programu rozruchowego, które upraszcza proces generowania i uruchamiania obrazu rozruchowego.

Aby uruchomić jądro bez flashowania:

adb reboot bootloader
fastboot boot Image.lz4-dtb

W przypadku tej metody nie następuje flashowanie jądra i nie będzie ono zachowane po ponownym uruchomieniu.

Uruchamianie jąder w Cuttlefish

Na urządzeniach Cuttlefish możesz uruchamiać jądra w wybranej architekturze.

Aby uruchomić urządzenie Cuttlefish z określonym zestawem artefaktów jądra, uruchom polecenie cvd create, podając jako parametry docelowe artefakty jądra. W tym przykładowym poleceniu użyto artefaktów jądra dla celu arm64 z manifestu jądra common-android14-6.1.

cvd create \
    -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

Więcej informacji znajdziesz w artykule Tworzenie jąder w Cuttlefish.

Dostosuj kompilację jądra

Aby dostosować wersje jądra dla wersji Kleaf, zapoznaj się z dokumentacją Kleaf.

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

W przypadku build/build.sh zmienne środowiskowe mogą mieć wpływ na proces kompilacji i jego wynik. Większość z nich jest opcjonalna, a każda gałąź jądra powinna mieć prawidłową konfigurację domyślną. Tutaj znajdziesz najczęściej używane z nich. Pełną (aktualną) listę znajdziesz tutaj: build/build.sh.

Zmienna środowiskowa Opis Przykład
BUILD_CONFIG Plik konfiguracji kompilacji z miejsca, w którym inicjujesz środowisko kompilacji. Lokalizacja musi być zdefiniowana w odniesieniu do katalogu głównego repozytorium. Domyślna wartość to build.config.
Wymagany w przypadku wspólnych jąder.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Kompilator zastępczy do użycia. W przeciwnym razie użyje domyślnego kompilatora określonego przez zmienną 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 w przypadku kompilacji lokalnych

W Androidzie 14 i nowszych możesz używać fragmentów defconfig do dostosowywania konfiguracji jądra. Więcej informacji znajdziesz w dokumentacji Kleaf na temat fragmentów defconfig.

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

W przypadku Androida 13 i starszych:

Jeśli musisz regularnie przełączać opcję konfiguracji jądra, na przykład podczas pracy nad funkcją, lub jeśli musisz ustawić opcję na potrzeby rozwoju, możesz uzyskać tę elastyczność, zachowując lokalną modyfikację lub kopię konfiguracji kompilacji.

Ustaw zmienną POST_DEFCONFIG_CMDS na instrukcję, która jest oceniana bezpośrednio po zakończeniu zwykłego kroku make defconfig. Ponieważ pliki build.config są pobierane do środowiska kompilacji, funkcje zdefiniowane w pliku build.config mogą być wywoływane w ramach poleceń po konfiguracji definicji.

Typowym przykładem jest wyłączenie optymalizacji czasu łączenia (LTO) dla jąder krzyżujących się podczas rozwoju. Chociaż LTO jest korzystne w przypadku opublikowanych jąder, nakład pracy w czasie kompilacji może być znaczny. Ten fragment kodu dodany do lokalnego pliku build.config wyłącza LTO na stałe podczas korzystania z pliku 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)
}

Identyfikowanie wersji jądra

Prawidłową wersję do skompilowania możesz określić na podstawie 2 źródeł: drzewa AOSP i obrazu systemu.

Wersja jądra z drzewa AOSP

Drzewo AOSP zawiera wstępnie utworzone wersje jądra. Log gita pokazuje poprawną wersję w ramach wiadomości o zmianie:

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

Jeśli wersja jądra nie jest wymieniona w logu git, pobierz ją z obrazu systemu w sposób opisany poniżej.

Wersja jądra z obrazu systemu

Aby określić wersję jądra używaną w pliku obrazu systemu, uruchom to polecenie w pliku jądra:

file kernel

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

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

Tworzenie obrazu rozruchowego

Obraz rozruchowy można skompilować za pomocą środowiska kompilacji jądra.

Tworzenie obrazu rozruchowego dla urządzeń z init_boot

W przypadku urządzeń z partycją init_boot obraz rozruchu jest tworzony razem z jądrem. Obraz initramfs nie jest osadzony w obrazie rozruchowym.

Na przykład w przypadku Kleaf możesz skompilować obraz rozruchowy GKI za pomocą:

tools/bazel run //common:kernel_aarch64_dist [-- --destdir=$DIST_DIR]

W przypadku build/build.sh (starsza wersja) możesz utworzyć obraz startowy GKI za pomocą:

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

Obraz rozruchowy GKI znajduje się w regionie $DIST_DIR.

Tworzenie obrazu rozruchowego na urządzeniach bez init_boot (wersja starsza)

W przypadku urządzeń bez partycji init_boot musisz mieć plik binarny ramdisk, który możesz pobrać, pobierając obraz rozruchowy GKI i rozpakowując go. Dobrze sprawdzi się dowolny obraz GKI z powiązanej wersji Androida.

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

Folder docelowy to katalog główny drzewa jądra (bieżący katalog roboczy).

Jeśli pracujesz z wersją główną AOSP, możesz zamiast tego pobrać artefakt kompilacji ramdisk-recovery.img z kompilacji aosp_arm64 na stronie ci.android.com i użyć go jako binarnego pliku ramdisk.

Gdy masz plik binarny dysku RAM i skopiujesz go do katalogu gki-ramdisk.lz4 w katalogu głównym kompilacji jądra, możesz wygenerować obraz rozruchowy, wykonując polecenie:

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ą x86, zastąp Image wartością bzImage, a aarch64 wartością 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

Ten plik znajduje się w katalogu artefaktów $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

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