פיתוח ליבות

בדף הזה מוסבר איך ליצור ליבות בהתאמה אישית למכשירי Android. בהוראות האלה מוסבר איך לבחור את המקורות המתאימים, ליצור את ליבת המערכת ולהטמיע את התוצאות בקובץ אימג' של המערכת שנבנה מתוך פרויקט Android בקוד פתוח (AOSP).

הורדת מקורות וכלים לבנייה

בליבות עדכניות, משתמשים ב-repo כדי להוריד את המקורות, את ערכת הכלים ואת סקריפטים הבנייה. חלק מהקרנלים (לדוגמה, קרנלים של Pixel 3) דורשים מקורות מכמה מאגרי git, בעוד שאחרים (לדוגמה, קרנלים נפוצים) דורשים רק מקור אחד. השימוש בגישה repo מבטיח הגדרה נכונה של ספריית המקור.

מורידים את המקורות של הענף המתאים:

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

רשימה של ענפים במאגר (BRANCH) שאפשר להשתמש בהם עם הפקודה הקודמת `repo init` זמינה במאמר ענפי ליבה ומערכות הבנייה שלהם.

פרטים על הורדה והידור של ליבות למכשירי Pixel זמינים במאמר בנושא בניית ליבות Pixel.

הרכבת הליבה

Build with Bazel (Kleaf)

ב-Android 13 הוצגה האפשרות ליצור ליבות באמצעות Bazel.

כדי ליצור הפצה של ליבת GKI לארכיטקטורת aarch64, צריך לבדוק ענף של ליבת Android Common Kernel מגרסה Android 13 ואילך, ואז להריץ את הפקודה הבאה:

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

לאחר מכן, הקובץ הבינארי של הליבה, המודולים והתמונות התואמות ממוקמים בספרייה $DIST_DIR. אם לא מציינים את --destdir, אפשר לראות את הפלט של הפקודה כדי לדעת איפה נמצאים פריטי המידע שנוצרו בתהליך הפיתוח (Artifact). פרטים נוספים זמינים במסמכי התיעוד בנושא AOSP.

איך בונים באמצעות build.sh (מאמר שמתייחס לגרסה קודמת)

להסתעפויות ב-Android 12 ומטה, או להסתעפויות ללא Kleaf:

build/build.sh

הקובץ הבינארי של הליבה, המודולים והתמונה המתאימה ממוקמים בספרייה out/BRANCH/dist.

יצירת מודולים של ספקים למכשיר הווירטואלי

ב-Android 13 הוצגה האפשרות לבנות ליבות באמצעות Bazel‏ (Kleaf), במקום build.sh.

כדי ליצור הפצה למודולים של virtual_device, מריצים את הפקודה:

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

לפרטים נוספים על בניית ליבות של Android באמצעות Bazel, אפשר לעיין במאמר. ‫Kleaf – בניית ליבות של Android באמצעות Bazel.

פרטים על תמיכת Kleaf בארכיטקטורות ספציפיות זמינים במאמר בנושא תמיכת Kleaf במכשירים ובליבות.

יצירת מודולים של הספק למכשיר הווירטואלי באמצעות build.sh (גרסה קודמת)

ב-Android 12,‏ Cuttlefish ו-Goldfish מתאחדים, כך שהם חולקים את אותו ליבה: virtual_device. כדי ליצור את המודולים של ליבת המערכת, משתמשים בהגדרת הבנייה הזו:

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

ב-Android 11 הוצג GKI, שמפריד את הליבה לתמונת ליבה שמתוחזקת על ידי Google ולמודולים שמתוחזקים על ידי הספק, שנבנים בנפרד.

בדוגמה הזו מוצגת הגדרה של תמונת ליבה:

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

בדוגמה הזו מוצגת הגדרת מודול (Cuttlefish ו-Emulator):

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

הרצת ליבת הקרנל

יש כמה דרכים להפעיל ליבת מערכת בהתאמה אישית. בהמשך מפורטות דרכים מוכרות שמתאימות לתרחישי פיתוח שונים.

הטמעה ב-build של תמונת Android

