פתח קוד ליבה עבור GKI

תמונת הליבה הגנרית (GKI) מפחיתה את פיצול הליבה על ידי יישור הדוק עם ליבת לינוקס במעלה הזרם. עם זאת, ישנן סיבות תקפות לכך שלא ניתן לקבל טלאים מסוימים במעלה הזרם, וישנם לוחות זמנים של מוצרים שחייבים לעמוד בהם, כך שחלק מהטלאים נשמרים במקורות Android Common Kernel (ACK) שמהם בנוי ה-GKI.

מפתחים חייבים להגיש שינויי קוד במעלה הזרם באמצעות רשימת התפוצה של ליבת לינוקס (LKML) כבחירה הראשונה, ולהגיש שינויי קוד לסניף ACK android-mainline רק כאשר יש סיבה חזקה לכך שהמקדם אינו בר קיימא. דוגמאות לסיבות תקפות וכיצד לטפל בהן מפורטות כדלקמן.

  • התיקון הוגש ל-LKML, אך לא התקבל בזמן להוצאת המוצר. כדי לטפל בתיקון זה:

    • ספק הוכחה לכך שהתיקון הוגש ל-LKML והערות שהתקבלו עבור התיקון, או מועד משוער שבו התיקון יוגש במעלה הזרם.
    • החליטו על דרך פעולה להנחית את התיקון ב-ACK, לאשר אותו במעלה הזרם, ואז להוציא אותו מ-ACK כאשר הגרסה הסופית במעלה הזרם תתמזג לתוך ACK.
  • התיקון מגדיר את EXPORT_SYMBOLS_GPL() עבור מודול ספק, אך לא ניתן היה להגיש במעלה הזרם כי אין מודולים בתוך העץ שצורכים את הסמל הזה. כדי לטפל בתיקון זה, ספק פרטים מדוע לא ניתן להגיש את המודול שלך במעלה הזרם ואת החלופות ששקלת לפני הגשת בקשה זו.

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

  • לא ניתן לקבל את התיקון במעלה הזרם כי... <הכנס סיבה כאן> . כדי לטפל בתיקון הזה, פנו לצוות ליבת אנדרואיד ועבדו איתנו על אפשרויות לשחזור התיקון כך שניתן יהיה לשלוח אותו לבדיקה ולקבלו במעלה הזרם.

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

דרישות תיקון

התיקונים חייבים להתאים לתקני קידוד ליבת לינוקס המתוארים בעץ המקור של לינוקס , בין אם הם נשלחים במעלה הזרם או ל-ACK. הסקריפט scripts/checkpatch.pl מופעל כחלק מבדיקת Gerrit presubmit, אז הפעל אותו מראש כדי לוודא שהוא עובר. כדי להפעיל את הסקריפט של checkpatch עם אותה תצורה כמו בדיקת Presubmit, השתמש ב //build/kernel/static_analysis:checkpatch_presubmit . לפרטים, ראה build/kernel/kleaf/docs/checkpatch.md .

תיקוני ACK

תיקונים הנשלחים ל-ACK חייבים להתאים לתקני קידוד ליבת לינוקס ולהנחיות התרומה . עליך לכלול תג Change-Id בהודעת ה-commit; אם אתה שולח את התיקון למספר סניפים (לדוגמה, android-mainline ו- android12-5.4 ), עליך להשתמש באותו Change-Id עבור כל המופעים של התיקון.

שלח תחילה תיקונים ל-LKML לסקירה במעלה הזרם. אם התיקון הוא:

  • מקובל במעלה הזרם, הוא מוזג אוטומטית ל- android-mainline .
  • לא מתקבל במעלה הזרם, שלח אותו ל- android-mainline עם הפניה להגשה במעלה הזרם או הסבר מדוע הוא לא נשלח ל-LKML.

לאחר שתיקון יתקבל במעלה הזרם או ב- android-mainline , ניתן להעביר אותו בחזרה ל-ACK המתאים מבוסס LTS (כגון android12-5.4 ו- android11-5.4 עבור תיקונים שמתקנים קוד ספציפי לאנדרואיד). הגשה ל- android-mainline מאפשרת בדיקה עם מועמדים חדשים לשחרור במעלה הזרם ומבטיחה שהתיקון נמצא ב-ACK מבוסס LTS הבא. חריגים כוללים מקרים שבהם תיקון במעלה הזרם מועבר לאחור ל- android12-5.4 (מכיוון שהתיקון כבר קיים ב- android-mainline ).

טלאים במעלה הזרם

