Opracowywanie kodu jądra dla GKI

Ogólny obraz jądra (GKI) ogranicza fragmentację jądra dzięki ścisłemu dopasowaniu używając jądra systemu Linux. Istnieją jednak pewne powody, Niektórych poprawek nie można zaakceptować na poziomie początkowym. Istnieją harmonogramy usług, muszą być spełnione, więc niektóre poprawki są zachowywane w komponencie Common Jądro (ACK) Androida źródeł, na których zbudowano GKI.

Deweloperzy muszą przesłać zmiany w kodzie na poziomie wyższym przy użyciu systemu pocztowego systemu Linux Podaj (LKML) jako pierwszą opcję i prześlij zmiany w kodzie do potwierdzenia Gałąź android-mainline ma istotny powód, dla którego nie jest opłacalne. Poniżej znajdziesz przykłady prawidłowych przyczyn i sposobów postępowania z nimi.

  • Poprawka została przesłana do LKML, ale nie została zaakceptowana na czas dla produktu wersji. Aby obsłużyć tę poprawkę:

    • Podaj dowody na to, że poprawka została przesłana do LKML, oraz komentarze lub szacowany czas, do którego przesłanego wyżej.
    • Zdecyduj, co zrobić, aby wprowadzić poprawkę w ramach potwierdzenia i poprosić o jej zatwierdzenie w górę i w dół, a następnie wycofać je z ACK, gdy ostateczna wersja nadrzędna scalone w ACK.
  • Poprawka definiuje EXPORT_SYMBOLS_GPL() dla modułu dostawcy, ale nie można została przesłana, ponieważ nie ma żadnych modułów w drzewie, które pochłaniały ten . Aby umożliwić obsługę tej poprawki, podaj szczegółowe informacje na temat tego, dlaczego nie można przesłane w górę i alternatywy brane pod uwagę przed jej utworzeniem użytkownika.

  • Poprawka nie jest wystarczająco ogólna dla wdrożenia z góry i nie ma czasu na dokonać ich refaktoryzacji przed wprowadzeniem produktu na rynek. Aby obsłużyć tę poprawkę, podaj szacowany czas, w jakim przesyła się poprawkę z refaktoryzowaną poprawka nie zostanie zaakceptowana w narzędziu ACK bez planu przesłania zmodyfikowanej wersji poprawkę do sprawdzenia).

  • Poprawka nie może zostać zaakceptowana przez zasadę nadrzędną, ponieważ... <wstaw powód tutaj>. Aby obsłużyć tę poprawkę, skontaktuj się z zespołem ds. jądra Androida i poproś o wspólnie wypracować możliwości refaktoryzacji poprawki, aby można ją było przesłać do sprawdzenia i akceptacji.

Potencjalnych uzasadnień jest znacznie więcej. Gdy zgłosisz błąd lub należy podać poprawne uzasadnienie i oczekiwać pewnej iteracji oraz dyskusji. Zdajemy sobie sprawę, że ACK wprowadza pewne poprawki, zwłaszcza na początku w kolejnych fazach GKI, kiedy wszyscy uczą się, jak pracować na zewnątrz, ale nie mogą się odprężyć. harmonogramy usług. Należy spodziewać się, że wymagania dotyczące nadrzędnych ciągów znaków będą rosnąć i ciągły czas.

Wymagania dotyczące poprawek

Poprawki muszą być zgodne ze standardami kodowania jądra systemu Linux opisanymi w Drzewo źródłowe Linuksa, niezależnie od tego, czy są przesyłane w górnej wersji, czy do potwierdzenia. scripts/checkpatch.pl jest uruchamiany w ramach testów wstępnych za pomocą Gerrit. by mieć pewność, że nie jest śledzona. Aby uruchomić skrypt poprawki z tą samą konfiguracją testów przed przesłaniem, użyj //build/kernel/static_analysis:checkpatch_presubmit. Więcej informacji: build/kernel/kleaf/docs/checkpatch.md.

Poprawki potwierdzenia