מעתיקים את Image.lz4-dtb למיקום המתאים של הקובץ הבינארי של הליבה בעץ AOSP, ובונים מחדש את תמונת האתחול.

אפשר גם להגדיר את המשתנה TARGET_PREBUILT_KERNEL בזמן השימוש בפקודה make bootimage (או בכל פקודה אחרת בשורת הפקודה make שיוצרת תמונת אתחול). המשתנה הזה נתמך בכל המכשירים כי הוא מוגדר דרך device/common/populate-new-device.sh. לדוגמה:

export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb

הפעלה של ליבות (kernel) וטעינה שלהן באמצעות fastboot

ברוב המכשירים החדשים יש תוסף לתוכנת האתחול שמייעל את התהליך של יצירת תמונת אתחול והפעלת אתחול.

כדי להפעיל את הליבה בלי להפעיל את ה-flash:

adb reboot bootloader
fastboot boot Image.lz4-dtb

בשיטה הזו, הליבה לא באמת מוצגת, והיא לא תישמר אחרי הפעלה מחדש.

הרצת ליבות ב-Cuttlefish

אתם יכולים להריץ ליבות בארכיטקטורה שתבחרו במכשירי Cuttlefish.

כדי להפעיל מכשיר Cuttlefish עם קבוצה מסוימת של ארטיפקטים של ליבת המערכת, מריצים את הפקודה cvd create עם הארטיפקטים של ליבת המערכת הרלוונטיים כפרמטרים. בדוגמה הבאה של פקודה נעשה שימוש בארטיפקטים של ליבת מערכת ההפעלה עבור יעד arm64 ממניפסט הליבה 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

מידע נוסף זמין במאמר בנושא פיתוח ליבות ב-Cuttlefish.

התאמה אישית של ה-build של ליבת המערכת

כדי להתאים אישית את הגרסאות של ליבת ה-Kleaf, אפשר לעיין במסמכי התיעוד של Kleaf.

התאמה אישית של ה-build של הליבה באמצעות build.sh (גרסה קודמת)

ב-build/build.sh, משתני סביבה יכולים להשפיע על תהליך ה-build ועל התוצאה שלו. רובם אופציונליים, ולכל ענף של ליבת המערכת צריכה להיות הגדרת ברירת מחדל מתאימה. ריכזנו כאן את קיצורי הדרך הנפוצים ביותר. רשימה מלאה (ומעודכנת) זמינה build/build.sh.

משתנה סביבה תיאור דוגמה
BUILD_CONFIG קובץ תצורת ה-build שממנו מאתחלים את סביבת ה-build. המיקום צריך להיות מוגדר ביחס לספריית הבסיס של Repo. ברירת המחדל היא build.config.
חובה לליבות נפוצות.
BUILD_CONFIG=common/build.config.gki.aarch64
CC שינוי ההגדרות של הקומפיילר שבו רוצים להשתמש. חוזר לקומפיילר שמוגדר כברירת מחדל על ידי build.config. CC=clang
DIST_DIR ספריית הפלט הבסיסית להפצת הליבה. DIST_DIR=/path/to/my/dist
OUT_DIR ספריית הפלט הבסיסית של בניית הליבה. OUT_DIR=/path/to/my/out
SKIP_DEFCONFIG דילוג make defconfig SKIP_DEFCONFIG=1
SKIP_MRPROPER דילוג make mrproper SKIP_MRPROPER=1

הגדרת ליבה בהתאמה אישית לגרסאות build מקומיות

ב-Android מגרסה 14 ואילך, אפשר להשתמש בקטעי defconfig כדי להתאים אישית את הגדרות הליבה. מידע נוסף זמין במסמכי Kleaf בנושא קטעי defconfig.

הגדרת ליבה בהתאמה אישית לגרסאות build מקומיות באמצעות הגדרות build (מאמר שמתייחס לגרסה קודמת)

ב-Android מגרסה 13 ומטה, אפשר לראות את ההוראות הבאות.

