کد هسته را برای GKI توسعه دهید

تصویر هسته عمومی (GKI) با همسویی نزدیک با هسته بالادست لینوکس، تکه تکه شدن هسته را کاهش می دهد. با این حال، دلایل معتبری وجود دارد که چرا برخی از وصله‌ها را نمی‌توان در بالادستی پذیرفت، و برنامه‌های زمانی محصولات وجود دارد که باید رعایت شوند، بنابراین برخی از وصله‌ها در منابع هسته مشترک Android (ACK) که GKI از آن ساخته شده است، نگهداری می‌شوند.

توسعه دهندگان باید تغییرات کد را در بالادست با استفاده از لیست پستی هسته لینوکس (LKML) به عنوان اولین انتخاب ارسال کنند، و تغییرات کد را تنها زمانی به شعبه android-mainline ACK ارسال کنند که دلیل قوی وجود داشته باشد که بالادستی قابل دوام نیست. نمونه هایی از دلایل معتبر و نحوه رسیدگی به آنها به شرح زیر ذکر شده است.

  • پچ به LKML ارسال شد، اما به موقع برای انتشار محصول پذیرفته نشد. برای مدیریت این پچ:

    • شواهدی را ارائه کنید که نشان دهد وصله به LKML ارسال شده است و نظرات دریافت شده برای وصله، یا زمان تخمینی برای ارسال وصله در بالادست.
    • در مورد روشی تصمیم بگیرید که پچ را در ACK قرار دهید، آن را در بالادست تأیید کنید، و سپس زمانی که نسخه بالادستی نهایی در ACK ادغام شد، آن را از ACK خارج کنید.
  • پچ EXPORT_SYMBOLS_GPL() را برای یک ماژول فروشنده تعریف می کند، اما نمی تواند در بالادست ارسال شود زیرا هیچ ماژول درون درختی وجود ندارد که آن نماد را مصرف کند. برای رسیدگی به این وصله، جزئیاتی در مورد اینکه چرا ماژول شما نمی تواند در بالادست ارسال شود و گزینه های جایگزینی که قبل از ارائه این درخواست در نظر گرفته اید، ارائه دهید.

  • پچ به اندازه کافی برای بالادستی عمومی نیست و زمانی برای اصلاح آن قبل از انتشار محصول وجود ندارد. برای رسیدگی به این وصله، یک زمان تخمینی ارائه کنید که تا آن یک وصله اصلاح‌شده در بالادست ارسال می‌شود (وصله در ACK بدون برنامه‌ای برای ارسال یک وصله اصلاح‌شده در بالادست برای بررسی پذیرفته نمی‌شود).

  • وصله نمی تواند توسط upstream پذیرفته شود زیرا... <درج دلیل در اینجا> . برای رسیدگی به این وصله، با تیم هسته اندروید تماس بگیرید و با ما روی گزینه‌هایی برای بازسازی پچ کار کنید تا برای بررسی ارسال شود و در بالادستی پذیرفته شود.

توجیهات بالقوه بیشتری وجود دارد. هنگامی که باگ یا پچ خود را ارسال می کنید، یک توجیه معتبر وارد کنید و منتظر تکرار و بحث باشید. ما می دانیم که ACK دارای برخی وصله ها است، به خصوص در مراحل اولیه GKI در حالی که همه در حال یادگیری نحوه کار در بالادست هستند اما نمی توانند برنامه های محصول را برای انجام این کار راحت کنند. انتظار می رود الزامات بالادستی در طول زمان سختگیرانه تر شوند.

الزامات پچ

وصله ها باید با استانداردهای کدنویسی هسته لینوکس که در درخت منبع لینوکس توضیح داده شده است، مطابقت داشته باشند، خواه در بالادست ارسال شوند یا به ACK. اسکریپت scripts/checkpatch.pl به عنوان بخشی از آزمایش پیش ارسال Gerrit اجرا می‌شود، بنابراین آن را از قبل اجرا کنید تا مطمئن شوید که موفق می‌شود. برای اجرای اسکریپت وصله چک با همان پیکربندی آزمایش پیش ارسال، از //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 ادغام می شود.
  • در بالادست پذیرفته نشد، آن را با ارجاع به ارسال بالادستی یا توضیحی برای اینکه چرا به LKML ارسال نشده است، به android-mainline ارسال کنید.

پس از پذیرش یک وصله در بالادست یا android-mainline ، می‌توان آن را به ACK مبتنی بر LTS (مانند android12-5.4 و android11-5.4 برای وصله‌هایی که کدهای خاص Android را اصلاح می‌کنند) بکپورت کرد. ارسال به android-mainline آزمایش با نامزدهای جدید نسخه بالادستی را امکان پذیر می کند و تضمین می کند که وصله در ACK بعدی مبتنی بر LTS باشد. موارد استثنا شامل مواردی می شود که یک وصله upstream به android12-5.4 بکپورت می شود (زیرا این وصله احتمالاً قبلاً در android-mainline بوده است).

