Образ ядра 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, когда все только учатся работать в режиме upstream, но не могут позволить себе ослабить графики разработки продукта ради этого. Ожидается, что требования к upstream-подготовке со временем станут более строгими.
Требования к патчу
Патчи должны соответствовать стандартам кодирования ядра 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-версию ACK (например, android12-5.4
и android11-5.4
для исправления кода, специфичного для Android). Отправка в android-mainline
позволяет проводить тестирование с новыми релиз-кандидатами основной ветки разработки и гарантирует попадание патча в следующую LTS-версию ACK. Исключения составляют случаи, когда патч основной ветки разработки портируется в android12-5.4
(поскольку он, вероятно, уже находится в android-mainline
).
Upstream-патчи
Как указано в руководстве по внесению изменений , патчи, предназначенные для ядер 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
, создайте запрос в ИТ-отделе для обсуждения этого изменения. Любое изменение CONFIG
, влияющее на интерфейс модулей ядра (KMI) после его заморозки, отклоняется. В случаях, когда партнёры запрашивают конфликтующие настройки для одной конфигурации, мы разрешаем конфликты путём обсуждения соответствующих ошибок.
Код, которого нет в исходном коде
Изменения кода, специфичные для Android, не могут быть отправлены в вышестоящий проект. Например, несмотря на то, что драйвер связывания поддерживается вышестоящий проект, изменения функций наследования приоритетов драйвера связывания не могут быть отправлены в вышестоящий проект, поскольку они специфичны для Android. В описании ошибки и исправления чётко укажите, почему код не может быть отправлен в вышестоящий проект. По возможности разделите исправления на части, которые можно отправить в вышестоящий проект, и части, специфичные для Android, которые нельзя отправить в вышестоящий проект, чтобы минимизировать объём кода, не входящего в дерево разработки и поддерживаемого в ACK.
Другие изменения в этой категории — это обновления файлов представления KMI, списков символов KMI, gki_defconfig
, скриптов сборки или конфигурации или других скриптов, которые не существуют в исходном коде.
Модули, не входящие в дерево
Разработчики Linux активно препятствуют поддержке сборки модулей, не входящих в дерево разработки. Это разумная позиция, учитывая, что разработчики Linux не гарантируют совместимость с исходным кодом ядра или двоичным кодом и не хотят поддерживать код, не входящий в дерево разработки. Однако GKI предоставляет гарантии ABI для модулей вендоров, обеспечивая стабильность интерфейсов KMI на протяжении всего срока службы ядра. Таким образом, существует класс изменений для поддержки модулей вендоров, которые приемлемы для ACK, но неприемлемы для разработчиков ветки разработки.
Например, рассмотрим патч, добавляющий макросы EXPORT_SYMBOL_GPL()
, в которых модули, использующие этот экспорт, отсутствуют в исходном дереве. Хотя вам необходимо попытаться запросить EXPORT_SYMBOL_GPL()
в исходном коде и предоставить модуль, использующий новый экспортированный символ, если есть веское обоснование того, почему модуль не отправляется в исходный код, вы можете отправить патч в ACK. Необходимо включить обоснование того, почему модуль не может быть отправлен в исходный код в проблеме. (Не запрашивайте вариант EXPORT_SYMBOL()
без лицензии GPL.)
Скрытые конфигурации
Некоторые модули, входящие в дерево сборки, автоматически выбирают скрытые конфигурации, которые невозможно указать в 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
.
Чтобы добавить вендор-хук, сообщите о проблеме в 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
не монтируется во время нормальной работы устройства).