Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Imagen de kernel genérica

El Común núcleos Android (ACK) son la base para todos los núcleos de productos Android. Los kernels de proveedores y dispositivos son posteriores a los ACK. Los proveedores agregan soporte para SoC y dispositivos periféricos modificando el código fuente del kernel y agregando controladores de dispositivo. Estas modificaciones pueden ser extensa, hasta el punto de que tanto como el 50% del código que se ejecuta en un dispositivo es el código fuera de árbol (no desde aguas arriba Linux o desde AOSP núcleos comunes).

Por lo tanto, un kernel de dispositivo se compone de:

  • Upstream: el kernel de Linux de kernel.org
  • AOSP: parches adicionales específicos de Android de los núcleos comunes de AOSP
  • Proveedor: parches de optimización y habilitación de periféricos y SoC de proveedores
  • OEM / dispositivo: controladores de dispositivos adicionales y personalizaciones

Casi todos los dispositivos tienen un kernel personalizado. Esta es la fragmentación del kernel.

La jerarquía del kernel de Android conduce a la fragmentación

Figura 1. Android jerarquía kernel lleva a la fragmentación

Los costos de la fragmentación

La fragmentación del kernel tiene varios efectos negativos en la comunidad de Android.

Las actualizaciones de seguridad requieren mucha mano de obra

Parches de seguridad citadas en el boletín de seguridad de Android (ASB) debe ser portado en cada uno de los núcleos de dispositivos. Sin embargo, debido a la fragmentación del kernel, es prohibitivamente caro propagar las correcciones de seguridad a los dispositivos Android en el campo.

Difícil de fusionar actualizaciones compatibles a largo plazo

Compatible (LTS) libera el largo plazo incluyen parches de seguridad y otras correcciones de errores críticos. Mantenerse al día con las versiones de LTS ha demostrado ser la forma más eficaz de proporcionar correcciones de seguridad. En los dispositivos Pixel, se descubrió que el 90% de los problemas de seguridad del kernel informados en ASB ya se habían solucionado para los dispositivos que se mantienen actualizados.

Sin embargo, con todas las modificaciones personalizadas en los núcleos del dispositivo, es difícil fusionar las correcciones LTS en los núcleos del dispositivo.

Inhibe las actualizaciones de lanzamiento de la plataforma Android

La fragmentación dificulta las nuevas funciones de Android que requieren que se agreguen cambios del kernel a los dispositivos en el campo. El código de Android Framework debe asumir que se admiten hasta cinco versiones del kernel y que no se realizaron cambios en el kernel para la nueva versión de la plataforma (Android 10 admite kernels 3.18, 4.4, 4.9, 4.14 y 4.19, que en algunos casos no se han realizado mejorado con nuevas funciones desde Android 8 en 2017).

Es difícil contribuir con los cambios del kernel a la versión ascendente de Linux

Con todos los cambios realizados en el kernel, la mayoría de los dispositivos insignia se envían con una versión del kernel que ya tiene al menos 18 meses de antigüedad. Por ejemplo, el kernel de 4.14 fue liberado por kernel.org en noviembre de 2017 y los primeros teléfonos Android con 4.14 granos transportados en la primavera de 2019.

Este largo retraso entre el lanzamiento del kernel ascendente y los productos dificulta que la comunidad de Android introduzca las funciones y controladores necesarios en los kernel ascendentes, por lo que es un desafío solucionar el problema de la fragmentación.

Arreglando la fragmentación: imagen de kernel genérica

Las direcciones de proyectos núcleo genérico de imagen (GKI) del núcleo mediante la unificación de la fragmentación del núcleo central y moviendo SoC y soporte de la placa fuera del núcleo central en módulos cargables. El GKI núcleo presenta un estables Kernel Módulo de interfaz (KMI) para los módulos del núcleo, por lo que los módulos y kernel se pueden actualizar de forma independiente.