تکه های بالادست

همانطور که در دستورالعمل های مشارکت مشخص شده است، وصله های بالادستی برای هسته های ACK در گروه های زیر قرار می گیرند (فهرست شده به ترتیب احتمال پذیرفته شدن).

  • UPSTREAM: - وصله‌های انتخاب‌شده از «android-mainline» احتمالاً در صورت وجود موارد استفاده معقول در ACK پذیرفته می‌شوند.
  • BACKPORT: - وصله‌هایی از بالادست که تمیز نمی‌شوند و نیاز به اصلاح دارند نیز در صورت وجود موارد استفاده معقول، احتمالاً پذیرفته می‌شوند.
  • FROMGIT: - وصله‌هایی که از یک شعبه نگهدارنده برای آماده‌سازی برای ارسال به خط اصلی لینوکس انتخاب شده‌اند، در صورت وجود مهلت آتی، ممکن است پذیرفته شوند. اینها باید هم برای محتوا و هم از نظر برنامه توجیه شوند.
  • FROMLIST: - وصله هایی که به LKML ارسال شده اند اما هنوز در یک شاخه نگهدارنده پذیرفته نشده اند بعید است پذیرفته شوند، مگر اینکه توجیه به اندازه کافی قانع کننده باشد که این وصله پذیرفته شود چه در لینوکس بالادست قرار بگیرد یا نه (فرض می کنیم که نمی شود). برای تسهیل بحث با تیم هسته اندروید، باید مشکلی با وصله‌های FROMLIST وجود داشته باشد.

وصله های مخصوص اندروید

اگر نمی توانید تغییرات مورد نیاز را در بالادست پیاده کنید، می توانید سعی کنید وصله های خارج از درخت را مستقیماً به ACK ارسال کنید. ارسال وصله‌های خارج از درخت مستلزم این است که مشکلی در IT ایجاد کنید که در آن وصله و دلیلی برای عدم ارسال وصله در بالادست ذکر می‌کند (برای مثال به لیست قبلی مراجعه کنید). با این حال، چند مورد وجود دارد که کد را نمی توان در بالادست ارسال کرد. این موارد به شرح زیر پوشش داده می شوند و باید دستورالعمل های مشارکت برای وصله های خاص اندروید را دنبال کنند و با پیشوند ANDROID: در موضوع برچسب گذاری شوند.

تغییرات در gki_defconfig

تمام تغییرات CONFIG به gki_defconfig باید برای هر دو نسخه arm64 و x86 اعمال شود، مگر اینکه CONFIG مختص معماری باشد. برای درخواست تغییر در تنظیمات CONFIG ، یک مشکل در IT ایجاد کنید تا در مورد تغییر بحث کنید. هرگونه تغییر CONFIG که بر رابط ماژول هسته (KMI) پس از ثابت شدن تأثیر بگذارد، رد می شود. در مواردی که شرکا تنظیمات متناقضی را برای یک پیکربندی درخواست می‌کنند، ما تضادها را از طریق بحث در مورد باگ‌های مرتبط حل می‌کنیم.

کدی که در بالادست وجود ندارد

تغییرات در کدهایی که قبلاً مختص Android هستند را نمی‌توان در بالادست ارسال کرد. برای مثال، حتی اگر درایور بایندر در بالادست نگهداری شود، تغییرات در ویژگی‌های وراثت اولویتی درایور کلاسور نمی‌تواند به بالادست ارسال شود زیرا مختص اندروید هستند. در اشکال و وصله خود صریح باشید که چرا کد نمی تواند در بالادست ارسال شود. در صورت امکان، وصله‌ها را به قطعاتی تقسیم کنید که می‌توانند در بالادست ارسال شوند و قطعات مخصوص Android که نمی‌توانند در بالادست ارسال شوند تا مقدار کد خارج از درخت نگهداری شده در ACK به حداقل برسد.

تغییرات دیگر در این دسته به‌روزرسانی فایل‌های نمایش KMI، لیست نمادهای KMI، gki_defconfig ، اسکریپت‌های ساخت یا پیکربندی، یا سایر اسکریپت‌هایی است که در بالادست وجود ندارند.

ماژول های خارج از درخت

لینوکس بالادست به طور فعال پشتیبانی از ساخت ماژول های خارج از درخت را متوقف می کند. با توجه به اینکه نگهبانان لینوکس در مورد منبع درون هسته یا سازگاری باینری تضمین نمی کنند و نمی خواهند از کدهایی که در درخت نیست پشتیبانی کنند، این یک موضع معقول است. با این حال، GKI ضمانت‌های ABI را برای ماژول‌های فروشنده ایجاد می‌کند و تضمین می‌کند که رابط‌های KMI برای طول عمر پشتیبانی شده یک هسته پایدار هستند. بنابراین، دسته‌ای از تغییرات برای پشتیبانی از ماژول‌های فروشنده وجود دارد که برای ACK قابل قبول هستند اما برای بالادستی قابل قبول نیستند.