Poprawki przesłane do potwierdzenia muszą być zgodne ze standardami kodowania jądra Linuksa oraz z wytycznymi dotyczącymi przesyłania treści. Musisz dodać Change-Id tag w komunikacie zatwierdzenia; jeśli prześlesz poprawkę do wielu gałęzi (na np. android-mainline i android12-5.4), musisz użyć tego samego Change-Id w przypadku wszystkich instancji poprawki.

Najpierw prześlij poprawki do LKML, aby przeprowadzić kontrolę nadrzędną. Jeśli poprawka to:

  • Zaakceptowana w górę, zostanie scalona automatycznie z android-mainline.
  • Nie zaakceptowano przed przesłaniem, prześlij do android-mainline z odniesienie do zgłoszenia nadrzędnego lub wyjaśnienie, dlaczego tak się nie stało przesłane do LKML.

Po zaakceptowaniu poprawki w źródle lub w elemencie android-mainline można ją wprowadzić przeniesiony do odpowiedniego potwierdzenia opartego na LTS (np. android12-5.4 czy android11-5.4, aby pobrać poprawki poprawiające kod Androida). Przesyłam do android-mainline umożliwia testowanie z nowymi kandydatami wersji nadrzędnych oraz gwarantuje, że poprawka zostanie zastosowana w następnym Potwierdzeniem opartym na LTS. Wyjątki obejmują przypadki gdzie poprawka nadrzędna jest przeniesiona do systemu android12-5.4 (ponieważ poprawka jest prawdopodobnie znajduje się już w lokalizacji android-mainline).

Poprawki nadrzędne

Zgodnie z informacją w publikacji wytycznych, poprawki nadrzędne przeznaczone dla jąder ACK należą do następujących grup (wymienionych uporządkowane według prawdopodobieństwa zaakceptowania).

  • UPSTREAM: – poprawki wybrane z „android-mainline” prawdopodobnie będą do potwierdzenia, jeśli istnieje uzasadniony przypadek użycia.
  • BACKPORT: – poprawki z przepływu danych, które nie są wystarczająco wyraźne i potrzebują zmiany prawdopodobnie zostaną zaakceptowane, o ile występują uzasadnione użycie tych kwestii.
  • FROMGIT: – plamy wybrane w ramach przygotowań z oddziału konserwacyjnego do przesłania do Linuksa mainline może zostać zaakceptowana, jeśli . Muszą one być uzasadnione zarówno pod względem treści, jak i harmonogramu.
  • FROMLIST: – poprawki, które zostały przesłane do LKML, ale nie zostały akceptowana do gałęzi konserwacyjnej, ale raczej nie zostanie zaakceptowana, chyba że uzasadnienie jest na tyle przekonujące, że poprawka została zaakceptowana. niezależnie od tego, czy zostanie otwarty w systemie Linux (zakładamy, że nie). OK musi być problemem powiązanym z FROMLIST poprawkami, aby umożliwić dyskusję z zespołem ds. jądra Androida.

Poprawki dla Androida

Jeśli nie możesz przesłać wymaganych zmian na początku, spróbuj przesłać i gotowe, aby uzyskać potwierdzenie bezpośrednio. Wymagania dotyczące przesyłania poprawek spoza drzewa że tworzysz problem w dziale IT, podając poprawkę i uzasadnienie. poprawki nie można przesłać wyżej (przykłady znajdziesz na poprzedniej liście). W niektórych przypadkach nie można jednak przesłać kodu na wyższym poziomie. Te są opisane poniżej i muszą być zgodne z wytycznych w przypadku poprawek aplikacji na Androida i otaguj go prefiksem ANDROID: w tagu podmiotu danych.

Zmiany w konfiguracji gki_defconfig

Wszystkie zmiany (CONFIG) w elemencie gki_defconfig muszą zostać zastosowane zarówno w grupie arm64, w wersji x86, chyba że interfejs CONFIG jest związany tylko z architekturą. Aby poprosić o zmianę do ustawienia CONFIG, utwórz problem w dziale IT, aby omówić zmianę. Dowolne CONFIG zmiana, która wpływa na interfejs modułu jądra (KMI) po jego wprowadzeniu Zablokowane. W przypadkach, gdy partnerzy proszą o konflikt dla jednej konfiguracji, rozwiązujemy konflikty, omawiając i związanych z nimi błędach.

Kod, który nie istnieje na poziomie nadrzędnym

