Budowanie jąder

Ta strona szczegółowo opisuje proces tworzenia niestandardowych jąder dla urządzeń z systemem Android. Te instrukcje przeprowadzą Cię przez proces wybierania odpowiednich źródeł, budowania jądra i osadzania wyników w obrazie systemu zbudowanym z Android Open Source Project (AOSP).

Możesz uzyskać nowsze źródła jądra za pomocą 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 budowania

W przypadku najnowszych jąder użyj repo , aby pobrać źródła, łańcuch narzędzi i skrypty kompilacji. Niektóre jądra (na przykład jądra Pixel 3) wymagają źródeł z wielu repozytoriów git, podczas gdy inne (na przykład wspólne jądra) wymagają tylko jednego źródła. Korzystanie z podejścia repo zapewnia poprawną konfigurację katalogu źródłowego.

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

W poniższej tabeli wymieniono nazwy BRANCH dla jąder dostępnych za pomocą tej metody.

Urządzenie Ścieżka binarna w drzewie AOSP Oddziały repo
Pixel 7 (pantera)
Pixel 7 Pro (gepard)
urządzenie/google/pantah-kernel android-gs-pantah-5.10-android13-qpr2
Pixel 6a (bluejay) urządzenie/google/bluejay-kernel android-gs-bluejay-5.10-android13-qpr2
Pixel 6 (wilga)
Pixel 6 Pro (kruk)
device/google/raviole-kernel android-gs-raviole-5.10-android13-qpr2
Pixel 5a (barbet)
Piksel 5 (czerwonopłetwy)
Pixel 4a (5G) (jeżyna)
urządzenie/google/redbull-kernel android-msm-redbull-4.19-android13-qpr2
Pixel 4a (samosamochód) device/google/sunfish-kernel android-msm-sunfish-4.14-android13-qpr2
Piksel 4 (płomień)
Pixel 4 XL (koralowy)
device/google/coral-kernel android-msm-coral-4.14-android13
Pixel 3a (sargo)
Pixel 3a XL (bonito)
urządzenie/google/bonito-kernel android-msm-bonito-4.9-android12L
Piksel 3 (niebieska linia)
Pixel 3 XL (kreskowanie)
device/google/crosshatch-kernel android-msm-crosshatch-4.9-android12
Piksel 2 (walleye)
Pixel 2 XL (taimen)
urządzenie/google/jądro-wahoo android-msm-wahoo-4.4-android10-qpr3
Piksel (żaglica)
Pixel XL (marlin)
urządzenie/google/marlin-kernel android-msm-marlin-3.18-pie-qpr2
Hikey960 urządzenie/linaro/jądro-hikey hikey-linaro-android-4.14
hikey-linaro-android-4.19
wspólny android 12-5.4
wspólny android 13-5.10
Pies gończy x15 urządzenie/ti/beagle_x15-kernel omap-beagle-x15-android-4.14
omap-beagle-x15-android-4.19
Wspólne jądro Androida Nie dotyczy wspólny Android-4.4
wspólny Android-4.9
wspólny Android-4.14
wspólny Android-4.19
wspólny-Android-4.19-stabilny
wspólny android 11-5.4
wspólny android 12-5.4
wspólny android 12-5.10
wspólny android 13-5.10
wspólny android 13-5.15
wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida

Budowanie jądra

Następnie zbuduj jądro za pomocą tego:

build/build.sh

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

Budynek z Bazelem (Kleaf)

Android 13 wprowadził jądra do budowania z Bazel , zastępując build/build.sh .

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

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 są umieszczane w katalogu $DIST_DIR . Jeśli --dist_dir nie zostanie określony, zobacz dane wyjściowe polecenia dotyczące lokalizacji artefaktów. Aby uzyskać szczegółowe informacje, zapoznaj się z dokumentacją AOSP .

Tworzenie modułów dostawcy dla urządzenia wirtualnego

Android 11 wprowadził GKI , który dzieli jądro na obraz jądra obsługiwany przez Google i moduły obsługiwane przez dostawcę, które są budowane oddzielnie.

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 (mątwa i emulator):

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

W systemie Android 12 mątwa 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

