Универсальный образ ядра (GKI) уменьшает фрагментацию ядра, будучи тесно согласованным с исходным ядром Linux. Однако существуют веские причины, по которым некоторые патчи не могут быть приняты исходным кодом, и существуют графики разработки продукта, которые необходимо соблюдать, поэтому некоторые патчи поддерживаются в исходных кодах Android Common Kernel (ACK), на основе которых создается GKI.
Разработчики должны в первую очередь отправлять изменения в основной репозиторий, используя список рассылки ядра Linux (LKML), и отправлять изменения в ветку ACK android-mainline только в том случае, если есть веская причина, по которой отправка в основной репозиторий невозможна. Примеры уважительных причин и способы их обработки приведены ниже.
Патч был отправлен в LKML, но не был принят к моменту выпуска продукта. Для обработки этого патча:
- Предоставьте доказательства того, что патч был отправлен в LKML и получены комментарии к нему, или укажите примерные сроки отправки патча в основной репозиторий.
- Определите план действий: внести патч в ACK, получить одобрение от разработчиков, а затем удалить его из ACK после слияния окончательной версии из ACK с ACK.
Патч определяет функцию
EXPORT_SYMBOLS_GPL()для модуля поставщика, но его не удалось отправить в основную ветку разработки, поскольку в дереве модулей нет тех, которые используют этот символ. Чтобы обработать этот патч, предоставьте подробную информацию о том, почему ваш модуль не может быть отправлен в основную ветку разработки, и об альтернативных вариантах, которые вы рассматривали до отправки этого запроса.Данный патч недостаточно универсален для включения в основной репозиторий, и нет времени на его рефакторинг до выпуска продукта. Для обработки этого патча укажите примерные сроки, к которым рефакторизованный патч будет отправлен в основной репозиторий (патч не будет принят в ACK без плана отправки рефакторизованного патча в основной репозиторий для проверки).
Данный патч не может быть принят разработчиками, потому что... <укажите причину> . Чтобы решить эту проблему, свяжитесь с командой разработчиков ядра Android и обсудите с нами варианты рефакторинга патча, чтобы его можно было отправить на рассмотрение и принять разработчиками.
Существует множество других потенциальных обоснований. Когда вы отправляете сообщение об ошибке или патче, обязательно укажите веское обоснование и ожидайте дальнейших обсуждений и доработок. Мы понимаем, что подтверждение (ACK) включает в себя некоторые патчи, особенно на ранних этапах GKI, когда все учатся работать с исходным кодом, но не можем ослабить сроки разработки продукта для этого. Ожидайте, что требования к интеграции с исходным кодом со временем станут более строгими.
Требования к обновлениям
Патчи должны соответствовать стандартам кодирования ядра Linux, описанным в исходном коде Linux , независимо от того, отправляются ли они в основную ветку или в ACK. Скрипт scripts/checkpatch.pl запускается в рамках предварительного тестирования Gerrit, поэтому запустите его заранее, чтобы убедиться в его успешном прохождении. Чтобы запустить скрипт checkpatch с той же конфигурацией, что и при предварительном тестировании, используйте //build/kernel/static_analysis:checkpatch_presubmit . Подробности см. в build/kernel/kleaf/docs/checkpatch.md .
Патчи ACK
Патчи, отправляемые в ACK, должны соответствовать стандартам кодирования ядра Linux и рекомендациям по внесению вклада . В сообщении коммита необходимо указать тег Change-Id ; если вы отправляете патч в несколько веток (например, android-mainline и android12-5.4 ), необходимо использовать один и тот же Change-Id для всех экземпляров патча.
Сначала отправьте патчи в LKML для проверки в вышестоящем проекте. Если патч:
- Принято к реализации в основном репозитории и автоматически объединено с
android-mainline. - Если ваш проект не принят в основной репозиторий, отправьте его в
android-mainlineсо ссылкой на исходный проект или объяснением причин, по которым он не был отправлен в LKML.
После того, как патч принят либо в основной ветке проекта, либо в android-mainline , его можно перенести в соответствующий LTS-релиз (например, android12-5.4 и android11-5.4 для патчей, исправляющих специфический для Android код). Отправка в android-mainline позволяет тестировать патч с новыми кандидатами на релиз из основной ветки проекта и гарантирует, что он будет включен в следующий LTS-релиз. Исключения составляют случаи, когда патч из основной ветки проекта переносится в android12-5.4 (поскольку патч, скорее всего, уже есть в android-mainline ).
Патчи из вышестоящего репозитория
Как указано в рекомендациях по внесению вклада , патчи из исходного кода, предназначенные для ядер ACK, делятся на следующие группы (перечислены в порядке вероятности принятия).
-
UPSTREAM:- Патчи, отобранные из 'android-mainline', скорее всего, будут приняты в ACK, если для них есть разумное обоснование. -
BACKPORT:— Патчи из исходного кода, которые не корректно подбираются и требуют доработки, также, скорее всего, будут приняты, если для них есть разумное обоснование. -
FROMGIT:— Патчи, отобранные из ветки сопровождающего проекта в рамках подготовки к отправке в основную ветку Linux, могут быть приняты, если приближается крайний срок. Необходимо обосновать их как по содержанию, так и по срокам. -
FROMLIST:— Патчи, отправленные в LKML, но еще не принятые в ветку сопровождающего, вряд ли будут приняты, если только обоснование не будет достаточно убедительным, чтобы патч был принят независимо от того, попадет ли он в основную ветку Linux или нет (мы предполагаем, что этого не произойдет). Для обсуждения с командой разработчиков ядра Android необходимо создать соответствующую проблему, связанную с патчамиFROMLIST.
Патчи, специфичные для Android
Если вам не удаётся внести необходимые изменения в основной репозиторий, вы можете попытаться отправить патчи вне основного репозитория непосредственно в ACK. Для отправки таких патчей необходимо создать в IT-отделе заявку, в которой будет указан патч и обоснование того, почему его нельзя отправить в основной репозиторий (см. предыдущий список примеров). Однако есть несколько случаев, когда код нельзя отправить в основной репозиторий. Эти случаи описаны ниже и должны соответствовать рекомендациям по внесению изменений для патчей, специфичных для Android, и быть помечены префиксом ANDROID: в теме письма.
Изменения в gki_defconfig
Все изменения параметров CONFIG в gki_defconfig должны применяться как к версиям arm64, так и к x86, за исключением случаев, когда изменение CONFIG является архитектурно-специфичным. Чтобы запросить изменение параметра CONFIG , создайте заявку в IT-отделе для обсуждения изменений. Любые изменения CONFIG , затрагивающие интерфейс модуля ядра (KMI) после его фиксации, отклоняются. В случаях, когда партнеры запрашивают конфликтующие параметры для одной конфигурации, мы разрешаем конфликты путем обсуждения соответствующих ошибок.
Код, которого нет в исходном коде.
Изменения в коде, уже специфичном для Android, не могут быть отправлены в основной репозиторий. Например, даже несмотря на то, что драйвер binder поддерживается в основном репозитории, изменения в функциях наследования приоритетов этого драйвера не могут быть отправлены в основной репозиторий, поскольку они специфичны для Android. Четко укажите в своем сообщении об ошибке и патче, почему код не может быть отправлен в основной репозиторий. По возможности разделите патчи на части, которые могут быть отправлены в основной репозиторий, и части, специфичные для Android, которые не могут быть отправлены в основной репозиторий, чтобы минимизировать количество кода, находящегося вне основного дерева и поддерживаемого в ACK.
К этой категории относятся также обновления файлов представления KMI, списков символов KMI, gki_defconfig , скриптов сборки или конфигурации, а также других скриптов, отсутствующих в исходном коде.
Модули, не входящие в исходное дерево
В основном репозитории Linux активно не рекомендуется поддержка сборки модулей, не входящих в основное дерево. Это разумная позиция, учитывая, что сопровождающие 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 ). Для фреймворков (таких как thermal framework), которые не поддерживают загружаемые регуляторы или драйверы, но все же требуют реализации, специфичной для поставщика, создайте заявку в ИТ-отделе и проконсультируйтесь с командой разработчиков ядра Android .
Мы будем сотрудничать с вами и разработчиками исходного кода, чтобы добавить необходимую поддержку.
Зацепки поставщика
В предыдущих версиях можно было добавлять специфические для поставщика модификации непосредственно в ядро. В GKI 2.0 это невозможно, поскольку код, специфичный для продукта, должен быть реализован в модулях и не будет принят в ядрах разработчиков или в ACK. Чтобы обеспечить работу дополнительных функций, на которые полагаются партнеры, с минимальным влиянием на код ядра, GKI принимает хуки поставщиков, позволяющие вызывать модули из кода ядра. Кроме того, ключевые структуры данных могут быть дополнены полями данных поставщика, доступными для хранения специфических для поставщика данных для реализации этих функций.
Вспомогательные модули (vendor hooks) бывают двух типов (обычные и ограниченные), основанных на точках трассировки (а не событиях трассировки), к которым могут подключаться модули сторонних разработчиков. Например, вместо добавления новой функции sched_exit() для учета при завершении задачи, модули сторонних разработчиков могут добавить вспомогательный модуль в функцию do_exit() , к которому модуль стороннего разработчика сможет подключиться для обработки. Пример реализации включает следующие вспомогательные модули.
- В стандартных хуках поставщиков используется
DECLARE_HOOK()для создания функции трассировки с именемtrace_ nameгдеname— уникальный идентификатор трассировки. По соглашению, имена стандартных хуков поставщиков начинаются сandroid_vh, поэтому имя для хукаsched_exit()будетandroid_vh_sched_exit. - Ограниченные обработчики запросов необходимы в таких случаях, как обработчики планировщика, когда прикрепленная функция должна вызываться даже если процессор отключен или требуется неатомарный контекст. Ограниченные обработчики запросов нельзя отсоединить, поэтому модули, которые подключаются к ограниченному обработчику, никогда не смогут выгрузиться. Имена ограниченных обработчиков запросов начинаются с
android_rvh.
Чтобы добавить механизм взаимодействия с поставщиком, создайте заявку в IT-отделе и отправьте патчи (как и в случае со всеми патчами, специфичными для Android, должна существовать заявка, и вы должны предоставить обоснование). Поддержка механизмов взаимодействия с поставщиком доступна только в ACK, поэтому не отправляйте эти патчи в основную ветку Linux.
Добавить поля поставщика в структуры
Вы можете связать данные поставщика с ключевыми структурами данных, добавив поля android_vendor_data с помощью макроса ANDROID_VENDOR_DATA() . Например, для поддержки дополнительных функций добавьте поля к структурам, как показано в следующем примере кода.
Во избежание потенциальных конфликтов между полями, необходимыми поставщикам, и полями, необходимыми производителям оборудования, производители оборудования никогда не должны использовать поля, объявленные с помощью макроса 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 */
}
Определите точки взаимодействия с поставщиками.
Добавьте в код ядра точки трассировки, используя функции 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>
Для создания необходимых интерфейсов для обработчика запросов поставщика добавьте заголовочный файл с объявлением обработчика в 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 для 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);
...
}
Используйте хуки поставщиков из заголовочных файлов.
Для использования механизмов трассировки из заголовочных файлов может потребоваться обновить заголовочный файл механизма трассировки, отменив определение переменной TRACE_INCLUDE_PATH , чтобы избежать ошибок сборки, указывающих на то, что заголовочный файл точки трассировки не найден. Например,
In file included from .../common/init/main.c:111:
In file included from .../common/include/trace/events/initcall.h:74:
.../common/include/trace/define_trace.h:95:10: fatal error: 'trace/hooks/initcall.h' file not found
95 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:90:32: note: expanded from macro 'TRACE_INCLUDE'
90 | # define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
| ^~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:87:34: note: expanded from macro '__TRACE_INCLUDE'
87 | # define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:10:27: note: expanded from macro '__stringify'
10 | #define __stringify(x...) __stringify_1(x)
| ^~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:9:29: note: expanded from macro '__stringify_1'
9 | #define __stringify_1(x...) #x
< | > ^~
scratch space:14:1: note: expanded from here
14 | "trace/hooks/initcall.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Чтобы исправить этот тип ошибки сборки, примените соответствующее исправление к заголовочному файлу vendor hook, который вы включаете. Для получения дополнительной информации см. https://r.android.com/3066703 .
diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h
index bc6de7e53d66..039926f7701d 100644
--- a/include/trace/hooks/mm.h
+++ b/include/trace/hooks/mm.h
@@ -2,7 +2,10 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM mm
+#ifdef CREATE_TRACE_POINTS
#define TRACE_INCLUDE_PATH trace/hooks
+#define UNDEF_TRACE_INCLUDE_PATH
+#endif
Определение UNDEF_TRACE_INCLUDE_PATH указывает файлу include/trace/define_trace.h отменить определение TRACE_INCLUDE_PATH после создания точек трассировки.
Основные функции ядра
Если ни один из предыдущих методов не позволяет реализовать функцию из модуля, то необходимо добавить эту функцию в ядро Android в качестве модификации, специфичной для Android. Создайте заявку в системе отслеживания ошибок (IT), чтобы начать обсуждение.
Пользовательский интерфейс прикладного программирования (UAPI)
- Заголовочные файлы UAPI. Изменения в заголовочных файлах UAPI должны вноситься в основной репозиторий, за исключением изменений, касающихся интерфейсов, специфичных для Android. Используйте заголовочные файлы, специфичные для поставщика, для определения интерфейсов между модулями поставщика и кодом пользовательского пространства поставщика.
- Узлы sysfs. Не добавляйте новые узлы sysfs в ядро GKI (такие дополнения допустимы только в модулях поставщика). Узлы sysfs, используемые библиотеками и Java-кодом, не зависящими от SoC и устройства, составляющими фреймворк Android, могут быть изменены только совместимым образом и должны быть изменены в вышестоящем проекте, если они не являются узлами sysfs, специфичными для Android. Вы можете создавать узлы sysfs, специфичные для поставщика, для использования пользовательским пространством поставщика. По умолчанию доступ к узлам sysfs из пользовательского пространства запрещен с помощью SELinux. Поставщик должен добавить соответствующие метки SELinux, чтобы разрешить доступ авторизованному программному обеспечению поставщика.
- Узлы DebugFS. Модули производителя могут определять узлы в
debugfsтолько для отладки (посколькуdebugfsне монтируется во время нормальной работы устройства).