El GKI:

  • Está construido a partir de las fuentes de ACK.
  • Es de una sola binario del núcleo más módulos de carga dinámica por la arquitectura, por versión LTS asociado (actualmente sólo arm64 para android11-5.4 y android12-5.4 ).
  • Está probado con todas las versiones de la plataforma Android que son compatibles con el ACK asociado. No hay obsolescencia de funciones durante la vida útil de una versión del kernel de GKI
  • Expone un establo KMI a los conductores dentro de un determinado LTS.
  • No contiene SoC- o código tablero-específica.

Así es como se ve un dispositivo Android con GKI implementado.

Arquitectura GKI

Arquitectura Figura 2. GKI

GKI es un cambio complejo que se implementará en varias etapas a partir de los kernels v5.4 en la versión de la plataforma Android 11.

GKI 1.0 - Requisitos de compatibilidad de GKI

Para algunos dispositivos que se inician con la versión de la plataforma Android 11, la compatibilidad de agudos requiere pruebas GKI para dispositivos que ejecutan kernels v5.4.

Particiones para pruebas de compatibilidad GKI

Figura 3. particiones para pruebas de compatibilidad GKI

GKI medios de compatibilidad que el dispositivo pasa el VTS y CTS-en-GSI pruebas + GKI con la imagen del sistema genérico (GSI) y el núcleo GKI instalado por la imagen de arranque GKI intermitente en el boot de imagen del sistema GSI partición y en el system partición. Los dispositivos se pueden enviar con un núcleo de producto diferente y pueden utilizar módulos de carga dinámica que GKI no proporciona. Sin embargo, tanto el producto como núcleos GKI deben cargar los módulos de las mismas vendor_boot y vendor particiones. Por lo tanto, todos los núcleos de productos deben tener la misma interfaz de módulo de núcleo binario (KMI). Los proveedores pueden ampliar la KMI para los núcleos de productos siempre que siga siendo compatible con la KMI de GKI. No es necesario que los módulos de los proveedores se puedan descargar en GKI 1.0.

GKI 1.0 goles

  • No introduzca regresiones en VTS o CTS cuando el kernel del producto sea reemplazado por el kernel GKI.
  • Reduzca la carga de mantenimiento del kernel para los fabricantes de equipos originales y los proveedores para mantenerse actualizados con los kernels comunes de AOSP.
  • Incluya los cambios centrales de Android en los núcleos, ya sea que un dispositivo se actualice a una nueva versión de la plataforma Android o se haya lanzado recientemente.
  • Nunca rompa el espacio de usuario de Android.
  • Separe los componentes específicos del hardware del núcleo central como módulos cargables.

GKI 2.0 - Productos GKI

Algunos dispositivos que de lanzamiento con el Android 12 (2021) versión de la plataforma que utilizan versiones del núcleo V5.10 o superior se requiere a buque con el núcleo GKI. Las imágenes de arranque firmadas estarán disponibles y se actualizarán periódicamente con LTS y correcciones de errores críticos. Debido a que se mantendrá la estabilidad binaria para la KMI, estas imágenes de arranque se pueden instalar sin cambios en las imágenes del proveedor.

Objetivos de GKI 2.0

  • No introduzca regresiones significativas de rendimiento o potencia con GKI.
  • Permita que los OEM proporcionen correcciones de seguridad del kernel y correcciones de errores (LTS) sin la participación del proveedor.
  • Reducir el costo de actualizar la versión principal del kernel para dispositivos (por ejemplo, de v5.10 al kernel LTS 2021).
  • Mantenga solo un binario de kernel GKI por arquitectura actualizando las versiones del kernel con un proceso claro de actualización.

Diseño GKI

Ramas del kernel de KMI

GKI núcleos se construyen a partir de las ramas del núcleo ACK KMI, que se describen con detalle en Android Común núcleos . El IGC se identifica de manera única por la versión del kernel y la versión de la plataforma Android, por lo que las ramas se denominan <androidRelease>-<kernel version> . Por ejemplo, el IGC rama 5.4 del kernel para Android 11 es el nombre android11-5.4. Se espera que para Android 12 (no comprometido y se muestra sólo para demostrar cómo el nuevo modelo de ramificación progresará en el futuro) habrá dos núcleos KMI adicional, android12-5.4 y un segundo núcleo basado en el kernel 5.10 LTS, publicado en diciembre 2020.

Jerarquía del kernel de KMI