כפי שצוין בהנחיות התרומה , תיקונים במעלה הזרם המיועדים לגרעיני ACK נכללים בקבוצות הבאות (רשומות לפי סדר הסבירות להתקבל).

  • UPSTREAM: - תיקונים שנבחרו מ'android-mainline' צפויים להתקבל ל-ACK אם יש מקרה שימוש סביר.
  • BACKPORT: - תיקונים ממעלה הזרם שאינם בולטים בצורה נקייה וזקוקים לשינוי עשויים גם להתקבל אם יש מקרה שימוש סביר.
  • FROMGIT: - תיקונים שנבחרו מסניף מתחזק לקראת הגשה ל-Linux mainline עשויים להתקבל אם יש מועד אחרון קרוב. אלה חייבים להיות מוצדקים הן בתוכן והן בלוח הזמנים.
  • FROMLIST: - תיקונים שנשלחו ל-LKML אך לא התקבלו לסניף מתחזק עדיין לא צפויים להתקבל, אלא אם ההצדקה משכנעת מספיק כדי שהתיקון יתקבל בין אם הוא נוחת ב-Upstream Linux ובין אם לאו (אנו מניחים שזה לא יהיה). חייבת להיות בעיה הקשורה לתיקוני FROMLIST כדי להקל על הדיון עם צוות ליבת אנדרואיד.

תיקונים ספציפיים לאנדרואיד

אם אינך יכול לנחות את השינויים הנדרשים במעלה הזרם, תוכל לנסות לשלוח תיקונים מחוץ לעץ ל-ACK ישירות. שליחת תיקונים מחוץ לעץ דורשת שתיצור בעיה ב-IT המצטטת את התיקון והרציונל מדוע לא ניתן להגיש את התיקון במעלה הזרם (עיין ברשימה הקודמת לדוגמאות). עם זאת, ישנם כמה מקרים שבהם לא ניתן לשלוח את הקוד במעלה הזרם. מקרים אלה מכוסים כדלקמן וחייבים לציית להנחיות התרומה עבור תיקונים ספציפיים לאנדרואיד ולהיות מתויגים בקידומת ANDROID: בנושא.

שינויים ב-gki_defconfig

כל שינויי CONFIG ב- gki_defconfig חייבים להיות מיושמים גם בגרסת arm64 וגם ב-x86, אלא אם ה- CONFIG הוא ספציפי לארכיטקטורה. כדי לבקש שינוי בהגדרת CONFIG , צור בעיה ב-IT כדי לדון בשינוי. כל שינוי CONFIG שמשפיע על ממשק מודול ליבה (KMI) לאחר הקפאתו נדחה. במקרים שבהם שותפים מבקשים הגדרות סותרות עבור תצורה יחידה, אנו פותרים התנגשויות באמצעות דיון על הבאגים הקשורים.

קוד שלא קיים במעלה הזרם

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

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

מודולים מחוץ לעץ

Upstream Linux מונע באופן פעיל תמיכה בבניית מודולים מחוץ לעץ. זוהי עמדה סבירה בהתחשב בכך שמתחזקי לינוקס אינם מבטיחים לגבי מקור הליבה או תאימות בינארית ואינם רוצים לתמוך בקוד שאינו בעץ. עם זאת, ה-GKI אכן נותן ערבויות של ABI עבור מודולי ספקים, ומבטיח שממשקי KMI יהיו יציבים לכל החיים הנתמכים של ליבה. לכן, יש סוג של שינויים לתמיכה במודולים של ספקים שמקובלים עבור ACK אך אינם מקובלים עבור במעלה הזרם.

לדוגמה, שקול תיקון שמוסיף פקודות מאקרו EXPORT_SYMBOL_GPL() כאשר המודולים המשתמשים בייצוא אינם נמצאים בעץ המקור. אמנם עליך לנסות לבקש EXPORT_SYMBOL_GPL() במעלה הזרם ולספק מודול המשתמש בסמל המיוצא החדש, אך אם יש הצדקה חוקית מדוע המודול לא נשלח במעלה הזרם, תוכל להגיש את התיקון ל-ACK במקום זאת. אתה צריך לכלול את ההצדקה מדוע לא ניתן להעלות את המודול במעלה הזרם בנושא. (אל תבקש את הגרסה שאינה GPL, EXPORT_SYMBOL() .)

הגדרות נסתרות

חלק מהמודולים בתוך העץ בוחרים אוטומטית בתצורות נסתרות שלא ניתן לציין ב- gki_defconfig . לדוגמה, CONFIG_SND_SOC_TOPOLOGY נבחר באופן אוטומטי כאשר CONFIG_SND_SOC_SOF=y מוגדר. כדי להתאים לבניית מודול מחוץ לעץ, GKI כולל מנגנון להפעלת הגדרות נסתרות.

כדי לאפשר תצורה נסתרת, הוסף משפט select ב- init/Kconfig.gki כך שהיא תיבחר אוטומטית בהתבסס על תצורת ליבת CONFIG_GKI_HACKS_TO_FIX , אשר מופעלת ב- gki_defconfig . השתמש במנגנון זה רק עבור הגדרות נסתרות; אם התצורה אינה מוסתרת, יש לציין אותה ב- gki_defconfig באופן מפורש או כתלות.