Nie można wysyłać zmian w kodzie, które są już przeznaczone tylko na Androida. Na przykład, mimo że sterownik separatora jest nadal utrzymywany na początku, modyfikacje do funkcji dziedziczenia priorytetowego sterownika powiązania nie można wysłać z niego do funkcji dziedziczenia bo są związane tylko z Androidem. Wyraźnie wskaż błąd i popraw, dlaczego nie można przesłać kodu z góry. Jeśli to możliwe, podziel łatki na części, mogą być przesyłane nadrzędne i przeznaczone tylko dla Androida, których nie można przesyłać w górę i w dół, by zminimalizować ilość kodu spoza drzewa utrzymywanego w odpowiedzi ACK.

Inne zmiany w tej kategorii to aktualizacje plików reprezentujących KMI, KMI listy symboli, gki_defconfig, skrypty kompilacji lub konfiguracje bądź inne skrypty nie występują w hierarchii powyżej.

Moduły zewnętrzne

Na urządzeniach z systemem Linux aktywnie zniechęca do tworzenia modułów zewnętrznych. Takie stanowisko jest rozsądne, ponieważ specjaliści od konserwacji Linuksa nie dają gwarancji dotyczące zgodności źródła w jądrze lub plików binarnych i nie chcą obsługiwać kodu których nie ma w drzewie. GKI gwarantuje jednak interfejs ABI modułów innych dostawców. Zapewni to stabilność interfejsów KMI od początku istnienia jądra systemu operacyjnego. W związku z tym pojawi się klasa zmian, dzięki którym dostawcy będą mogli które są akceptowane w ramach potwierdzenia, ale nie w przypadku modułów nadrzędnych.

Rozważ na przykład poprawkę dodającą makra EXPORT_SYMBOL_GPL(), w których modułów, które korzystają z eksportu, nie ma w drzewie źródłowym. Choć musisz spróbować żądania EXPORT_SYMBOL_GPL() z góry i dostarczenia modułu, który korzysta z metody nowo wyeksportowanego symbolu, jeśli istnieje ważne uzasadnienie, nie jest przesyłana wyżej, możesz przesłać poprawkę do ACK. Ty musi zawierać uzasadnienie, dlaczego nie można umieścić modułu nad nim w Google Cloud. (Nie wysyłaj żądania wersji innej niż GPL, EXPORT_SYMBOL()).

Ukryte konfiguracje

Niektóre moduły w drzewie automatycznie wybierają ukryte konfiguracje, których nie można określić w usłudze gki_defconfig. np. wybrano: CONFIG_SND_SOC_TOPOLOGY automatycznie po skonfigurowaniu CONFIG_SND_SOC_SOF=y. Do dostosowania (GKI) udostępnia mechanizm umożliwiający korzystanie z ukrytych konfiguracji.

Aby włączyć ukrytą konfigurację, dodaj w init/Kconfig.gki instrukcję select, dzięki czemu jest wybierany automatycznie na podstawie konfiguracji jądra CONFIG_GKI_HACKS_TO_FIX, która jest włączona w gki_defconfig. Używaj tego mechanizmu tylko do ukrytych konfiguracji. jeśli konfiguracja nie jest ukryta, musi być określona w gki_defconfig albo wprost lub jako zależność.

Ładowane gubernatorki

W przypadku platform jądra (takich jak cpufreq) obsługujących załadowane regulatory może zastąpić domyślny gubernator (taki jak schedutil w cpufreq). Dla: konstrukcje (takie jak struktura termiczna), które nie obsługują ładowalnych gubernatorów; lub sterowników, ale nadal wymagają implementacji konkretnego dostawcy, stwarza problem w IT i skonsultować się z zespołem ds. jądra Androida.

Skontaktujemy się z Tobą i zespołami ds. obsługi klienta, aby zapewnić niezbędne wsparcie.

Punkty zaczepienia dostawcy