La Figura 4 muestra la jerarquía de ramas para los núcleos KMI 5.10. android12-5.10 es el núcleo KMI correspondiente a Android 12 y android13-5.10 corresponde a Android T (AOSP experimental) (no comprometido y se muestra sólo para demostrar cómo el nuevo modelo de ramificación progresará en el futuro).

Jerarquía del kernel de KMI para 5.10

Jerarquía Figura 4. KMI kernel para 5,10

Como se muestra en la figura 4, el ciclo de ramas KMI a través de tres fases: desarrollo (dev), estabilización (stab), y congelado. Estas fases se describen en detalle en Android Común núcleos .

Una vez que se congela el kernel de KMI, no se aceptan cambios que rompan la KMI a menos que se identifique un problema de seguridad grave que no se pueda mitigar sin afectar la KMI estable. La rama permanece congelada durante toda su vida.

Las correcciones de errores y las funciones de los socios se pueden aceptar en una rama congelada siempre que no se rompa la KMI existente. La KMI se puede ampliar con nuevos símbolos exportados siempre que las interfaces que componen la KMI actual no se vean afectadas. Cuando se agregan nuevas interfaces a la KMI, se vuelven estables de inmediato y no pueden romperse con cambios futuros.

Por ejemplo, no se permite un cambio que agrega un campo a una estructura utilizada por una interfaz KMI porque cambia la definición de la interfaz:

struct foo {
  int original_field1;
  int original_field2;
  int new_field; // Not allowed
};

int do_foo(struct foo &myarg)
{
  do_something(myarg);
}
EXPORT_SYMBOL_GPL(do_foo);

Sin embargo, agregar una nueva función está bien:

struct foo_ext {
  struct foo orig_foo;
  int new_field;
};

int do_foo2(struct foo_ext &myarg)
{
  do_something_else(myarg);
}
EXPORT_SYMBOL_GPL(do_foo2);

Estabilidad KMI

Para lograr los objetivos de GKI, es fundamental mantener un KMI estable para los conductores. El kernel de GKI está construido y enviado en forma binaria, pero los módulos cargables por el proveedor se construyen en un árbol separado. El kernel y los módulos de GKI resultantes deben funcionar como si estuvieran construidos juntos. Para las pruebas de compatibilidad de GKI, la imagen de inicio que contiene el kernel se reemplaza con una imagen de inicio que contiene el kernel de GKI, y los módulos cargables en la imagen del proveedor deben funcionar correctamente con cualquiera de los kernel.

El KMI no incluye todos los símbolos en el kernel o incluso todos los más de 30,000 símbolos exportados. En cambio, los símbolos que pueden usar los módulos se enumeran explícitamente en un conjunto de archivos de lista de símbolos que se mantienen públicamente en la raíz del árbol del kernel. La unión de todos los símbolos en todos los archivos de lista de símbolos define el conjunto de símbolos KMI mantenido como estable. Un ejemplo de archivo de lista de símbolos es abi_gki_aarch64_db845c , que declara los símbolos necesarios para el 845c DragonBoard .

Solo los símbolos enumerados en una lista de símbolos y sus estructuras y definiciones relacionadas se consideran parte del KMI. Puede publicar cambios en sus listas de símbolos si los símbolos que necesita no están presentes. Una vez que las nuevas interfaces están en una lista de símbolos y, por lo tanto, forman parte de la descripción de KMI, se mantienen estables y no deben eliminarse de la lista de símbolos ni modificarse después de que se congele la rama.

Cada árbol del kernel de KMI tiene su propio conjunto de listas de símbolos. No se intenta proporcionar estabilidad ABI entre diferentes ramas del kernel de KMI. Por ejemplo, el IGC para android11-5.4 es completamente independiente de la IGC para android12-5.4 .

