A imagem genérica do kernel (GKI, na sigla em inglês) reduz a fragmentação do kernel ao se alinhar bem com o kernel upstream do Linux. No entanto, há motivos válidos para que alguns patches não sejam aceitos upstream, e há cronogramas de produtos que precisam ser atendidos. Portanto, alguns patches são mantidos nas fontes do kernel comum do Android (ACK, na sigla em inglês) em que o GKI é criado.
Os desenvolvedores precisam enviar mudanças de código upstream usando o Mailing do kernel do Linux
List (LKML) como a primeira escolha e enviar alterações de código para o sistema ACK
android-mainline
somente quando há um forte motivo pelo qual o upstream não está
viáveis. Confira abaixo exemplos de motivos válidos e como lidar com eles.
O patch foi enviado ao LKML, mas não foi aceito a tempo para um lançamento do produto. Para processar esse patch:
- Forneça evidências de que o patch foi enviado ao LKML e comentários recebidos para o patch ou um tempo estimado em que o patch foi enviado para upstream.
- Decida um curso de ação para implantar o patch no ACK, aprová-lo upstream e, em seguida, removê-lo do ACK quando a versão upstream final for fundida no ACK.
O patch define
EXPORT_SYMBOLS_GPL()
para um módulo do fornecedor, mas não pode ser enviado para upstream porque não há módulos na árvore que consumam esse símbolo. Para lidar com esse patch, forneça detalhes sobre os motivos pelos quais o módulo não pode ser enviado upstream e as alternativas que você considerou antes de fazer isso solicitação.O patch não é genérico o suficiente para upstream e não há tempo para fazer a refatoração antes do lançamento de um produto. Para processar esse patch, forneça um tempo estimado para que um patch reformulado seja enviado upstream. O patch não será aceito no ACK sem um plano para enviar um patch reformulado upstream para revisão.
O patch não pode ser aceito pelo upstream porque... <insert reason here>. Para processar esse patch, entre em contato com a equipe do kernel do Android e trabalhe com a gente nas opções para refatorar o patch para que ele possa ser enviado para revisão e aceito upstream.
Há muitas outras justificativas possíveis. Quando você envia seu bug ou incluir uma justificativa válida e esperar alguma iteração e discussão. Reconhecemos que a ACK tem alguns patches, especialmente nos primeiros de GKI enquanto todos estão aprendendo a trabalhar de forma upstream, mas não conseguem relaxar de produtos para fazer isso. Os requisitos de upstreaming vão ficar rigorosas ao longo do tempo.
Requisitos de patch
Os patches devem estar em conformidade com os padrões de codificação do kernel do Linux descritos na
Árvore de origem do Linux,
se eles foram enviados de forma upstream ou para ACK. O script scripts/checkpatch.pl
é executado como parte dos testes de pré-envio do Gerrit. Portanto, execute-o com antecedência para garantir
que ele seja aprovado. Para executar o script checkpatch com a mesma configuração do
teste de pré-envio, use //build/kernel/static_analysis:checkpatch_presubmit
.
Para mais detalhes, consulte
build/kernel/kleaf/docs/checkpatch.md.
Patches ACK
Os patches enviados para o ACK precisam estar em conformidade com os padrões de programação do kernel do Linux e
as diretrizes de contribuição.
Você precisa incluir um Change-Id
.
tag na mensagem de confirmação. se você enviar o patch para várias ramificações (por
exemplo, android-mainline
e android12-5.4
), é necessário usar a mesma
Change-Id
para todas as instâncias do patch.
Envie os patches para o LKML primeiro para uma análise upstream. Se o patch estiver:
- Aceito upstream. Ele é mesclado automaticamente em
android-mainline
. - Não foi aceito upstream. Envie para
android-mainline
com uma referência ao envio upstream ou uma explicação de por que ele não foi enviado para o LKML.
Depois que um patch é aceito na upstream ou no android-mainline
, ele pode ser
retornado ao ACK baseado em LTS apropriado (como android12-5.4
e
android11-5.4
para patches que corrigem o código específico do Android). Enviando para
O android-mainline
permite testes com novos candidatos a lançamento upstream e
garante que o patch esteja na próxima ACK baseada em LTS. As exceções incluem casos
em que um patch upstream é transferido de volta para android12-5.4
porque é provável
que ele já esteja em android-mainline
.
Patches upstream
Conforme especificado na contribuição diretrizes, patches upstream destinados a kernels ACK estão nos seguintes grupos (listados em ordem de probabilidade de serem aceitos).
UPSTREAM:
: os patches escolhidos a dedo de "android-mainline" provavelmente serão aceitos em ACK se houver um caso de uso razoável.BACKPORT:
: patches do upstream que não são selecionados corretamente e precisam modificação provavelmente serão aceitas se houver um uso razoável caso.FROMGIT:
: patches escolhidos de uma ramificação de mantenedor em preparação para envio à linha principal do Linux podem ser aceitos se houver um prazo próximo. Elas precisam ser justificadas para o conteúdo e a programação.FROMLIST:
- Patches que foram enviados ao LKML, mas não foram aceitos em uma ramificação de mantenedor, mas provavelmente não serão aceitos, a menos que a justificativa é convincente o suficiente para que o patch seja aceito. mesmo se ele chegar ou não no Linux upstream (presumimos que não haja). É preciso haver um problema associado aos patchesFROMLIST
para facilitar a discussão com a equipe do kernel do Android.
Patches específicos do Android
Se não for possível fazer as mudanças necessárias na upstream, tente enviar
patches fora da árvore para o ACK diretamente. O envio de patches fora da árvore exige
que você crie um problema no TI que cite o patch e o motivo pelo qual
ele não pode ser enviado para upstream (consulte a lista anterior para ver exemplos).
No entanto, em alguns casos, não é possível enviar o código upstream. Esses
casos são cobertos da seguinte maneira e precisam seguir as diretrizes
de contribuição
para patches específicos do Android e ser marcados com o prefixo ANDROID:
no
assunto.
Mudanças no gki_defconfig
Todas as mudanças de CONFIG
para gki_defconfig
precisam ser aplicadas às versões arm64 e
x86, a menos que a CONFIG
seja específica da arquitetura. Para solicitar uma alteração
para uma configuração CONFIG
, crie um problema na TI para discutir a mudança. Qualquer um
Mudança no CONFIG
que afeta a interface de módulo do kernel (KMI) após ser
congelado é rejeitada. Nos casos em que os parceiros solicitam configurações
conflitantes para uma única configuração, resolvemos os conflitos por meio de discussões sobre
os bugs relacionados.
Código que não existe na upstream
Modificações em um código que já é específico para Android não podem ser enviadas para upstream. Por exemplo, embora o driver de vinculação seja mantido upstream, as modificações nos recursos de herança de prioridade do driver de vinculação não podem ser enviadas upstream porque são específicas do Android. Seja explícito no bug e no patch sobre por que o código não pode ser enviado para upstream. Se possível, divida os patches em partes que podem ser enviadas partes upstream e específicas do Android que não podem ser enviadas upstream para minimizar a quantidade de código fora da árvore mantido em ACK.
Outras mudanças nessa categoria são atualizações de arquivos de representação de KMI, listas de
símbolos de KMI, gki_defconfig
, scripts de build ou configuração ou outros scripts
que não existem upstream.
Módulos fora da árvore
O upstream do Linux não recomenda ativamente o suporte à criação de módulos fora da árvore. Essa é uma posição razoável, já que os mantenedores do Linux não garantem a compatibilidade binária ou de origem no kernel e não querem oferecer suporte a códigos que não estão na árvore. No entanto, o GKI faz garantias de ABI para módulos do fornecedor, garantindo que as interfaces do KMI sejam estáveis para a duração de um kernel com suporte. Portanto, há uma classe de mudanças para oferecer suporte a módulos do fornecedor que são aceitáveis para ACK, mas não para upstream.
Por exemplo, considere um patch que adiciona macros EXPORT_SYMBOL_GPL()
em que os
módulos que usam a exportação não estão na árvore de origem. Embora seja necessário tentar
solicitar o upstream EXPORT_SYMBOL_GPL()
e fornecer um módulo que use o
símbolo exportado recentemente, se houver uma justificativa válida para o módulo
não ser enviado para o upstream, você poderá enviar o patch para ACK. Você
é necessário incluir a justificativa para o motivo pelo qual o módulo não pode ser enviado no
problema. Não solicite a variante não GPL, EXPORT_SYMBOL()
.
Configurações ocultas
Alguns módulos em árvore selecionam automaticamente configurações ocultas que não podem ser especificadas
em gki_defconfig
. Por exemplo, CONFIG_SND_SOC_TOPOLOGY
foi selecionado
automaticamente quando CONFIG_SND_SOC_SOF=y
é configurado. Para acomodar
a criação de módulos fora da árvore, a GKI inclui um mecanismo para ativar configurações ocultas.
Para ativar uma configuração oculta, adicione uma instrução select
em init/Kconfig.gki
para que ela
é selecionado automaticamente com base na configuração do kernel CONFIG_GKI_HACKS_TO_FIX
,
que é ativado em gki_defconfig
. Use esse mecanismo apenas para configurações ocultas.
Se a configuração não estiver oculta, ela precisará ser especificada em gki_defconfig
,
explicitamente ou como uma dependência.
Governadores carregáveis
Para frameworks do kernel (como cpufreq
) com suporte a gerenciadores carregáveis,
pode substituir o governador padrão (como o governador schedutil
de cpufreq
). Para
estruturas (como a estrutura térmica) que não oferecem suporte a governantes ou drivers
carregáveis, mas ainda exigem uma implementação específica do fornecedor, crie um problema
na TI e consulte a equipe do kernel do Android.
Vamos trabalhar com você e os mantenedores upstream para adicionar o suporte necessário.
Ganchos do fornecedor
Em versões anteriores, era possível adicionar modificações específicas de fornecedores diretamente no núcleo do núcleo. Isso não é possível com o GKI 2.0 porque o código específico do produto deve serão implementadas em módulos e não serão aceitas nos kernels principais upstream ou em ACK. Para ativar recursos de valor agregado em que os parceiros confiam com impacto mínimo no código do kernel principal, o GKI aceita ganchos de fornecedores que permitem que os módulos sejam invocados no código do kernel principal. Além disso, as estruturas de dados principais podem ser preenchidas com campos de dados do fornecedor que estão disponíveis para armazenar dados específicos do fornecedor e implementar esses recursos.
Os ganchos para fornecedores têm duas variantes (normal e restrita) que são baseadas
tracepoints (não eventos de trace) aos quais os módulos do fornecedor podem se anexar. Por exemplo,
em vez de adicionar uma nova função sched_exit()
para fazer uma contabilidade na saída
da tarefa, os fornecedores podem adicionar um gancho em do_exit()
ao qual um módulo do fornecedor pode se conectar
para processamento. Um exemplo de implementação inclui os seguintes acionadores do fornecedor.
- Os hooks normais de fornecedores usam
DECLARE_HOOK()
para criar uma função de tracepoint. com o nometrace_name
, em quename
é o identificador exclusivo do rastros. Por convenção, os nomes de hook de fornecedor normais começam comandroid_vh
. Portanto, o nome do hooksched_exit()
seriaandroid_vh_sched_exit
. - Os hooks restritos do fornecedor são necessários para casos como hooks de agendador em que
a função anexada precisa ser chamada mesmo que a CPU esteja off-line ou exija
um contexto não atômico. Os hooks restritos de fornecedores não podem ser desconectados, portanto, os módulos
anexados a um gancho restrito nunca podem ser descarregados. Os nomes de
hooks de fornecedores restritos começam com
android_rvh
.
Para adicionar um gancho de fornecedor, registre um problema na TI e envie patches. Como acontece com todos os patches específicos do Android, é necessário que um problema exista e que você forneça uma justificativa. O suporte a ganchos do fornecedor está disponível apenas no ACK. Portanto, não envie esses patches para o Linux upstream.
Adicionar campos do fornecedor às estruturas
É possível associar dados do fornecedor a estruturas de dados importantes adicionando campos android_vendor_data
usando as macros ANDROID_VENDOR_DATA()
. Por
exemplo, para oferecer suporte a recursos de valor agregado, anexe campos a estruturas, conforme mostrado
no exemplo de código abaixo.
Para evitar possíveis conflitos entre campos exigidos por fornecedores e campos
exigido pelos OEMs, eles nunca poderão usar campos declarados usando
ANDROID_VENDOR_DATA()
de macros. Em vez disso, os OEMs precisam 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 */
}
Definir hooks do fornecedor
Adicionar hooks de fornecedores ao código do kernel como tracepoints declarando-os com o uso do
DECLARE_HOOK()
ou DECLARE_RESTRICTED_HOOK()
e, em seguida, adicioná-las ao código como
um tracepoint. Por exemplo, para adicionar trace_android_vh_sched_exit()
ao
função do kernel do_exit()
atual:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
A função trace_android_vh_sched_exit()
verifica inicialmente apenas se algo
está anexado. No entanto, se um módulo do fornecedor registrar um gerenciador usando
register_trace_android_vh_sched_exit()
, a função registrada será chamada. O
gerenciador precisa estar ciente do contexto em relação a bloqueios mantidos, estado de RCS e
outros fatores. O gancho precisa ser definido em um arquivo principal no
include/trace/hooks
.
Por exemplo, o código a seguir fornece uma possível declaração para
trace_android_vh_sched_exit()
no arquivo 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>
Para instanciar as interfaces necessárias para o hook de fornecedor, adicione o arquivo de cabeçalho.
com a declaração de hook para drivers/android/vendor_hooks.c
e exportar o
símbolos. Por exemplo, o código a seguir conclui a declaração do
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);
OBSERVAÇÃO: as estruturas de dados usadas na declaração do hook precisam ser
totalmente definidos para garantir a estabilidade da ABI. Caso contrário, não é seguro
desreferencie os ponteiros opacos ou use a estrutura em contextos dimensionados. A inclusão
que fornece a definição completa dessas estruturas de dados,
Seção #ifndef __GENKSYMS__
de drivers/android/vendor_hooks.c
. Cabeçalho
os arquivos em include/trace/hooks
não devem incluir o arquivo de cabeçalho do kernel com o
definições de tipo para evitar alterações de CRC que possam corromper o KMI. Em vez disso, encaminhe
declarar os tipos.
Anexar aos hooks do fornecedor
Para usar os Hooks do fornecedor, o módulo do fornecedor precisa registrar um gerenciador para o hook,
normalmente feito durante a inicialização do módulo. Por exemplo, o código a seguir
mostra o gerenciador foo.ko
do 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);
...
}
Usar ganchos de fornecedor a partir de arquivos principais
Para usar ganchos de fornecedor a partir de arquivos de cabeçalho, pode ser necessário atualizar o gancho de fornecedor
arquivo principal para remover a definição de TRACE_INCLUDE_PATH
para evitar erros de build que indicam
um arquivo de cabeçalho do ponto de rastreamento não foi encontrado. Por exemplo:
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 corrigir esse tipo de erro de build, aplique a correção equivalente ao hook de fornecedor arquivo de cabeçalho que está sendo incluído. Para mais informações, consulte 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
A definição de UNDEF_TRACE_INCLUDE_PATH
informa a include/trace/define_trace.h
para
desdefinir TRACE_INCLUDE_PATH
após a criação dos pontos de rastreamento.
Principais recursos do kernel
Se nenhuma das técnicas anteriores permitir a implementação de um recurso de um módulo, adicione o recurso como uma modificação específica do Android no grão Crie um problema no Issue Tracker (TI) para iniciar a conversa.
Interface de programação de aplicativos do usuário (UAPI)
- Arquivos de cabeçalho UAPI. Mudanças no Arquivos de cabeçalho UAPI precisam ocorrer upstream, a menos que as mudanças sejam em interfaces específicas do Android. Use arquivos de cabeçalho específicos do fornecedor para definir interfaces entre os módulos do fornecedor e o código do espaço do usuário do fornecedor.
- nós sysfs. Não adicione novos nós sysfs ao kernel do GKI. Essas adições são válidas apenas em módulos de fornecedores. Os nós sysfs usados pelas bibliotecas não dependentes de SoC e dispositivo e pelo código Java que compreende o framework do Android podem ser alterados apenas de maneiras compatíveis e precisam ser alterados upstream se não forem nós sysfs específicos do Android. Você pode criar nós sysfs específicos do fornecedor a serem usados pelo espaço do usuário do fornecedor. Por padrão, o acesso aos nós sysfs por espaço do usuário é negado ao usar o SELinux. Cabe ao fornecedor adicione os rótulos SELinux apropriados para permitir o acesso por o software de um fornecedor.
- Nós do DebugFS. Os módulos do fornecedor podem definir nós em
debugfs
apenas para depuração, já quedebugfs
não é montado durante a operação normal do dispositivo.