We wcześniejszych wersjach można było dodawać modyfikacje specyficzne dla dostawcy bezpośrednio do i jednego jądra systemu operacyjnego. Nie jest to możliwe w GKI 2.0. Kod konkretnego produktu musi są zaimplementowane w modułach i nie będą akceptowane w głównych jądrach początkowych lub w języku ACK. Aby umożliwić partnerom korzystanie z dodatkowych funkcji przy minimalnym wpływie w przypadku podstawowego kodu jądra, GKI akceptuje punkty zaczepienia dostawcy umożliwiające wywoływanie modułów z kodu jądra systemu operacyjnego. Kluczowe struktury danych można też uzupełnić pola danych dostawcy, które służą do przechowywania danych konkretnego dostawcy w celu zaimplementowania tych funkcji.

Elementy przykuwające uwagę dostawcy występują w 2 wariantach (normalnej i z ograniczeniami) uwzględniających: punkty śledzenia (nie zdarzenia śledzenia), do których moduły dostawców mogą dołączać. Przykład: zamiast dodawać nową funkcję sched_exit() do księgowania zadania wyjścia, dostawcy mogą dodać w interfejsie do_exit() element zaczepienia, do którego moduł dostawcy może dołączyć do przetworzenia. Przykładowa implementacja zawiera podane niżej punkty zaczepienia dostawcy.

  • Zwykłe punkty zaczepienia dostawcy wykorzystują DECLARE_HOOK() do utworzenia funkcji logu czasu śledzenia. o nazwie trace_name, gdzie name to unikalny identyfikator śledzić. Zgodnie z tradycją normalne nazwy punktów zaczepienia dostawców zaczynają się od android_vh, więc nazwa haka sched_exit() będzie miała postać android_vh_sched_exit.
  • Ograniczone elementy zaczepienia dostawcy są potrzebne w przypadkach takich jak punkty zaczepienia algorytmu szeregowania, dołączona funkcja musi być wywołana nawet wtedy, gdy procesor jest offline lub wymaga w kontekście nieatomowym. Elementów zaczepienia dostawcy z ograniczonym dostępem nie można odłączać, więc modułów które przymocowane do ograniczonego zaczepu nigdy nie wyjdą. Z ograniczonym dostępem nazwy punktów zaczepienia dostawcy zaczynają się od android_rvh.

Aby dodać punkt zaczepienia dostawcy, zgłoś problem do działu IT i prześlij poprawki (tak jak w przypadku wszystkich poprawki aplikacji dla Androida muszą istnieć jakieś problemy i należy je udostępnić, uzasadnienie). Obsługa punktów zaczepienia dostawców jest dostępna tylko w ACK, więc nie wysyłaj ich poprawki na starszym Linuksie.

Dodaj pola dostawców do struktur

Dane dostawcy możesz powiązać z kluczowymi strukturami danych, dodając android_vendor_data pól używa makr ANDROID_VENDOR_DATA(). Dla: na przykład, aby obsługiwać funkcje o wartości dodanej, dołącz pola do struktur w następujący sposób w poniższym przykładowym kodzie.

Aby uniknąć potencjalnych konfliktów między polami wymaganymi przez dostawców i polami wymaganych przez producentów OEM, OEM nie może nigdy używać pól zadeklarowanych za pomocą Makra ANDROID_VENDOR_DATA(). Zamiast tego dostawcy OEM muszą używać ANDROID_OEM_DATA() zadeklarowanie android_oem_data pól.

#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 */
}

Zdefiniuj punkty zaczepienia dostawcy

Dodaj punkty zaczepienia dostawcy do kodu jądra jako punkty śledzenia, zadeklarując je za pomocą DECLARE_HOOK() lub DECLARE_RESTRICTED_HOOK(), a następnie dodaj je do kodu jako za pomocą punktów śledzenia. Aby na przykład dodać element trace_android_vh_sched_exit() do istniejącej funkcji jądra systemu do_exit():

#include <trace/hooks/exit.h>
void do_exit(long code)
{
    struct task_struct *tsk = current;
    ...
    trace_android_vh_sched_exit(tsk);
    ...
}

Funkcja trace_android_vh_sched_exit() początkowo sprawdza tylko to, czy coś Plik został załączony. Jeśli jednak moduł dostawcy rejestruje moduł obsługi za pomocą register_trace_android_vh_sched_exit(), zostaje wywołana zarejestrowana funkcja. moduł obsługi musi znać kontekst dotyczący wstrzymywanych blokad, stanu RCS i z innymi czynnikami. Punkt zaczepienia musi być zdefiniowany w pliku nagłówka w Katalog include/trace/hooks.