En general, la comunidad Linux ha fruncido el ceño en la idea de la estabilidad ABI en el núcleo para el núcleo principal. Frente a las diferentes cadenas de herramientas, configuraciones y un kernel de línea principal de Linux en constante evolución, no es factible mantener un KMI estable en la línea principal. Sin embargo, es posible en el entorno GKI altamente restringido. Las limitaciones son:

  • El KMI sólo es estable dentro del mismo núcleo LTS (por ejemplo, android11-5.4 ).
    • Sin estabilidad KMI se mantiene durante android-mainline .
  • Sólo el Clang cadena de herramientas específico suministrado en AOSP y definido para la rama correspondiente se utiliza para la construcción de núcleo y los módulos.
  • Solo los símbolos que se sabe que son utilizados por los módulos como se especifica en una lista de símbolos se monitorean para la estabilidad y se consideran símbolos KMI.
    • El corolario es que los módulos deben usar solo símbolos KMI. Esto se aplica al fallar las cargas del módulo si se requieren símbolos que no sean KMI.
  • Una vez que se congela la rama de KMI, ningún cambio puede romper la KMI, incluidos:
    • Cambios de configuración
    • Cambios en el código del kernel
    • Cambios en la cadena de herramientas (incluidas las actualizaciones)

Monitoreo de KMI

Herramientas de monitoreo ABI Control de estabilización KMI durante la prueba de presentar previamente. Los cambios que rompen el KMI fallan en las pruebas de preenvío y deben ser reelaborados para que sean compatibles. Estas herramientas están disponibles para los socios y el público para su integración en sus procesos de construcción. El equipo del kernel de Android utiliza estas herramientas para encontrar fallos de KMI durante el desarrollo y al fusionar versiones de LTS. Si se detecta una rotura de KMI durante una fusión de LTS, la KMI se conserva eliminando los parches infractores o refactorizando los parches para que sean compatibles.

El KMI se considera roto si un símbolo KMI existente se modifica de forma incompatible. Ejemplos:

  • Nuevo argumento agregado a una función KMI
  • Nuevo campo agregado a una estructura utilizada por una función KMI
  • Nuevo valor de enumeración agregado que cambia los valores de enumeraciones utilizados por una función KMI
  • Cambio de configuración que cambia la presencia de miembros de datos que afectan al KMI

Agregar nuevos símbolos no necesariamente rompe KMI, pero los nuevos símbolos que se utilizan deben agregarse a una lista de símbolos y a la representación ABI. De lo contrario, no se reconocerán los cambios futuros en esta parte de la KMI.

Se espera que los socios utilicen las herramientas de monitoreo ABI para comparar el KMI entre el kernel de su producto y el kernel GKI y asegurarse de que sean compatibles.

La última android11-5.4 binaria GKI kernel se puede descargar desde ci.android.com ( kernel_aarch64 construye).

Compilador único

Un cambio de compilador puede alterar el diseño de la estructura de datos del kernel interno que afecta a la ABI. Debido a que es fundamental mantener estable la KMI, la cadena de herramientas utilizada para construir el kernel de GKI debe ser completamente compatible con la cadena de herramientas utilizada para construir módulos de proveedores. El kernel de GKI está construido con la cadena de herramientas LLVM incluida en AOSP.

A partir de Android 10, todos los kernels de Android deben compilarse con una cadena de herramientas LLVM. Con GKI, la cadena de herramientas LLVM utilizada para construir núcleos de productos y módulos de proveedores debe generar la misma ABI que la cadena de herramientas LLVM de AOSP y los socios deben asegurarse de que la KMI sea compatible con el núcleo GKI.

La documentación de la construcción del kernel de Android se describe cómo se construye el núcleo GKI referencia. En particular, el procedimiento documentado garantiza que se utilicen la cadena de herramientas y la configuración correctas para construir el kernel. Se recomienda a los socios intermedios que utilicen las mismas herramientas para producir el kernel final para evitar incompatibilidades causadas por la cadena de herramientas u otras dependencias en el tiempo de compilación.

Configuraciones del kernel

El núcleo GKI se construye utilizando arch/arm64/configs/gki_defconfig . Debido a que estas configuraciones afectan a la KMI, las configuraciones de GKI se administran con mucho cuidado. Para los kernels de KMI congelados, las configuraciones solo se pueden agregar o eliminar si no hay impacto en la KMI.