به عنوان مثال، وصله‌ای را در نظر بگیرید که ماکروهای EXPORT_SYMBOL_GPL() را اضافه می‌کند، جایی که ماژول‌هایی که از صادرات استفاده می‌کنند در درخت منبع نیستند. در حالی که باید سعی کنید EXPORT_SYMBOL_GPL() upstream را درخواست کنید و ماژولی را ارائه دهید که از نماد جدید صادر شده استفاده می کند، اگر دلیل معتبری برای عدم ارسال ماژول در بالادست وجود داشته باشد، می توانید به جای آن پچ را به ACK ارسال کنید. شما باید توجیهی را برای اینکه چرا ماژول نمی‌تواند آپاستریم شود را در این موضوع بگنجانید. (نوع غیر GPL، EXPORT_SYMBOL() درخواست نکنید.)

تنظیمات پنهان

برخی از ماژول های درون درختی به طور خودکار پیکربندی های پنهانی را انتخاب می کنند که نمی توان آنها را در gki_defconfig مشخص کرد. برای مثال، زمانی که CONFIG_SND_SOC_SOF=y پیکربندی شود، CONFIG_SND_SOC_TOPOLOGY به طور خودکار انتخاب می شود. برای تطبیق ساختمان ماژول خارج از درخت، 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() android_vh_sched_exit خواهد بود.
  • قلاب‌های فروشنده محدود برای مواردی مانند قلاب‌های زمان‌بندی که در آن‌ها تابع پیوست شده باید فراخوانی شود، حتی اگر CPU آفلاین باشد یا به یک زمینه غیراتمی نیاز دارد، مورد نیاز است. قلاب های فروشنده محدود را نمی توان جدا کرد، بنابراین ماژول هایی که به یک قلاب محدود متصل می شوند هرگز نمی توانند بارگیری شوند. نام قلاب فروشنده محدود با android_rvh شروع می شود.

برای افزودن یک قلاب فروشنده، یک مشکل را در IT ثبت کنید و وصله‌ها را ارسال کنید (مانند همه وصله‌های مخصوص اندروید، مشکل باید وجود داشته باشد و باید توجیهی ارائه کنید). پشتیبانی از قلاب‌های فروشنده فقط در ACK است، بنابراین این وصله‌ها را به لینوکس بالادستی ارسال نکنید.

فیلدهای فروشنده را به ساختارها اضافه کنید

با افزودن فیلدهای 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 و سایر عوامل آگاه باشد. قلاب باید در یک فایل هدر در دایرکتوری 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 به 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);

توجه : ساختارهای داده ای که در اعلان قلاب استفاده می شوند باید به طور کامل تعریف شوند تا پایداری ABI تضمین شود. در غیر این صورت، عدم ارجاع به اشاره گرهای مات یا استفاده از ساختار در زمینه های اندازه، ناامن است. شامل که تعریف کاملی از چنین ساختارهای داده ای را ارائه می دهد باید در بخش #ifndef __GENKSYMS__ drivers/android/vendor_hooks.c قرار گیرد. فایل‌های سرصفحه در include/trace/hooks نباید شامل فایل هدر هسته با تعاریف نوع باشد تا از تغییرات CRC که KMI را خراب می‌کند جلوگیری شود. در عوض به جلو انواع را اعلام کنید.

به قلاب های فروشنده وصل کنید

برای استفاده از قلاب‌های فروشنده، ماژول فروشنده باید یک کنترل‌کننده برای قلاب ثبت کند (معمولاً در طول اولیه‌سازی ماژول انجام می‌شود). برای مثال، کد زیر ماژول foo.ko handler را برای 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 و دستگاه‌ها و کدهای جاوا که چارچوب Android را تشکیل می‌دهند را می‌توان تنها به روش‌های سازگار تغییر داد و اگر گره‌های sysfs مختص اندروید نیستند، باید در بالادست تغییر کنند. شما می توانید گره های sysfs خاص فروشنده ایجاد کنید تا توسط فضای کاربران فروشنده استفاده شود. به طور پیش فرض، دسترسی به گره های sysfs توسط فضای کاربری با استفاده از SELinux ممنوع است. این بر عهده فروشنده است که برچسب های SELinux مناسب را اضافه کند تا اجازه دسترسی به نرم افزار فروشنده مجاز را بدهد.
  • گره های DebugFS. ماژول‌های فروشنده می‌توانند گره‌هایی را در debugfs فقط برای اشکال‌زدایی تعریف کنند (زیرا debugfs در طول عملکرد عادی دستگاه نصب نمی‌شود).