تقلل صورة Kernel العامة (GKI) تجزئة النواة من خلال المحاذاة بشكل وثيق مع نواة Linux المنبع. ومع ذلك ، هناك أسباب وجيهة لعدم قبول بعض التصحيحات في المراحل الأولية ، وهناك جداول زمنية للمنتج يجب الوفاء بها ، لذلك يتم الاحتفاظ ببعض التصحيحات في مصادر Android Common Kernel (ACK) التي تم إنشاء GKI منها.
يجب على المطورين إرسال تغييرات التعليمات البرمجية في المراحل الأولى باستخدام قائمة Linux Kernel البريدية (LKML) كخيار أول ، وإرسال تغييرات التعليمات البرمجية إلى فرع ACK android-mainline
فقط عندما يكون هناك سبب قوي لعدم إمكانية تطبيق upstream. يتم سرد أمثلة على الأسباب الصحيحة وكيفية التعامل معها على النحو التالي.
تم إرسال التصحيح إلى LKML ، ولكن لم يتم قبوله في الوقت المناسب لإصدار المنتج. للتعامل مع هذا التصحيح:
- قدم دليلاً على أن التصحيح قد تم تقديمه إلى LKML والتعليقات التي تم تلقيها للتصحيح ، أو الوقت المقدر الذي سيتم فيه إرسال التصحيح قبل المنبع.
- اتخذ قرارًا بشأن مسار العمل للحصول على التصحيح في ACK ، والحصول على الموافقة عليه ، ثم أخرجه من ACK عند دمج الإصدار النهائي في ACK.
يعرّف التصحيح
EXPORT_SYMBOLS_GPL()
لوحدة البائع ، ولكن لا يمكن إرساله إلى المنبع نظرًا لعدم وجود وحدات نمطية داخل الشجرة تستهلك هذا الرمز. للتعامل مع هذا التصحيح ، قدم تفاصيل حول سبب عدم إمكانية إرسال الوحدة النمطية الخاصة بك والبدائل التي فكرت فيها قبل تقديم هذا الطلب.التصحيح ليس عامًا بما يكفي للتنقيب ولا يوجد وقت لإعادة بنائه قبل إصدار المنتج. للتعامل مع هذا التصحيح ، قم بتوفير الوقت المقدر الذي سيتم فيه إرسال التصحيح المعاد تصنيعه قبل المنبع (لن يتم قبول التصحيح في ACK بدون خطة لإرسال تصحيح معاد تصنيعه للمراجعة).
لا يمكن قبول التصحيح من قبل المنبع لأن ... <أدخل السبب هنا> . للتعامل مع هذا التصحيح ، تواصل مع فريق Android kernel واعمل معنا على خيارات لإعادة تشكيل التصحيح بحيث يمكن إرساله للمراجعة وقبوله في مرحلة البداية.
هناك الكثير من المبررات المحتملة. عندما ترسل الخطأ أو التصحيح الخاص بك ، قم بتضمين تبرير صالح وتوقع بعض التكرار والمناقشة. نحن ندرك أن ACK ستحمل بعض التصحيحات ، خاصة في المراحل الأولى من GKI بينما يتعلم الجميع كيفية العمل في المنبع ولكن لا يمكنهم الاسترخاء في جداول المنتج للقيام بذلك. توقع أن تصبح متطلبات التنقيب أكثر صرامة بمرور الوقت.
متطلبات التصحيح
يجب أن تتوافق التصحيحات مع معايير ترميز Linux kernel الموضحة في شجرة مصدر Linux ، سواء تم إرسالها إلى المنبع أو إلى ACK. يتم تشغيل البرنامج النصي scripts/checkpatch.pl
كجزء من اختبار Gerrit المسبق ، لذا قم بتشغيله مسبقًا للتأكد من اجتيازه. لتشغيل البرنامج النصي checkpatch بنفس التكوين مثل اختبار التقديم المسبق ، استخدم build/static_analysis/checkpatch_presubmit.sh
من repo
تسجيل الخروج.
بقع ACK
يجب أن تتوافق التصحيحات المقدمة إلى ACK مع معايير ترميز Linux kernel وإرشادات المساهمة . يجب عليك تضمين علامة Change-Id
في رسالة الالتزام ؛ إذا قمت بإرسال التصحيح إلى عدة فروع (على سبيل المثال ، android-mainline
و android12-5.4
) ، فيجب عليك استخدام نفس Change-Id
لجميع مثيلات التصحيح.
قم بإرسال التصحيحات إلى LKML أولاً للمراجعة الأولية. إذا كان التصحيح:
- تم قبوله في المنبع ، ويتم دمجه تلقائيًا في
android-mainline
. - لم يتم قبوله في المنبع ، أرسله إلى
android-mainline
مع الإشارة إلى الإرسال الأولي أو شرح سبب عدم إرساله إلى LKML.
بعد قبول التصحيح إما في المنبع أو في android-mainline
، يمكن نقله إلى ACK المناسب المستند إلى LTS (مثل android12-5.4
و android11-5.4
للتصحيحات التي تعمل على إصلاح الكود الخاص بنظام Android). يتيح التقديم إلى android-mainline
الاختبار باستخدام مرشحين جدد للإصدار الأولي ويضمن أن التصحيح موجود في ACK التالي المستند إلى LTS. تشمل الاستثناءات الحالات التي يكون فيها التصحيح المنبع backported إلى android12-5.4
(لأنه من المحتمل أن يكون التصحيح موجودًا بالفعل في android-mainline
).
بقع المنبع
كما هو محدد في إرشادات المساهمة ، تقع التصحيحات الأولية المخصصة لنواة ACK في المجموعات التالية (المدرجة بترتيب احتمالية قبولها).
-
UPSTREAM:
- من المحتمل قبول التصحيحات المنتقاة من "android-mainline" في ACK إذا كانت هناك حالة استخدام معقولة. -
BACKPORT:
- من المحتمل أيضًا قبول التصحيحات من المنبع التي لا تنتقي بشكل نظيف وتحتاج إلى تعديل إذا كانت هناك حالة استخدام معقولة. -
FROMGIT:
- قد يتم قبول التصحيحات المنتقاة من فرع المشرف استعدادًا لتقديمها إلى خط Linux الرئيسي إذا كان هناك موعد نهائي قادم. يجب أن تكون هذه مبررة لكل من المحتوى والجدول الزمني. -
FROMLIST:
- التصحيحات التي تم إرسالها إلى LKML ولكن لم يتم قبولها في فرع المشرف حتى الآن من غير المرجح أن يتم قبولها ، ما لم يكن التبرير مقنعًا بما يكفي لقبول التصحيح سواء تم نقله إلى نظام Linux الرئيسي أم لا (نفترض أنها لن تفعل ذلك). يجب أن تكون هناك مشكلة مرتبطة بتصحيحاتFROMLIST
لتسهيل المناقشة مع فريق Android kernel.
التصحيحات الخاصة بنظام Android
إذا لم تتمكن من إجراء التغييرات المطلوبة في المنبع ، يمكنك محاولة إرسال تصحيحات خارج الشجرة إلى ACK مباشرةً. يتطلب إرسال التصحيحات خارج الشجرة إنشاء مشكلة في قسم تكنولوجيا المعلومات تستشهد بالتصحيح والأساس المنطقي لعدم إمكانية إرسال التصحيح في البداية (راجع القائمة السابقة للحصول على أمثلة). ومع ذلك ، هناك بعض الحالات التي لا يمكن فيها تقديم الكود في اتجاه المنبع. تتم تغطية هذه الحالات على النحو التالي ويجب أن تتبع إرشادات المساهمة للتصحيحات الخاصة بنظام Android ويتم تمييزها بـ ANDROID:
بادئة في الموضوع.
التغييرات على gki_defconfig
يجب تطبيق جميع تغييرات CONFIG
على gki_defconfig
على كل من إصداري arm64 و x86 ما لم يكن CONFIG
خاصًا بالبنية. لطلب تغيير في إعداد CONFIG
، قم بإنشاء مشكلة في IT لمناقشة التغيير. يتم رفض أي تغيير CONFIG
يؤثر على واجهة وحدة Kernel (KMI) بعد تجميدها. في الحالات التي يطلب فيها الشركاء إعدادات متضاربة لتهيئة واحدة ، فإننا نحل التعارضات من خلال مناقشة الأخطاء ذات الصلة.
رمز غير موجود في المنبع
لا يمكن إرسال التعديلات على التعليمات البرمجية الخاصة بنظام Android إلى المنبع. على سبيل المثال ، على الرغم من الحفاظ على برنامج تشغيل Binder في اتجاه المنبع ، لا يمكن إرسال التعديلات على ميزات الميراث ذات الأولوية لبرنامج تشغيل Binder لأنها خاصة بنظام Android. كن صريحًا في الخطأ الخاص بك وقم بالتصحيح لماذا لا يمكن إرسال الرمز إلى المنبع. إذا أمكن ، قسّم التصحيحات إلى أجزاء يمكن إرسالها إلى المنبع وأجزاء خاصة بأندرويد لا يمكن إرسالها إلى المنبع لتقليل مقدار الشفرة خارج الشجرة المحفوظة في ACK.
التغييرات الأخرى في هذه الفئة هي تحديثات ملفات تمثيل KMI ، أو قوائم رموز KMI ، أو gki_defconfig
، أو إنشاء البرامج النصية أو التكوين ، أو البرامج النصية الأخرى غير الموجودة في المنبع.
وحدات خارج الشجرة
لا يشجع Upstream Linux دعم بناء وحدات خارج الشجرة. هذا موقف معقول نظرًا لأن المشرفين على Linux لا يقدمون ضمانات حول مصدر in-kernel أو التوافق الثنائي ولا يريدون دعم الكود غير الموجود في الشجرة. ومع ذلك ، فإن 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
إما بشكل صريح أو تبعية.
حكام قابلة للتحميل
بالنسبة لأطر عمل kernel (مثل cpufreq
) التي تدعم المحافظات القابلة للتحميل ، يمكنك تجاوز الحاكم الافتراضي (مثل محافظ schedutil
cpufreq
. بالنسبة للأطر (مثل الإطار الحراري) التي لا تدعم المحافظ أو برامج التشغيل القابلة للتحميل ولكنها لا تزال تتطلب التنفيذ الخاص بالمورد ، وإنشاء مشكلة في تكنولوجيا المعلومات والتشاور مع فريق Android kernel .
سنعمل معك ومع المشرفين على المنبع لإضافة الدعم اللازم.
خطاطيف البائعين
في الإصدارات السابقة ، يمكنك إضافة تعديلات خاصة بالبائع مباشرة إلى النواة الأساسية. هذا غير ممكن مع GKI 2.0 لأنه يجب تنفيذ التعليمات البرمجية الخاصة بالمنتج في وحدات ولن يتم قبولها في النواة الأساسية في المنبع أو في ACK. لتمكين ميزات القيمة المضافة التي يعتمد عليها الشركاء بأقل تأثير على كود النواة الأساسية ، يقبل GKI روابط البائع التي تسمح باستدعاء الوحدات النمطية من كود النواة الأساسية. بالإضافة إلى ذلك ، يمكن تعبئة هياكل البيانات الرئيسية بحقول بيانات البائع المتوفرة لتخزين البيانات الخاصة بالبائع لتنفيذ هذه الميزات.
تأتي أدوات ربط البائعين في متغيرين (عادي ومقيّد) يعتمدان على نقاط التتبع (وليس أحداث التتبع) التي يمكن أن ترفق بها وحدات البائع. على سبيل المثال ، بدلاً من إضافة وظيفة sched_exit()
جديدة لإجراء محاسبة عند إنهاء المهمة ، يمكن للبائعين إضافة خطاف في do_exit()
يمكن لوحدة المورد إرفاقها للمعالجة. يتضمن مثال التنفيذ خطافات البائع التالية.
- تستخدم أدوات ربط البائع العادية
DECLARE_HOOK()
لإنشاء دالة tracepoint بالاسمtrace_ name
حيثname
هو المعرف الفريد للتتبع. حسب الاصطلاح ، تبدأ أسماء ربط البائع العادية بـandroid_vh
، لذا فإن اسم الخطافsched_exit()
Sched_exit سيكونandroid_vh_sched_exit
. - هناك حاجة إلى أدوات ربط المورد المقيدة لحالات مثل خطافات جدولة حيث يجب استدعاء الوظيفة المرفقة حتى إذا كانت وحدة المعالجة المركزية غير متصلة أو تتطلب سياقًا غير ذري. لا يمكن فصل خطافات البائع المقيدة ، لذا لا يمكن أبدًا إلغاء تحميل الوحدات النمطية التي ترتبط بخطاف مقيد. يُسمح بإرفاق واحد فقط ، لذا فإن أي محاولات أخرى للإرفاق تفشل مع
-EBUSY
. تبدأ أسماء ربط البائع المقيدة بـandroid_rvh
.
لإضافة أداة جذب للبائع ، قم بتسجيل مشكلة في قسم تكنولوجيا المعلومات وإرسال التصحيحات (كما هو الحال مع جميع التصحيحات الخاصة بنظام Android ، يجب أن تكون هناك مشكلة ويجب تقديم تبرير). يتوفر دعم أدوات ربط البائعين في ACK فقط ، لذا لا ترسل هذه التصحيحات إلى نظام Linux المنبع.
إضافة حقول البائعين إلى الهياكل
يمكنك إقران بيانات المورد بهياكل البيانات الرئيسية عن طريق إضافة حقول android_vendor_data
باستخدام وحدات الماكرو ANDROID_VENDOR_DATA()
. على سبيل المثال ، لدعم ميزات القيمة المضافة ، قم بإلحاق الحقول بالبنيات كما هو موضح في نموذج التعليمات البرمجية التالي.
لتجنب التعارض المحتمل بين الحقول التي يحتاجها البائعون والحقول التي يحتاجها المصنّعون الأصليون (OEM) ، يجب ألا يستخدم المصنّعون الأصليون مطلقًا الحقول المعلنة باستخدام وحدات الماكرو ANDROID_VENDOR_DATA()
. بدلاً من ذلك ، يجب على مصنعي المعدات الأصلية استخدام 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 */
}
تحديد خطاطيف البائع
أضف خطافات البائع إلى كود kernel كنقاط تتبع عن طريق إعلانها باستخدام DECLARE_HOOK()
أو DECLARE_RESTRICTED_HOOK()
ثم إضافتها إلى التعليمات البرمجية كنقطة تتبع. على سبيل المثال ، لإضافة trace_android_vh_sched_exit()
إلى دالة kernel 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>
لإنشاء مثيل للواجهات المطلوبة لخطاف البائع ، أضف ملف الرأس مع إعلان الخطاف إلى 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
ملف رأس kernel مع تعريفات النوع لتجنب تغييرات CRC التي تكسر KMI. بدلا من ذلك إلى الأمام تعلن الأنواع.
نعلق على خطاف البائع
لاستخدام أدوات ربط البائع ، تحتاج وحدة البائع إلى تسجيل معالج للخطاف (يتم ذلك عادةً أثناء تهيئة الوحدة النمطية). على سبيل المثال ، يُظهر الكود التالي معالج 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);
...
}
ميزات النواة الأساسية
إذا لم تمكّنك أي من الأساليب السابقة من تنفيذ ميزة من وحدة نمطية ، فيجب عليك إضافة الميزة كتعديل خاص بـ Android إلى النواة الأساسية. قم بإنشاء مشكلة في أداة تعقب المشكلة (IT) لبدء المحادثة.
واجهة برمجة تطبيقات المستخدم (UAPI)
- ملفات رأس UAPI. يجب أن تحدث التغييرات على ملفات رأس UAPI في بداية الطريق ما لم تكن التغييرات على واجهات خاصة بـ Android. استخدم ملفات الرأس الخاصة بالمورد لتعريف الواجهات بين وحدات البائعين النمطية ورمز مساحة مستخدمي البائعين.
- عقد sysfs. لا تقم بإضافة عُقد sysfs جديدة إلى نواة GKI (مثل هذه الإضافات صالحة فقط في وحدات البائع). يمكن تغيير عُقد sysfs التي تستخدمها مكتبات SoC والمكتبات الحيادية للجهاز ورمز Java الذي يشتمل على إطار عمل Android فقط بطرق متوافقة ويجب تغييرها في البداية إذا لم تكن عُقد sysfs خاصة بنظام Android. يمكنك إنشاء عقد sysfs خاصة بالبائع لتستخدمها مساحة مستخدمي البائعين. افتراضيًا ، يتم رفض وصول مساحة المستخدمين إلى عقد sysfs باستخدام SELinux. الأمر متروك للبائع لإضافة تسميات SELinux المناسبة للسماح بالوصول بواسطة برنامج البائع المعتمد.
- عقد DebugFS. يمكن لوحدات البائع أن تحدد العقد في
debugfs
من أجل التصحيح فقط (حيث لا يتم تحميلdebugfs
أثناء التشغيل العادي للجهاز).