El kernel de GKI debe configurarse para ejecutarse en un conjunto diverso de dispositivos. Por lo tanto, debe tener soporte integrado para todos los subsistemas y opciones requeridas para todos estos dispositivos, sin incluir los módulos cargables que se utilizan para habilitar el hardware. Los socios deben solicitar los cambios de configuración necesarios a los núcleos dev.

Cambios de arranque

Para facilitar una separación limpia entre los componentes GKI y proveedores, el boot partición contiene sólo componentes genéricos, incluyendo el núcleo y un disco RAM con módulos GKI. Se define una nueva versión del encabezado de arranque (v3) para indicar el cumplimiento de la arquitectura GKI. Google entrega la versión GKI de las imágenes de arranque y reemplaza la versión del proveedor de la imagen de arranque cuando se prueba la compatibilidad con GKI.

El disco de memoria para la primera etapa init , recovery , y fastbootd es un initramfs imagen compuesta de dos archivos CPIO que se concatenan por el cargador de arranque. El primer archivo cpio proviene de la nueva vendor_boot partición. El segundo viene del boot de la partición.

Aquí se proporciona un resumen de los cambios. Ver partición de inicio del proveedor para más detalles.

Partición de arranque

El boot de partición incluye una cabecera, núcleo, y una CPIO archivo de la parte genérica del disco RAM de arranque.

Con una v3 cabecera de arranque boot de partición, estas secciones de la antes boot partición ya no está presente son:

  • Cargador de arranque de segunda etapa: si un dispositivo tiene un cargador de arranque de segunda etapa, debe almacenarse en su propia partición.
  • DTB: El DTB se almacena en la partición de inicio del proveedor .

El boot la partición contiene un archivo cpio con los componentes GKI:

  • Módulos del núcleo GKI ubicados en /lib/modules/
  • first_stage_init y bibliotecas de los que depende
  • fastbootd y recovery (utilizado en A / B y A Virtual / dispositivos B)

La imagen de arranque GKI es proporcionado por Google y debe ser utilizado para las pruebas de compatibilidad GKI .

La última arm64 android11-5.4 boot.img es descargable desde ci.android.com en los aosp_arm64 artefactos de construcción de la aosp-master rama.

La última arm64 android11-5.4 imagen del núcleo ( Image.gz ) se puede descargar desde ci.android.com en los kernel_aarch64 artefactos de construcción de la aosp_kernel-common-android11-5.4 rama.

Partición de arranque del proveedor

El vendor_boot partición se introduce con GKI. Es A / B con Virtual A / B y consta de un encabezado, el disco ram del proveedor y el blob del árbol de dispositivos. El disco RAM del proveedor es un archivo CPIO que contiene los módulos del proveedor necesarios para el arranque del dispositivo. Esto incluye módulos para habilitar la funcionalidad crítica de SoC, así como los controladores de almacenamiento y visualización necesarios para iniciar el dispositivo y mostrar pantallas de presentación.

El archivo CPIO contiene:

  • La primera etapa init del proveedor módulos del núcleo se encuentra en /lib/modules/
  • modprobe config archivos ubicados en /lib/modules
  • modules.load archivo que indica los módulos a la carga durante la primera etapa- init

Requisito del cargador de arranque

El gestor de arranque debe cargar la imagen de disco RAM CPIO genérica (desde el boot la partición ) en la memoria inmediatamente después de la imagen CPIO proveedor disco RAM (del vendor_boot partición ). Después de la descompresión, el resultado es el ramdisk genérico superpuesto sobre la estructura de archivos del ramdisk del proveedor.

Prueba de compatibilidad GKI

Para el lanzamiento de la plataforma Android 11, los dispositivos lanzados con un kernel v5.4 deben ejecutar las pruebas VTS y CTS-on-GSI utilizando la imagen de arranque GKI proporcionada por Google.

Contribuyendo al kernel de GKI