מושלים נטענים

עבור מסגרות ליבה (כגון cpufreq ) התומכות במושלים הניתנים לטעינה, אתה יכול לעקוף את המושל המוגדר כברירת מחדל (כגון מושל schedutil של cpufreq . עבור מסגרות (כגון המסגרת התרמית) שאינן תומכות במושלים או מנהלי התקנים הניתנים לטעינה אך עדיין דורשות יישום ספציפי לספק, צור בעיה ב-IT והתייעץ עם צוות ליבת אנדרואיד .

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

ווי ספקים

במהדורות קודמות, אתה יכול להוסיף שינויים ספציפיים לספק ישירות לתוך ליבת הליבה. זה לא אפשרי עם GKI 2.0 מכיוון שקוד ספציפי למוצר חייב להיות מיושם במודולים ולא יתקבל בליבת הליבה במעלה הזרם או ב-ACK. כדי לאפשר תכונות עם ערך מוסף ששותפים מסתמכים עליהן עם השפעה מינימלית על קוד ליבת הליבה, GKI מקבל הוקס של ספקים המאפשרים להפעיל מודולים מקוד הליבה. בנוסף, ניתן לרפד מבני נתונים מרכזיים בשדות נתוני ספקים הזמינים לאחסון נתונים ספציפיים לספק כדי ליישם תכונות אלו.

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

  • ווים של ספקים רגילים משתמשים DECLARE_HOOK() כדי ליצור פונקציה של נקודת מעקב עם השם trace_ name כאשר name הוא המזהה הייחודי של המעקב. לפי המוסכמה, שמות הוק של ספקים רגילים מתחילים ב- android_vh , כך שהשם עבור sched_exit() hook יהיה android_vh_sched_exit .
  • יש צורך ב-hooks של ספקים מוגבלים למקרים כמו מתזמן, שבהם יש לקרוא לפונקציה המצורפת גם אם ה-CPU לא מקוון או דורש הקשר לא אטומי. לא ניתן לנתק ווי ספק מוגבל, כך שמודולים שמתחברים לוו מוגבל לעולם לא יוכלו לפרוק. שמות ספקים מוגבלים מתחילים ב- android_rvh .

כדי להוסיף הוק של ספק, הגש בעיה ב-IT ושלח תיקונים (כמו בכל התיקונים הספציפיים לאנדרואיד, בעיה חייבת להתקיים ועליך לספק הצדקה). תמיכה ב-hooks של ספקים היא רק ב-ACK, אז אל תשלח את התיקונים האלה ל-Upstream Linux.

הוסף שדות ספק למבנים

אתה יכול לשייך נתוני ספק למבני נתונים מרכזיים על ידי הוספת שדות android_vendor_data באמצעות פקודות המאקרו ANDROID_VENDOR_DATA() . לדוגמה, כדי לתמוך בתכונות בעלות ערך מוסף, הוסף שדות למבנים כפי שמוצג בדגימת הקוד הבאה.

כדי למנוע התנגשויות פוטנציאליות בין שדות הדרושים לספקים לבין שדות הדרושים ליצרני OEM, יצרני OEM אינם חייבים להשתמש בשדות המוצהרים באמצעות פקודות מאקרו ANDROID_VENDOR_DATA() . במקום זאת, יצרני OEM חייבים להשתמש ANDROID_OEM_DATA() כדי להצהיר על שדות android_oem_data .

#include <linux/android_vendor.h>
...
struct important_kernel_data {
  [all the standard fields];
  /* Create vendor data for use by hook implementations. The
   * size of vendor data is based on vendor input. Vendor data
   * can be defined as single u64 fields like the following that
   * declares a single u64 field named "android_vendor_data1" :
   */
  ANDROID_VENDOR_DATA(1);

  /*
   * ...or an array can be declared. The following is equivalent to
   * u64 android_vendor_data2[20]:
   */
  ANDROID_VENDOR_DATA_ARRAY(2, 20);

  /*
   * SoC vendors must not use fields declared for OEMs and
   * OEMs must not use fields declared for SoC vendors.
   */
  ANDROID_OEM_DATA(1);

  /* no further fields */
}

הגדר ווים של ספקים

הוסף הוקס של ספקים לקוד הליבה כנקודות עקיבה על ידי הצהרתם באמצעות DECLARE_HOOK() או DECLARE_RESTRICTED_HOOK() ולאחר מכן הוספתם לקוד כנקודת עקיבה. לדוגמה, כדי להוסיף trace_android_vh_sched_exit() לפונקציית ליבת do_exit() הקיימת:

#include <trace/hooks/exit.h>
void do_exit(long code)
{
    struct task_struct *tsk = current;
    ...
    trace_android_vh_sched_exit(tsk);
    ...
}

הפונקציה trace_android_vh_sched_exit() בודקת תחילה רק אם משהו מצורף. עם זאת, אם מודול ספק רושם מטפל באמצעות register_trace_android_vh_sched_exit() , הפונקציה הרשומה נקראת. המטפל חייב להיות מודע להקשר לגבי מנעולים מוחזקים, מצב RCS וגורמים אחרים. ה-hook חייב להיות מוגדר בקובץ כותרת בספריית include/trace/hooks .

לדוגמה, הקוד הבא נותן הצהרה אפשרית עבור trace_android_vh_sched_exit() בקובץ include/trace/hooks/exit.h .

/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM sched
#define TRACE_INCLUDE_PATH trace/hooks

#if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_SCHED_H
#include <trace/hooks/vendor_hooks.h>
/*
 * Following tracepoints are not exported in tracefs and provide a
 * mechanism for vendor modules to hook and extend functionality
 */

struct task_struct;

DECLARE_HOOK(android_vh_sched_exit,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));

