La imagen genérica del kernel (GKI) reduce la fragmentación del kernel a través de una estrecha alineación con el kernel de Linux ascendente. Sin embargo, existen motivos válidos por los que algunos parches no se pueden aceptar en upstream y hay cronogramas de productos que se deben cumplir, por lo que algunos parches se mantienen en las fuentes del kernel común de Android (ACK) desde las que se compila el GKI.
Los desarrolladores deben enviar los cambios de código upstream con la lista de distribución del kernel de Linux (LKML) como primera opción y enviar los cambios de código a la rama android-mainline
de ACK solo cuando haya un motivo sólido por el que no sea viable hacerlo upstream. A continuación, se incluyen ejemplos de motivos válidos y cómo manejarlos.
El parche se envió a LKML, pero no se aceptó a tiempo para el lanzamiento del producto. Para controlar este parche, haz lo siguiente:
- Proporciona pruebas de que el parche se envió a la LKML y comentarios recibidos para el parche o una hora estimada a la que enviados de manera ascendente.
- Decide el procedimiento para implementar el parche en ACK y obtener su aprobación. ascendente y, luego, quitarlo de ACK cuando la versión ascendente se combina en ACK.
El parche define
EXPORT_SYMBOLS_GPL()
para un módulo de proveedor, pero no se pudo enviar upstream porque no hay módulos en el árbol que consuman ese símbolo. Para administrar este parche, proporciona detalles sobre por qué no se puede usar tu módulo que se enviaron en sentido upstream y las alternativas que consideraste para cada solicitud.El parche no es lo suficientemente genérico para la versión anterior y no hay tiempo para refactorizarlo antes del lanzamiento de un producto. Para controlar este parche, proporciona un tiempo estimado en el que se enviará un parche refactorizado a la fuente (el parche no se aceptará en ACK sin un plan para enviar un parche refactorizado a la fuente para su revisión).
El parche no se puede aceptar en la parte superior porque… <insertar motivo aquí>. Para administrar este parche, comunícate con el equipo de kernel de Android y trabajaremos con nosotros en opciones para refactorizar el parche a fin de que pueda enviarse para su revisión y aceptación ascendente.
Existen muchas más justificaciones posibles. Cuando envíes el error o el parche, incluye una justificación válida y espera que se realice una iteración y un debate. Reconocemos que el ACK lleva algunos parches, especialmente en las primeras fases de GKI, mientras todos aprenden a trabajar en upstream, pero no pueden relajar los cronogramas de productos para hacerlo. Se espera que los requisitos de integración ascendente sean más estrictos con el tiempo.
Requisitos de parches
Los parches deben cumplir con los estándares de codificación del kernel de Linux descritos en el
Árbol de fuentes de Linux,
ya sea que se envíen ascendentes
o a ACK. La secuencia de comandos scripts/checkpatch.pl
se ejecuta como parte de las pruebas previas al envío de Gerrit, así que ejecútala con anticipación para asegurarte de que se apruebe. Para ejecutar la secuencia de comandos checkpatch con la misma configuración que
la prueba previa al envío, usa //build/kernel/static_analysis:checkpatch_presubmit
.
Para obtener más información, consulta
build/kernel/kleaf/docs/checkpatch.md
Parches ACK
Los parches que se envían a ACK deben cumplir con los estándares de codificación del kernel de Linux y los lineamientos de contribución.
Debes incluir una etiqueta Change-Id
en el mensaje de confirmación. Si envías el parche a varias ramas (por ejemplo, android-mainline
y android12-5.4
), debes usar la misma Change-Id
para todas las instancias del parche.
Primero, envía parches al LKML para una revisión upstream. A continuación, se describen los estados de los parches:
- Se acepta en upstream y se combina automáticamente en
android-mainline
. - No se aceptó en upstream, envíalo a
android-mainline
con una referencia al envío anterior o una explicación de por qué no se envió a LKML.
Una vez que se acepta un parche en upstream o en android-mainline
, se puede llevar a la versión anterior al ACK basado en LTS correspondiente (como android12-5.4
y android11-5.4
para parches que corrigen el código específico de Android). El envío a android-mainline
permite realizar pruebas con nuevas versiones candidatas upstream y garantiza que el parche esté en el próximo ACK basado en LTS. Las excepciones incluyen los casos
en la que se brinda portabilidad a versiones anteriores de un parche upstream a android12-5.4
(porque el parche
probablemente ya estén en android-mainline
).
Parches ascendentes
Como se especifica en los lineamientos de contribución, los parches upstream destinados a los kernels de ACK se dividen en los siguientes grupos (enumerados en orden de probabilidad de aceptación).
UPSTREAM:
: Es probable que se apliquen los parches seleccionados de "android-mainline" acepta en ACK si existe un caso de uso razonable.BACKPORT:
: Es probable que también se acepten los parches de upstream que no seleccionen de forma clara y necesiten modificaciones si hay un caso de uso razonable.FROMGIT:
: Parches seleccionados especialmente de una rama de encargado de mantenimiento en preparación para enviar a la línea principal de Linux si hay una próxima fecha límite. Estos deben justificarse tanto para el contenido como para la programación.FROMLIST:
: Es probable que no se acepten los parches que se enviaron a LKML, pero que aún no se aceptaron en una rama de mantenimiento, a menos que la justificación sea lo suficientemente convincente como para que se acepte el parche, independientemente de si llega o no a Linux upstream (suponemos que no). Debe haber un problema asociado con los parches deFROMLIST
para facilitar el análisis con el equipo del kernel de Android.
Parches específicos de Android
Si no puedes conseguir los cambios necesarios en sentido ascendente, intenta enviar
de parches fuera del árbol para confirmar
directamente los cambios. Para enviar parches fuera del árbol, debes crear un problema en el equipo de TI que cite el parche y el motivo por el que no se puede enviar upstream (consulta la lista anterior para ver ejemplos).
Sin embargo, hay algunos casos en los que el código no se puede enviar a la fuente. Estos
casos se abarcan de la siguiente manera y deben seguir la contribución
lineamientos
para parches específicos de Android y se etiqueta con el prefijo ANDROID:
en el
sujeto.
Cambios en gki_defconfig
Todos los cambios de CONFIG
a gki_defconfig
se deben aplicar a las versiones arm64 y x86, a menos que CONFIG
sea específico de la arquitectura. Para solicitar un cambio en la configuración de CONFIG
, crea un problema en el equipo de TI para analizar el cambio. Se rechaza cualquier cambio de CONFIG
que afecte la interfaz del módulo del kernel (KMI) después de que se inmoviliza. En los casos en que los socios soliciten un conflicto
para una sola configuración, resuelvo los conflictos mediante un debate sobre
los errores relacionados.
Código que no existe en sentido ascendente
Las modificaciones en un código que ya es específico de Android no se pueden enviar de forma ascendente. Por ejemplo, aunque el controlador de Binder se mantiene en sentido ascendente, las modificaciones Las funciones de herencia prioritaria del controlador de Binder no se pueden enviar de manera ascendente. porque son específicos de Android. Sé explícito en el error y parchea por qué el código no se puede enviar de forma ascendente. De ser posible, divide los parches en partes Se pueden enviar partes específicas de Android y upstream que no se pueden enviar. para minimizar la cantidad de código fuera del árbol que se mantiene en ACK.
Otros cambios en esta categoría son las actualizaciones de los archivos de representación de KMI, las listas de símbolos de KMI, gki_defconfig
, las secuencias de comandos de compilación o configuración, y otras secuencias de comandos que no existen en upstream.
Módulos fuera del árbol
Linux upstream desalienta de forma activa la compatibilidad para compilar módulos fuera del árbol. Esta es una posición razonable, ya que los responsables de mantenimiento de Linux no garantizan la compatibilidad binaria o de origen en el kernel y no quieren admitir código que no esté en el árbol. Sin embargo, GKI sí garantiza las ABI módulos de proveedores, lo que garantiza que las interfaces de KMI sean estables para las la vida útil de un kernel. Por lo tanto, hay una clase de cambios para admitir módulos de proveedores que son aceptables para ACK, pero no para upstream.
Por ejemplo, considera un parche que agrega macros EXPORT_SYMBOL_GPL()
en el que los módulos que usan la exportación no están en el árbol de origen. Si bien debes intentar
solicitar EXPORT_SYMBOL_GPL()
ascendente y proporcionar un módulo que use el
exportado recientemente, si hay una justificación válida que indique por qué el módulo
no se envía de forma ascendente, puedes enviar el parche a ACK en su lugar. Tú
deberás incluir la justificación de por qué el módulo no puede subirse en el
problema. (No solicites la variante que no es de GPL, EXPORT_SYMBOL()
).
Parámetros de configuración ocultos
Algunos módulos en el árbol seleccionan automáticamente parámetros de configuración ocultos que no se pueden especificar en gki_defconfig
. Por ejemplo, CONFIG_SND_SOC_TOPOLOGY
se selecciona
automáticamente cuando se configura CONFIG_SND_SOC_SOF=y
. Para admitir la compilación de módulos fuera del árbol, GKI incluye un mecanismo para habilitar configuraciones ocultas.
Para habilitar una configuración oculta, agrega una sentencia select
en init/Kconfig.gki
para que
se selecciona automáticamente en función de la configuración del kernel CONFIG_GKI_HACKS_TO_FIX
que está habilitado en gki_defconfig
. Usa este mecanismo solo para parámetros de configuración ocultos.
Si la configuración no está oculta, se debe especificar en gki_defconfig
,
expresamente o como una dependencia.
Reguladores cargables
Para los frameworks de kernel (como cpufreq
) que admiten reguladores que se pueden cargar, puedes
puede anular el regulador predeterminado (como el regulador schedutil
de cpufreq
. En el caso de los frameworks (como el framework térmico) que no admiten controladores o gobernadores cargables, pero que aún requieren una implementación específica del proveedor, crea un problema en TI y consulta con el equipo del kernel de Android.
Trabajaremos contigo y con los responsables de la versión anterior para agregar la compatibilidad necesaria.
Hooks de proveedores
En versiones anteriores, podías agregar modificaciones específicas del proveedor directamente en la kernel principal. Esto no es posible con GKI 2.0 porque el código específico del producto se debe implementar en módulos y no se aceptará en los kernels principales upstream ni en ACK. Habilitar funciones con valor agregado en las que confían los socios con un impacto mínimo en el código del kernel principal, GKI acepta hooks del proveedor que permiten que se invoquen módulos. a partir del código principal del kernel. Además, las estructuras de datos clave se pueden rellenar con campos de datos del proveedor que están disponibles para almacenar datos específicos del proveedor para implementar estas funciones.
Los hooks de proveedor se presentan en dos variantes (normal y restringida) que se basan en
puntos de seguimiento (no eventos de seguimiento) a los que pueden adjuntarse los módulos del proveedor. Por ejemplo:
en lugar de agregar una nueva función sched_exit()
para hacer una contabilidad en una tarea
los proveedores pueden agregar un gancho en do_exit()
al que se puede adjuntar un módulo de proveedores
para su procesamiento. Una implementación de ejemplo incluye los siguientes hooks del proveedor.
- Los hooks normales del proveedor usan
DECLARE_HOOK()
para crear una función de punto de seguimiento con el nombretrace_name
, dondename
es el identificador único del seguimiento. Por convención, los nombres de hooks de proveedores normales comienzan conandroid_vh
, por lo que el nombre del hooksched_exit()
seríaandroid_vh_sched_exit
. - Los hooks de proveedores restringidos son necesarios para casos como los hooks de programador, en los que se debe llamar a la función adjunta, incluso si la CPU está sin conexión o requiere un contexto no atómico. Los hooks restringidos del proveedor no se pueden separar, por lo que los módulos
que se adjunten a un hook restringido nunca podrán descargarse. Los nombres de hooks de proveedores restringidos comienzan con
android_rvh
.
Para agregar un hook de proveedor, informa un problema en TI y envía parches (como con todos los parches específicos de Android, debe existir un problema y debes proporcionar una justificación). La compatibilidad con hooks de proveedor solo es ACK, así que no los envíes. parches a Linux de forma ascendente.
Cómo agregar campos de proveedor a las estructuras
Puedes asociar datos de proveedores con estructuras de datos clave agregando
Campos android_vendor_data
que usan las macros ANDROID_VENDOR_DATA()
. Por ejemplo, para admitir funciones de valor agregado, agrega campos a las estructuras como se muestra en la siguiente muestra de código.
Para evitar posibles conflictos entre los campos que necesitan los proveedores y los que necesitan los OEM, los OEM nunca deben usar campos declarados con macros ANDROID_VENDOR_DATA()
. En su lugar, los OEMs deben usar ANDROID_OEM_DATA()
para declarar campos 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 */
}
Define hooks del proveedor
Agrega hooks de proveedores al código del kernel como puntos de seguimiento declarándolos con DECLARE_HOOK()
o DECLARE_RESTRICTED_HOOK()
y, luego, agrégalos al código como un punto de seguimiento. Por ejemplo, para agregar trace_android_vh_sched_exit()
a la función del kernel do_exit()
existente, haz lo siguiente:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
En un principio, la función trace_android_vh_sched_exit()
solo verifica si hay algo conectado. Sin embargo, si un módulo de proveedor registra un controlador usando
register_trace_android_vh_sched_exit()
, se llama a la función registrada. El controlador debe estar al tanto del contexto con respecto a los bloqueos retenidos, el estado de RCS y otros factores. El hook se debe definir en un archivo de encabezado en el directorio include/trace/hooks
.
Por ejemplo, el siguiente código proporciona una posible declaración para trace_android_vh_sched_exit()
en el archivo 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>
Agrega el archivo de encabezado para crear una instancia de las interfaces requeridas para el hook del proveedor.
con la declaración de hook a drivers/android/vendor_hooks.c
y exporta el
símbolos. Por ejemplo, el siguiente código completa la declaración del hook 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);
NOTA: Las estructuras de datos que se usan en la declaración de hook deben
completamente definida para garantizar la estabilidad de la ABI. De lo contrario, no es seguro
deshagan las referencias de los punteros opacos o usen el struct en contextos de gran tamaño. La inclusión que proporciona la definición completa de esas estructuras de datos debe ir dentro de la sección #ifndef __GENKSYMS__
de drivers/android/vendor_hooks.c
. El encabezado
Los archivos en include/trace/hooks
no deben incluir el archivo de encabezado de kernel con el
definiciones de tipo para evitar cambios de CRC que dañen el KMI En su lugar, declara los tipos de reenvío.
Adjuntar a hooks del proveedor
Para usar hooks de proveedores, el módulo del proveedor debe registrar un controlador para el hook (por lo general, se hace durante la inicialización del módulo). Por ejemplo, el siguiente código muestra el controlador foo.ko
del módulo para 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);
...
}
Usa hooks de proveedores desde archivos de encabezado
Para usar hooks de proveedor de archivos de encabezado, es posible que debas actualizar el hook de proveedor
de encabezado para anular la definición de TRACE_INCLUDE_PATH
y evitar errores de compilación que indiquen
no se pudo encontrar un archivo de encabezado de punto de seguimiento. Por ejemplo:
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.
Para corregir este tipo de error de compilación, aplica la corrección equivalente al hook del proveedor. archivo de encabezado que incluyes. Para obtener más información, consulta 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
Definir UNDEF_TRACE_INCLUDE_PATH
le indica a include/trace/define_trace.h
que
anula la definición de TRACE_INCLUDE_PATH
después de crear los puntos de seguimiento.
Funciones principales del kernel
Si ninguna de las técnicas anteriores te permite implementar una función desde un módulo, debes agregarla como modificación específica de Android al kernel principal. Crea una entrada en la Herramienta de seguimiento de errores (TI) para iniciar la conversación.
Interfaz de programación de aplicaciones del usuario (UAPI)
- Archivos de encabezado de UAPI. Los cambios en los archivos de encabezado de la UAPI deben realizarse upstream, a menos que los cambios se realicen en interfaces específicas de Android. Usa archivos de encabezado específicos del proveedor para definir interfaces entre los módulos y el código del espacio de usuario del proveedor.
- nodos sysfs. No agregues nuevos nodos sysfs al kernel de GKI (estas adiciones solo son válidos en los módulos de proveedores). nodos sysfs utilizados por el SoC- Se pueden usar bibliotecas independientes del dispositivo y código Java que comprende el framework de Android. solo se pueden cambiar de maneras compatibles y debe cambiarse en sentido ascendente si no son nodos sysfs específicos de Android. Puedes crear nodos sysfs específicos del proveedor que usará el espacio de usuario del proveedor. De forma predeterminada, se rechaza el acceso a los nodos sysfs por parte del espacio de usuario con SELinux. Depende de la que el proveedor agregue las etiquetas de SELinux adecuadas para permitir el acceso software del proveedor de servicios en la nube.
- Nodos de DebugFS. Los módulos de proveedores pueden definir nodos en
debugfs
para solo para depuración (ya quedebugfs
no se activa durante el funcionamiento normal de la dispositivo).