El núcleo GKI se construye a partir de los PSE Común núcleos a partir de android11-5.4 . Todos los parches presentados deben cumplir con estas pautas de contribución , que documentan dos estrategias:

  1. Mejor: Hacer todos los cambios a aguas arriba de Linux. Si corresponde, retroceda a las versiones estables. Estos parches se fusionan automáticamente en los núcleos comunes de AOSP correspondientes. Si el parche ya está en versiones anteriores de Linux, publique un backport del parche que cumpla con los requisitos del parche a continuación.
  2. Menos bueno: Desarrollar sus parches de árbol (desde el punto de vista de Linux aguas arriba). A menos que los parches están arreglando un error de Android-específica, son muy poco probable que sea aceptado a menos que hayan sido coordinadas con kernel-team@android.com .

Para los socios que implementan GKI, puede haber razones válidas por las que se requieren parches fuera del árbol (especialmente si hay programas de silicio que deben cumplirse). Para estos casos, presentar una Buganizer tema.

Enviar los cambios a través GKI Gerrit al android-mainline rama primero y luego portado a otras ramas de liberación, según sea necesario.

No es necesario que el código fuente asociado con los módulos cargables se contribuya al árbol de fuentes del kernel de GKI; sin embargo, se recomienda encarecidamente enviar todos los controladores a la versión superior de Linux.

Solicitando backports de mainline

Generalmente, los parches de la línea principal que necesitan los socios de GKI se pueden exportar a los núcleos de GKI. Sube el parche a Gerrit siguiendo las directrices de contribución .

Si el parche se publicó en sentido ascendente, pero aún no se ha aceptado, se recomienda esperar hasta que se acepte. Si el programa no permite esperar a que se acepte el parche en sentido ascendente, presente un problema con Buganizer.

Agregar y eliminar configuraciones de GKI

Solicitar a la adición o eliminación de configuraciones en arch/arm64/configs/gki_defconfig , presentar un tema Buganizer indicando claramente la solicitud y la justificación. Si no hay un proyecto Buganizer accesible, publique el parche con el cambio de configuración en Gerrit y asegúrese de que el mensaje de confirmación indique claramente la razón por la que se necesita la configuración.

Los cambios de configuración en los núcleos KMI congelados no deben afectar a KMI.

Modificar el código del núcleo del núcleo

No se recomiendan las modificaciones al código del núcleo del núcleo en los núcleos comunes de AOSP. Primero envíe los parches a la versión superior de Linux y luego vuelva a exportarlos. Si hay una buena razón para un cambio en el núcleo del núcleo, presente un problema de Buganizer indicando claramente la solicitud y la justificación. No se aceptan funciones específicas de Android sin un problema de Buganizer. Enviar un correo electrónico a kernel-team@android.com si no se puede crear un problema Buganizer.

Exportación de símbolos mediante EXPORT_SYMBOL_GPL ()

No envíe parches en sentido ascendente que solo contengan exportaciones de símbolos. Para ser considerado para aguas arriba Linux, adiciones de EXPORT_SYMBOL_GPL() requieren un controlador modular en-árbol que utiliza el símbolo, por lo que incluyen el nuevo controlador o modificaciones de un controlador existente en el mismo conjunto de parches como la exportación.

Al enviar parches en sentido ascendente, el mensaje de confirmación debe contener una justificación clara de por qué el parche es necesario y beneficioso para la comunidad. Permitir que las exportaciones beneficien a los controladores o la funcionalidad fuera del árbol no es un argumento persuasivo para los mantenedores ascendentes.

Si por alguna razón, el parche no se puede enviar en sentido ascendente, presente un problema con Buganizer y explique por qué el parche no se puede enviar en sentido ascendente. Generalmente, los símbolos que son la interfaz compatible con un subsistema del kernel probablemente se aceptarán como exportaciones. Sin embargo, es poco probable que se acepten funciones auxiliares internas aleatorias y se le pedirá que refactorice su código para evitar su uso.

Agregar un símbolo a una lista de símbolos KMI

Las listas de símbolos de KMI deben actualizarse con los símbolos del kernel de GKI utilizados por los módulos de los proveedores. Debido a que solo los símbolos KMI se mantienen estables, GKI no permite que los módulos se carguen si se basan en un símbolo que no sea KMI.

El extract_symbols guión extrae los símbolos relevantes de un árbol de construcción del núcleo y se puede utilizar para actualizar una lista de símbolos KMI. Consulte la documentación del símbolo de la lista para obtener más detalles.