אם אתם צריכים לשנות באופן קבוע אפשרות הגדרה של ליבת מערכת ההפעלה, למשל כשאתם עובדים על תכונה, או אם אתם צריכים להגדיר אפשרות למטרות פיתוח, אתם יכולים לשמור על הגמישות הזו על ידי שמירה של שינוי מקומי או עותק של הגדרות ה-build.

מגדירים את המשתנה POST_DEFCONFIG_CMDS להוראה שמוערכת מיד אחרי השלמת השלב הרגיל make defconfig. מכיוון שהקבצים build.config נכללים בסביבת הבנייה, אפשר לקרוא לפונקציות שמוגדרות ב-build.config כחלק מהפקודות של post-defconfig.

דוגמה נפוצה היא השבתה של אופטימיזציה בזמן הקישור (LTO) עבור ליבות של crosshatch במהלך הפיתוח. למרות שה-LTO מועיל לליבות שפורסמו, התקורה בזמן הבנייה יכולה להיות משמעותית. הקטע הבא נוסף ל-build.config המקומי כדי להשבית את LTO באופן קבוע כשמשתמשים ב-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)
}

זיהוי גרסאות ליבה

אפשר לזהות את הגרסה הנכונה לבנייה משני מקורות: עץ ה-AOSP וקובץ האימג' של המערכת.

גרסת ליבה מעץ AOSP

עץ ה-AOSP מכיל גרסאות ליבה מוכנות מראש. היומן של git מציג את הגרסה הנכונה כחלק מהודעת הקומיט:

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

אם גרסת הליבה לא מופיעה ביומן ה-git, צריך לקבל אותה מתמונת המערכת, כמו שמתואר בהמשך.

גרסת ליבה מתמונת מערכת

כדי לקבוע את גרסת הליבה שבה נעשה שימוש בקובץ אימג' של מערכת, מריצים את הפקודה הבאה על קובץ הליבה:

file kernel

לקובצי Image.lz4-dtb, מריצים את הפקודה:

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

יצירת קובץ אימג' לאתחול

אפשר ליצור אימג' של אתחול באמצעות סביבת ה-build של הליבה.

יצירת קובץ אימג' לאתחול למכשירים עם init_boot

במכשירים עם מחיצת init_boot, קובץ האימג' של האתחול נוצר יחד עם ליבת המערכת. התמונה initramfs לא מוטמעת בתמונת האתחול.

לדוגמה, באמצעות Kleaf, אפשר ליצור את תמונת האתחול של GKI באמצעות:

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

עם build/build.sh (גרסה קודמת), אפשר ליצור את קובץ האימג' לאתחול של GKI באמצעות:

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

קובץ האימג' לאתחול GKI נמצא ב-$DIST_DIR.

יצירת תמונת אתחול למכשירים ללא init_boot (גרסה קודמת)

במכשירים שאין בהם מחיצת init_boot, צריך קובץ בינארי של ramdisk. אפשר להשיג אותו על ידי הורדה של תמונת אתחול של GKI ופריסה שלה. כל תמונת אתחול של GKI מגרסת Android המשויכת תפעל.

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

תיקיית היעד היא הספרייה ברמה העליונה של עץ הליבה (ספריית העבודה הנוכחית).

אם אתם מפתחים באמצעות ענף הגרסה האחרון של AOSP, אתם יכולים להוריד את ramdisk-recovery.img ארטיפקט הבנייה מגרסת aosp_arm64 בכתובת ci.android.com ולהשתמש בו כקובץ הבינארי של ה-ramdisk.

אם יש לכם קובץ בינארי של ramdisk והעתקתם אותו אל gki-ramdisk.lz4 בספריית הבסיס של בניית הליבה, תוכלו ליצור תמונת אתחול על ידי הפעלת הפקודה:

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

אם אתם עובדים עם ארכיטקטורה מבוססת x86, מחליפים את Image ב-bzImage ואת aarch64 ב-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

הקובץ הזה נמצא בספריית ה-Artifacts‏: $KERNEL_ROOT/out/$KERNEL_VERSION/dist.

תמונת האתחול נמצאת ב-out/<kernel branch>/dist/boot.img.