Generic Kernel Image (GKI) уменьшает фрагментацию ядра, тесно согласуясь с вышестоящим ядром Linux. Однако существуют веские причины, по которым некоторые исправления не могут быть приняты вышестоящим, и существуют графики выпуска продуктов, которые необходимо соблюдать, поэтому некоторые исправления поддерживаются в исходных кодах Android Common Kernel (ACK), из которых построен GKI.
Разработчики должны отправлять изменения кода в апстрим, используя Linux Kernel Mailing List (LKML) в качестве первого выбора, и отправлять изменения кода в ветку ACK android-mainline
только в том случае, если есть веская причина, по которой апстрим нежизнеспособен. Примеры обоснованных причин и способы их обработки перечислены ниже.
Патч был отправлен в LKML, но не был принят вовремя для выпуска продукта. Чтобы обработать этот патч:
- Предоставьте доказательства того, что исправление было отправлено в LKML, и были получены комментарии к исправлению, или предполагаемое время, к которому исправление будет отправлено в вышестоящую ветку.
- Определите порядок действий для размещения патча в ACK, получения его одобрения в вышестоящей ветке разработки, а затем изъятия его из ACK, когда окончательная версия вышестоящей ветки разработки будет объединена с ACK.
Патч определяет
EXPORT_SYMBOLS_GPL()
для модуля поставщика, но не может быть отправлен в восходящем направлении, поскольку нет модулей в дереве, которые используют этот символ. Чтобы обработать этот патч, предоставьте сведения о том, почему ваш модуль не может быть отправлен в восходящем направлении, и альтернативы, которые вы рассматривали перед тем, как сделать этот запрос.Патч недостаточно универсален для апстрима, и нет времени на его рефакторинг до выпуска продукта. Чтобы обработать этот патч, укажите предполагаемое время, к которому рефакторингованный патч будет отправлен в апстрим (патч не будет принят в ACK без плана отправки рефакторингованного патча в апстрим для проверки).
Патч не может быть принят апстримом, потому что... <вставьте причину здесь> . Чтобы справиться с этим патчем, свяжитесь с командой ядра Android и поработайте с нами над вариантами рефакторинга патча, чтобы его можно было отправить на рассмотрение и принять апстримом.
Есть еще много потенциальных обоснований. Когда вы отправляете свой баг или патч, включите обоснованное обоснование и ожидайте некоторой итерации и обсуждения. Мы признаем, что ACK несет некоторые исправления, особенно на ранних этапах GKI, пока все учатся работать в восходящем направлении, но не могут ослабить графики продукта, чтобы сделать это. Ожидайте, что требования к восходящему направлению станут более строгими с течением времени.
Требования к патчу
Патчи должны соответствовать стандартам кодирования ядра Linux, описанным в исходном дереве Linux , независимо от того, отправляются ли они в upstream или в 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.
После того, как патч принят либо в upstream, либо в android-mainline
, его можно перенести в соответствующий ACK на основе LTS (например, android12-5.4
и android11-5.4
для патчей, которые исправляют специфичный для Android код). Отправка в android-mainline
позволяет проводить тестирование с новыми кандидатами на релиз upstream и гарантирует, что патч будет в следующем ACK на основе LTS. Исключения включают случаи, когда патч upstream переносится в 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
, сценариев сборки или конфигурации или других сценариев, которые не существуют в исходной версии.
Модули вне дерева
Upstream Linux активно препятствует поддержке сборки модулей вне дерева. Это разумная позиция, учитывая, что разработчики Linux не дают гарантий относительно совместимости исходного кода ядра или двоичного кода и не хотят поддерживать код, которого нет в дереве. Однако GKI дает гарантии ABI для модулей поставщиков, гарантируя, что интерфейсы KMI будут стабильными в течение поддерживаемого срока службы ядра. Таким образом, существует класс изменений для поддержки модулей поставщиков, которые приемлемы для ACK, но неприемлемы для upstream.
Например, рассмотрим патч, который добавляет макросы 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()
для создания функции tracepoint с именемtrace_ name
, гдеname
— уникальный идентификатор трассировки. По соглашению, обычные имена хуков вендора начинаются сandroid_vh
, поэтому имя для хукаsched_exit()
будетandroid_vh_sched_exit
. - Ограниченные хуки поставщиков нужны для таких случаев, как хуки планировщика, где присоединенная функция должна быть вызвана, даже если ЦП находится в автономном режиме или требует неатомарного контекста. Ограниченные хуки поставщиков не могут быть отсоединены, поэтому модули, которые присоединены к ограниченному хуку, никогда не могут быть выгружены. Имена ограниченных хуков поставщиков начинаются с
android_rvh
.
Чтобы добавить хук поставщика, отправьте сообщение о проблеме в IT и отправьте исправления (как и в случае со всеми патчами, специфичными для 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()
к существующей функции ядра 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
не монтируется во время нормальной работы устройства).