Na przykład ten kod zawiera możliwą deklarację dla trace_android_vh_sched_exit() w pliku 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>

Aby utworzyć instancje interfejsów wymagane przez punkt zaczepienia dostawcy, dodaj plik nagłówka z deklaracją webhooka do drivers/android/vendor_hooks.c i wyeksportuj symboli. Na przykład ten kod wypełnia deklarację Haczyk 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);

UWAGA: struktury danych używane w deklaracji webhooka muszą być w pełni zdefiniowane w celu zagwarantowania stabilności ABI. W przeciwnym razie nie jest bezpieczne usuwać nieprzezroczyste wskaźniki lub używać struktury w kontekstach o określonych rozmiarach. Zawierają który zawiera pełną definicję takich struktur danych, należy umieścić w Sekcja #ifndef __GENKSYMS__ z drivers/android/vendor_hooks.c. W nagłówku w include/trace/hooks nie powinny zawierać pliku nagłówka jądra z parametrem definicji typów, aby uniknąć zmian CRC, które zakłócają KMI. Zamiast tego przekazać dalej zadeklarować typy.

Dołącz do punktów zaczepienia dostawcy

Aby można było używać punktów zaczepienia dostawcy, moduł musi zarejestrować moduł obsługi tego punktu (zwykle odbywa się to podczas inicjowania modułu). Na przykład ten kod pokazuje moduł foo.ko modułu 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);
    ...
}

Używaj punktów zaczepienia dostawców z plików nagłówka

Aby używać punktów zaczepienia dostawcy w plikach nagłówka, może być konieczna aktualizacja punktu zaczepienia dostawcy pliku nagłówkowego, aby cofnąć definicję TRACE_INCLUDE_PATH i uniknąć błędów kompilacji wskazujących, nie udało się znaleźć pliku nagłówka punktu śledzenia. Na przykład

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.

Aby naprawić ten błąd kompilacji, zastosuj odpowiednią poprawkę do punktu zaczepienia dostawcy załączony plik nagłówka. Więcej informacji: 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

Definiowanie wartości UNDEF_TRACE_INCLUDE_PATH powoduje, że element include/trace/define_trace.h ma cofnij definicję TRACE_INCLUDE_PATH po utworzeniu punktów śledzenia.

Podstawowe funkcje jądra

Jeśli żadna z poprzednich metod nie pozwala wdrożyć funkcji z modułu, musisz dodać tę funkcję jako modyfikację związaną z Androidem jądro. Aby rozpocząć rozmowę, utwórz problem w narzędziu Issue Tracker (IT).

Interfejs programowania aplikacji użytkownika (UAPI)

  • Pliki nagłówków UAPI. Zmiany w Pliki nagłówków UAPI musi następować po przesłaniu, o ile zmiany nie dotyczą interfejsów wyłącznie Androida. Definiuj interfejsy za pomocą plików nagłówka odpowiednich dla danego dostawcy między modułami dostawcy a kodem przestrzeni użytkownika dostawcy.
  • węzłów sysfs. Nie dodawaj nowych węzłów sysfs do jądra GKI (takich mogą działać tylko w modułach dostawców). Węzły sysfs używane przez układy SoC- biblioteki niezależne od urządzenia i kod Java, które wchodzą w skład Androida; można zmieniać tylko w zgodny sposób. Trzeba je też zmienić na wyższym poziomie, jeśli nie są to węzły sysfs typowe dla Androida. Możesz tworzyć węzłów sysfs właściwych dla danego dostawcy, które mają być używane przez przestrzeń użytkownika dostawcy. Domyślnie dostęp do węzłów sysfs z przestrzeni użytkownika jest zabroniony przy użyciu SELinux. Zależy to tylko dostawca może dodać odpowiednie etykiety SELinux, aby umożliwić dostęp jego oprogramowania.
  • Węzły DebugFS. Moduły dostawcy mogą definiować węzły w: debugfs dla: tylko do debugowania (ponieważ interfejs debugfs nie jest podłączony podczas normalnego działania urządzenia).