Общий образ ядра (GKI) снижает фрагментацию ядра за счет тесного согласования с вышестоящим ядром Linux. Однако есть веские причины, по которым некоторые исправления не могут быть приняты в основную ветку, а также сроки выпуска продуктов, которые необходимо соблюдать, поэтому некоторые исправления поддерживаются в источниках общего ядра Android (ACK), на основе которых создается GKI.
Разработчики должны отправлять изменения кода в основной репозиторий, используя список рассылки ядра Linux (LKML) в качестве первого варианта, и отправлять изменения кода в ветку ACK android-mainline только в том случае, если есть веская причина, по которой основной репозиторий не подходит. Ниже приведены примеры допустимых причин и способы их обработки.
Патч был отправлен в LKML, но не был принят вовремя для выпуска продукта. Чтобы обработать это исправление:
- Предоставьте доказательства того, что исправление было отправлено в LKML и что к нему были получены комментарии, или укажите примерное время, когда исправление будет отправлено в основной репозиторий.
- Примите решение о том, как добавить исправление в ACK, получить одобрение вышестоящей организации, а затем удалить его из ACK, когда окончательная версия будет добавлена в ACK.
Патч определяет
EXPORT_SYMBOLS_GPL()для модуля поставщика, но не может быть отправлен в основной репозиторий, так как в дереве нет модулей, которые используют этот символ. Чтобы мы могли обработать исправление, укажите, почему вы не можете отправить модуль в основной репозиторий, и какие альтернативные варианты вы рассматривали.Патч недостаточно универсален для использования в upstream, и нет времени на его рефакторинг до выпуска рабочей версии. Чтобы применить этот патч, укажите примерное время, к которому будет отправлен переработанный патч (без плана отправки переработанного патча на рассмотрение патч не будет принят в ACK).
Патч не может быть принят вышестоящим проектом, потому что… <insert reason here>. Чтобы обработать этот патч, свяжитесь с командой разработчиков ядра 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.
После того как исправление будет принято в upstream или 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 (мы предполагаем, что нет). Чтобы упростить обсуждение с командой разработчиков ядра Android, с исправлениямиFROMLISTдолжна быть связана проблема.
Исправления для Android
Если вы не можете внести необходимые изменения в основную ветку, вы можете попытаться отправить исправления вне дерева непосредственно в ACK. Чтобы отправить исправления вне дерева, необходимо создать запрос в IT, в котором будет указано исправление и причина, по которой его нельзя отправить в основной репозиторий (примеры приведены в предыдущем списке).
Однако в некоторых случаях код нельзя отправить в основной репозиторий. В таких случаях необходимо следовать правилам отправки изменений для исправлений, относящихся к Android, и добавлять префикс ANDROID: в тему письма.
Изменения в gki_defconfig
Все изменения CONFIG в gki_defconfig должны быть применены к версиям arm64 и x86, если только CONFIG не относится к определенной архитектуре. Чтобы запросить изменение настройки CONFIG, создайте проблему в ИТ-отделе, чтобы обсудить изменение. Любые изменения,CONFIG которые влияют на интерфейс модуля ядра (KMI) после его заморозки, отклоняются. Если партнеры запрашивают для одной конфигурации противоречивые настройки, мы разрешаем конфликты, обсуждая связанные ошибки.
Код, которого нет в вышестоящем репозитории
Изменения в коде, который уже предназначен для Android, нельзя отправить в вышестоящий репозиторий. Например, хотя драйвер Binder поддерживается в основном репозитории, изменения в функциях наследования приоритета драйвера Binder нельзя отправить в основной репозиторий, поскольку они относятся к 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). Если фреймворк (например, фреймворк управления температурой) не поддерживает загружаемые регуляторы или драйверы, но требует реализации на уровне поставщика, создайте проблему в IT и проконсультируйтесь с командой разработчиков ядра Android.
Мы вместе с вами и разработчиками добавим необходимую поддержку.
Хуки поставщика
В предыдущих выпусках вы могли добавлять модификации, специфичные для поставщика, непосредственно в основное ядро. В GKI 2.0 это невозможно, поскольку код, относящийся к продукту, должен быть реализован в модулях и не будет принят в основных ядрах upstream или в 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(). Например, чтобы добавить в структуру поля для поддержки дополнительных функций, сделайте это так, как показано в следующем примере кода.
Чтобы избежать возможных конфликтов между полями, необходимыми поставщикам и производителям, производители не должны использовать поля, объявленные с помощью макросов 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, структуры данных, используемые в объявлении хука, должны быть полностью определены. В противном случае небезопасно разыменовывать непрозрачные указатели или использовать структуру в контекстах с указанием размера. Директива include, которая содержит полное определение таких структур данных, должна находиться в разделе #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. Создайте проблему в системе отслеживания ошибок, чтобы начать обсуждение.
User API
- Заголовочные файлы UAPI. Изменения в заголовочных файлах UAPI должны вноситься на более раннем этапе, если только они не касаются интерфейсов, предназначенных для Android. Используйте заголовочные файлы, относящиеся к определенному поставщику, чтобы задать интерфейсы между модулями поставщика и кодом пользовательского пространства поставщика.
- узлы sysfs. Не добавляйте новые узлы sysfs в ядро GKI (такие дополнения допустимы только в модулях поставщика). Узлы sysfs, используемые библиотеками и кодом Java, которые не зависят от SoC и устройства и входят в состав фреймворка Android, можно изменять только совместимым образом. Если это не узлы sysfs, относящиеся к Android, изменения должны быть внесены в основной репозиторий. Вы можете создавать узлы sysfs, предназначенные для использования в пространстве пользователя поставщика. По умолчанию доступ к узлам sysfs из пользовательского пространства запрещен с помощью SELinux. Поставщик должен добавить подходящие ярлыки SELinux, чтобы разрешить доступ авторизованному программному обеспечению поставщика.
- Узлы DebugFS. Модули поставщиков могут определять узлы в
debugfsтолько для отладки (посколькуdebugfsне монтируется во время нормальной работы устройства).