Android 13 wprowadził jądra do budowania z Bazel (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

Aby uzyskać więcej informacji na temat budowania jądra Androida za pomocą Bazel, zobacz. Kleaf — budowanie jąder Androida za pomocą Bazel .

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

Obsługa Kleaf dla urządzeń i jąder

Poniższa tabela zawiera listę obsługi Kleaf dla poszczególnych jąder urządzeń. W przypadku niewymienionych urządzeń skontaktuj się z producentem urządzenia.

Urządzenie Oddziały repo Wsparcie Kleafa wsparcie build/build.sh
Wspólne jądro Androida
db845c
Urządzenie wirtualne (x86_64, arm64)
Urządzenie wirtualne (i686, ramię)
Rockpi4
wspólny Android-4.4
wspólny Android-4.9
wspólny Android-4.14
wspólny Android-4.19
wspólny-Android-4.19-stabilny
wspólny android 11-5.4
wspólny android 12-5.4
wspólny android 12-5.10
Wspólne jądro Androida wspólny android 13-5.10
wspólny android 13-5.15
✅ (oficjalne) 1
Wspólne jądro Androida wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida
db845c wspólny android 13-5.10
db845c wspólny android 13-5.15 ✅ (oficjalne) 1
db845c wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida
Urządzenie wirtualne (x86_64, arm64) wspólny android 13-5.10
wspólny android 13-5.15
✅ (oficjalne) 1 ⚠️ (nieobsługiwany) 2
Urządzenie wirtualne (x86_64, arm64) wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida
Urządzenie wirtualne (i686, ramię) wspólny android 13-5.10
wspólny android 13-5.15
Urządzenie wirtualne (i686, ramię) wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida
Rockpi4 wspólny android 13-5.10
wspólny android 13-5.15
Rockpi4 wspólny android 14-5.15
wspólny Android 14-6.1
wspólna główna linia Androida
Hikey960 hikey-linaro-android-4.14
hikey-linaro-android-4.19
wspólny android 12-5.4
wspólny android 13-5.10
moduł fips140 wspólny android 12-5.10
wspólny android 13-5.10
wspólny android 13-5.15
moduł fips140 wspólny android 14-5.15

1 „Oficjalny” oznacza, że ​​jest to oficjalny sposób budowania jądra, chociaż alternatywny sposób może być również użyty do zbudowania jądra.

2 „Nieobsługiwany” oznacza, że ​​budowanie jądra za pomocą tej metody powinno działać, ale metoda kompilacji nie jest stale testowana. W przyszłości może przestać się budować. Zamiast tego użyj „oficjalnego” sposobu budowania.

Uruchamianie jądra

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

Osadzanie w kompilacji obrazu systemu Android

Skopiuj 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 polecenia make , który tworzy boot image). Ta zmienna jest obsługiwana przez wszystkie urządzenia, ponieważ jest konfigurowana za pomocą device/common/populate-new-device.sh . Na przykład:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

Flashowanie i ładowanie jądra za pomocą fastboot

Większość najnowszych urządzeń ma rozszerzenie programu ładującego, aby usprawnić 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 nie jest w rzeczywistości flashowane i nie będzie się utrzymywać po ponownym uruchomieniu.

Dostosowanie kompilacji jądra

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

W przypadku build/build.sh na proces i wynik kompilacji mogą mieć wpływ zmienne środowiskowe. Większość z nich jest opcjonalna, a każda gałąź jądra powinna mieć odpowiednią domyślną konfigurację. Najczęściej używane są wymienione tutaj. Pełna (i aktualna) lista znajduje się na stronie build/build.sh .

Zmienna środowiskowa Opis Przykład
BUILD_CONFIG Zbuduj plik konfiguracyjny, z którego inicjujesz środowisko kompilacji. Lokalizacja musi być zdefiniowana względem katalogu głównego repozytorium. Domyślnie build.config .
Obowiązkowe dla wspólnych jąder.
BUILD_CONFIG=common/build.config.gki.aarch64
CC Zastąp kompilator, który ma być używany. Powraca 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

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

Ustaw zmienną POST_DEFCONFIG_CMDS na instrukcję, która jest oceniana zaraz po wykonaniu zwykłego kroku make defconfig . Ponieważ pliki build.config są pobierane do środowiska kompilacji, funkcje zdefiniowane w build.config mogą być wywoływane jako część poleceń post-defconfig.

Typowym przykładem jest wyłączenie optymalizacji czasu łącza (LTO) dla jąder krzyżowych podczas programowania. Chociaż LTO jest korzystne dla wydanych jąder, narzut w czasie kompilacji może być znaczny. Poniższy fragment kodu dodany do lokalnego build.config trwale wyłącza LTO podczas używania 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ć z dwóch źródeł: drzewa AOSP i obrazu systemu.

Wersja jądra z drzewa AOSP

Drzewo AOSP zawiera gotowe 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ę względem 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 tworzony wraz z jądrem. Obraz initramfs nie jest osadzony w obrazie rozruchowym.

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 możesz zbudować obraz rozruchowy GKI za pomocą:

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

Obraz startowy GKI znajduje się w $DIST_DIR .

Budowanie obrazu rozruchowego dla urządzeń bez init_boot

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 pracujesz z AOSP master, 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.

Gdy 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 architekturze 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

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

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