#endif /* _TRACE_HOOK_SCHED_H */

/* This part must be outside protection */
#include <trace/define_trace.h>

כדי ליצור מופע של הממשקים הנדרשים עבור הספק ה-hook, הוסף את קובץ הכותרת עם הצהרת ה-hook ל- drivers/android/vendor_hooks.c וייצא את הסמלים. לדוגמה, הקוד הבא משלים את ההכרזה על ה- android_vh_sched_exit() .

#ifndef __GENKSYMS__
/* struct task_struct */
#include <linux/sched.h>
#endif

#define CREATE_TRACE_POINTS
#include <trace/hooks/vendor_hooks.h>
#include <trace/hooks/exit.h>
/*
 * Export tracepoints that act as a bare tracehook (i.e. have no trace
 * event associated with them) to allow external modules to probe
 * them.
 */
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_exit);

הערה : מבני נתונים המשמשים בהצהרת ה-hook צריכים להיות מוגדרים במלואם על מנת להבטיח יציבות ABI. אחרת זה לא בטוח לבטל את ההתייחסות למצביעים האטומים או להשתמש במבנה בהקשרים בגודל. ה-include שמספק את ההגדרה המלאה של מבני נתונים כאלה צריך להיכנס לקטע #ifndef __GENKSYMS__ של drivers/android/vendor_hooks.c . קובצי הכותרת ב- include/trace/hooks לא צריכים לכלול את קובץ הכותרת של הליבה עם הגדרות הסוג כדי למנוע שינויים ב-CRC ששוברים את ה-KMI. במקום קדימה להכריז על הסוגים.

חברו לווים של הספק

כדי להשתמש ב-hooks של ספקים, מודול הספק צריך לרשום מטפל עבור ה-hook (בדרך כלל נעשה במהלך אתחול המודול). לדוגמה, הקוד הבא מציג את המטפל של המודול foo.ko עבור trace_android_vh_sched_exit() .

#include <trace/hooks/sched.h>
...
static void foo_sched_exit_handler(void *data, struct task_struct *p)
{
    foo_do_exit_accounting(p);
}
...
static int foo_probe(..)
{
    ...
    rc = register_trace_android_vh_sched_exit(foo_sched_exit_handler, NULL);
    ...
}

תכונות ליבה

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

ממשק תכנות יישומי משתמש (UAPI)

  • קובצי כותרות UAPI. שינויים בקובצי כותרות UAPI חייבים להתרחש במעלה הזרם, אלא אם השינויים הם בממשקים ספציפיים לאנדרואיד. השתמש בקובצי כותרות ספציפיים לספק כדי להגדיר ממשקים בין מודולי ספק וקוד מרחב משתמש של ספק.
  • צומתי sysfs. אל תוסיף צמתי sysfs חדשים לקרנל GKI (תוספות כאלה תקפות רק במודולים של ספקים). צומתי sysfs המשמשים את הספריות SoC והמכשירים האגנוסטיות ואת קוד Java המרכיבים את מסגרת Android ניתנים לשינוי רק בדרכים תואמות ויש לשנות אותם במעלה הזרם אם הם לא צומתי sysfs ספציפיים לאנדרואיד. אתה יכול ליצור צמתי sysfs ספציפיים לספק לשימוש על ידי מרחב המשתמש של הספק. כברירת מחדל, גישה לצמתי sysfs על ידי מרחב משתמש נמנעת באמצעות SELinux. על הספק להוסיף את תוויות ה-SELinux המתאימות כדי לאפשר גישה על ידי תוכנת ספק מורשה.
  • צמתי DebugFS. מודולי ספק יכולים להגדיר צמתים ב- debugfs לניפוי באגים בלבד (כיוון ש- debugfs אינם מותקנים במהלך פעולה רגילה של המכשיר).