Общий образ ядра (GKI) уменьшает фрагментацию ядра за счет тесного согласования с исходным ядром Linux. Однако существуют веские причины, по которым некоторые исправления не могут быть приняты в исходном коде, и существуют графики выпуска продуктов, которые необходимо соблюдать, поэтому некоторые исправления сохраняются в источниках Android Common Kernel (ACK), на основе которых создается GKI.
Разработчики должны отправлять изменения кода в исходную версию, используя список рассылки ядра Linux (LKML) в качестве первого варианта, и отправлять изменения кода в ветку ACK android-mainline
только в том случае, если есть веская причина, по которой восходящая версия нежизнеспособна. Ниже приведены примеры веских причин и способов их устранения.
Патч был отправлен в LKML, но не был принят к выпуску продукта. Чтобы справиться с этим патчем:
- Предоставьте доказательства того, что исправление было отправлено в LKML, и комментарии, полученные для исправления, или примерное время, к которому исправление будет отправлено в исходную версию.
- Определите порядок действий, чтобы разместить исправление в ACK, получить его одобрение в восходящем направлении, а затем удалить его из ACK, когда окончательная исходная версия будет объединена с ACK.
Патч определяет
EXPORT_SYMBOLS_GPL()
для модуля поставщика, но не может быть отправлен в исходную версию, поскольку в дереве нет модулей, использующих этот символ. Чтобы обработать это исправление, предоставьте подробную информацию о том, почему ваш модуль не может быть отправлен в исходную версию, и альтернативы, которые вы рассмотрели, прежде чем делать этот запрос.Патч недостаточно универсален для основной ветки разработки, и нет времени на его рефакторинг перед выпуском продукта. Чтобы обработать это исправление, укажите примерное время, в течение которого исправленное исправление будет отправлено в исходную версию (исправление не будет принято в ACK без плана отправки исправленного исправления в исходную версию для проверки).
Исправление не может быть принято вышестоящей стороной, потому что... <вставьте здесь причину> . Чтобы обработать этот патч, обратитесь к команде разработчиков ядра Android и поработайте с нами над вариантами рефакторинга патча, чтобы его можно было отправить на рассмотрение и принять в исходную версию.
Есть еще много потенциальных оправданий. Когда вы отправляете сообщение об ошибке или исправлении, включите веское обоснование и ожидайте повторения и обсуждения. Мы понимаем, что ACK содержит некоторые исправления, особенно на ранних этапах GKI, когда все учатся работать над разработкой, но не могут для этого ослабить графики выпуска продуктов. Ожидайте, что требования к восходящему потоку со временем станут более строгими.
Требования к патчу
Патчи должны соответствовать стандартам кодирования ядра Linux, описанным в дереве исходного кода Linux , независимо от того, отправляются ли они в исходный код или на ACK. scripts/checkpatch.pl
запускается как часть предварительного тестирования Gerrit, поэтому запустите его заранее, чтобы убедиться, что он пройден. Чтобы запустить сценарий проверки патча с той же конфигурацией, что и при предварительном тестировании, используйте //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
, его можно перенести в соответствующий ACK на основе LTS (например, android12-5.4
и android11-5.4
для исправлений, исправляющих код, специфичный для Android). Отправка в android-mainline
позволяет проводить тестирование с новыми кандидатами на выпуск вышестоящей версии и гарантирует, что исправление будет в следующем ACK на основе LTS. Исключения включают случаи, когда исходный патч переносится в android12-5.4
(поскольку патч, скорее всего, уже находится в android-mainline
).
Восходящие патчи
Как указано в рекомендациях по участию , исходные исправления, предназначенные для ядер ACK, попадают в следующие группы (перечислены в порядке вероятности принятия).
-
UPSTREAM:
— Патчи, выбранные из «android-mainline», скорее всего, будут приняты в ACK, если есть разумный вариант использования. -
BACKPORT:
- Патчи из основной ветки разработки, которые не были тщательно отобраны и требуют модификации, также, скорее всего, будут приняты, если есть разумный вариант использования. -
FROMGIT:
— Патчи, выбранные из ветки сопровождающего при подготовке к отправке в основную ветку Linux, могут быть приняты, если наступит ближайший срок. Они должны быть обоснованы как по содержанию, так и по графику. -
FROMLIST:
- Патчи, которые были отправлены в LKML, но еще не были приняты в ветку сопровождающего, вряд ли будут приняты, если только обоснование не будет достаточно убедительным, чтобы патч был принят независимо от того, попадет ли он в исходную версию Linux (мы предполагаем, что что этого не будет). Должна существовать проблема, связанная с патчамиFROMLIST
, чтобы облегчить обсуждение с командой разработчиков ядра Android.
Патчи для Android
Если вы не можете внести необходимые изменения в исходную версию, вы можете попытаться отправить исправления вне дерева напрямую в ACK. Для отправки внесистемных исправлений необходимо создать в ИТ-отделе проблему, в которой будет указано исправление и обоснование того, почему исправление не может быть отправлено в исходную версию (примеры см. в предыдущем списке). Однако есть несколько случаев, когда код не может быть отправлен вверх по течению. Эти случаи рассматриваются следующим образом и должны соответствовать рекомендациям по публикации исправлений для Android и быть помечены префиксом ANDROID:
в теме.
Изменения в gki_defconfig
Все изменения CONFIG
в gki_defconfig
должны применяться как к версиям Arm64, так и к версиям x86, если CONFIG
не зависит от архитектуры. Чтобы запросить изменение параметра CONFIG
, создайте проблему в ИТ-отделе для обсуждения изменения. Любое изменение CONFIG
, которое влияет на интерфейс модуля ядра (KMI) после его заморозки, отклоняется. В случаях, когда партнеры запрашивают конфликтующие настройки для одной конфигурации, мы разрешаем конфликты путем обсуждения связанных ошибок.
Код, которого нет в исходной версии
Модификации кода, уже специфичные для Android, не могут быть отправлены в исходную версию. Например, даже несмотря на то, что драйвер связывателя поддерживается в исходном потоке, изменения в функциях наследования приоритета драйвера связывателя не могут быть отправлены в восходящий поток, поскольку они специфичны для 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 принимает хуки поставщиков, которые позволяют вызывать модули из основного кода ядра. Кроме того, ключевые структуры данных могут быть дополнены полями данных поставщика, которые доступны для хранения данных конкретного поставщика для реализации этих функций.
Перехватчики поставщиков бывают двух вариантов (обычные и ограниченные), основанные на точках трассировки (а не на событиях трассировки), к которым могут подключаться модули поставщиков. Например, вместо добавления новой функции sched_exit()
для ведения учета при выходе из задачи поставщики могут добавить в do_exit()
ловушку, к которой модуль поставщика может подключиться для обработки. Пример реализации включает следующие перехватчики поставщиков.
- Обычные перехватчики поставщиков используют
DECLARE_HOOK()
для создания функции точки трассировки с именемtrace_ name
гдеname
— это уникальный идентификатор трассировки. По соглашению имена обычных хуков поставщика начинаются сandroid_vh
, поэтому имя хукаsched_exit()
будетandroid_vh_sched_exit
. - Ограниченные перехватчики поставщиков необходимы в таких случаях, как перехватчики планировщика, когда присоединенная функция должна вызываться, даже если ЦП находится в автономном режиме или требует неатомарного контекста. Ограниченные перехватчики поставщиков не могут быть отсоединены, поэтому модули, подключенные к ограниченному перехватчику, никогда не смогут выгрузиться. Имена хуков ограниченного поставщика начинаются с
android_rvh
.
Чтобы добавить привязку поставщика, сообщите о проблеме в ИТ-отдел и отправьте исправления (как и в случае со всеми исправлениями для Android, проблема должна существовать, и вы должны предоставить обоснование). Поддержка перехватчиков поставщиков есть только в ACK, поэтому не отправляйте эти исправления в исходный 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 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.
Чтобы исправить этот тип ошибки сборки, примените эквивалентное исправление к включаемому вами заголовочному файлу привязки поставщика. Дополнительную информацию можно найти по адресу 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 модификацию ядра ядра. Создайте проблему в системе отслеживания проблем (IT), чтобы начать разговор.
Интерфейс программирования пользовательских приложений (UAPI)
- Заголовочные файлы UAPI. Изменения в файлах заголовков UAPI должны происходить в восходящем направлении, если только изменения не касаются интерфейсов, специфичных для Android. Используйте файлы заголовков, зависящие от поставщика, для определения интерфейсов между модулями поставщика и кодом пользовательского пространства поставщика.
- узлы sysfs. Не добавляйте новые узлы sysfs в ядро GKI (такие дополнения допустимы только в модулях поставщиков). Узлы sysfs, используемые библиотеками SoC и устройствами, а также кодом Java, составляющим платформу Android, могут быть изменены только совместимыми способами и должны быть изменены в восходящем направлении, если они не являются узлами sysfs, специфичными для Android. Вы можете создавать узлы sysfs для конкретного поставщика, которые будут использоваться пользовательским пространством поставщика. По умолчанию доступ к узлам sysfs из пользовательского пространства запрещен с помощью SELinux. Поставщик должен добавить соответствующие метки SELinux, чтобы разрешить доступ авторизованному программному обеспечению поставщика.
- Узлы DebugFS. Модули поставщиков могут определять узлы в
debugfs
только для отладки (посколькуdebugfs
не монтируется во время нормальной работы устройства).