O Extended Berkeley Packet Filter (eBPF) é uma máquina virtual no kernel que executa programas eBPF fornecidos pelo usuário para estender a funcionalidade do kernel. Esses programas podem ser conectados a testes ou eventos no kernel e usados para coletar estatísticas úteis do kernel, monitorar e depurar. Um programa é carregado no kernel usando a bpf(2) e é fornecido pelo usuário como um blob binário de instruções de máquina eBPF. O sistema de compilação do Android tem suporte para compilar programas C para eBPF usando a sintaxe de arquivo de compilação simples descrita neste documento.
Mais informações sobre os componentes internos e a arquitetura do eBPF podem ser encontradas na página do eBPF de Brendan Gregg .
O Android inclui um carregador e uma biblioteca eBPF que carrega programas eBPF no momento da inicialização.
Carregador Android BPF
 Durante a inicialização do Android, todos os programas eBPF localizados em /system/etc/bpf/ são carregados. Esses programas são objetos binários criados pelo sistema de compilação do Android a partir de programas C e são acompanhados por arquivos Android.bp na árvore de origem do Android. O sistema de compilação armazena os objetos gerados em /system/etc/bpf e esses objetos se tornam parte da imagem do sistema.
Formato de um programa Android eBPF C
Um programa eBPF C deve ter o seguinte formato:
#include <bpf_helpers.h>
/* Define one or more maps in the maps section, for example
 * define a map of type array int -> uint32_t, with 10 entries
 */
DEFINE_BPF_MAP(name_of_my_map, ARRAY, int, uint32_t, 10);
/* this will also define type-safe accessors:
 *   value * bpf_name_of_my_map_lookup_elem(&key);
 *   int bpf_name_of_my_map_update_elem(&key, &value, flags);
 *   int bpf_name_of_my_map_delete_elem(&key);
 * as such it is heavily suggested to use lowercase *_map names.
 * Also note that due to compiler deficiencies you cannot use a type
 * of 'struct foo' but must instead use just 'foo'.  As such structs
 * must not be defined as 'struct foo {}' and must instead be
 * 'typedef struct {} foo'.
 */
DEFINE_BPF_PROG("PROGTYPE/PROGNAME", AID_*, AID_*, PROGFUNC)(..args..) {
   <body-of-code
    ... read or write to MY_MAPNAME
    ... do other things
   >
}
LICENSE("GPL"); // or other license
Onde:
-  name_of_my_mapé o nome da sua variável de mapa. Este nome informa ao carregador BPF o tipo de mapa a ser criado e com quais parâmetros. Essa definição de estrutura é fornecida pelo cabeçalhobpf_helpers.hincluído.
- PROGTYPE/PROGNAMErepresenta o tipo do programa e o nome do programa. O tipo do programa pode ser qualquer um dos listados na tabela a seguir. Quando um tipo de programa não está listado, não há uma convenção de nomenclatura estrita para o programa; o nome só precisa ser conhecido pelo processo que anexa o programa.
- PROGFUNCé uma função que, quando compilada, é colocada em uma seção do arquivo resultante.
| kprobe | Conecta o PROGFUNCa uma instrução do kernel usando a infraestrutura kprobe.PROGNAMEdeve ser o nome da função do kernel que está sendo kprobed. Consulte a documentação do kernel do kprobe para obter mais informações sobre o kprobes. | 
|---|---|
| ponto de rastreamento | PROGFUNCem um ponto de rastreamento.PROGNAMEdeve estar no formatoSUBSYSTEM/EVENT. Por exemplo, uma seção de ponto de rastreamento para anexar funções a eventos de alternância de contexto do agendador seriaSEC("tracepoint/sched/sched_switch"), em queschedé o nome do subsistema de rastreamento esched_switché o nome do evento de rastreamento. Verifique a documentação do kernel de eventos de rastreamento para obter mais informações sobre pontos de rastreamento. | 
| skfilter | O programa funciona como um filtro de soquete de rede. | 
| agendas | O programa funciona como um classificador de tráfego de rede. | 
| cgroupskb, cgroupsock | O programa é executado sempre que os processos em um CGroup criam um soquete AF_INET ou AF_INET6. | 
Tipos adicionais podem ser encontrados no código-fonte do Loader .
 Por exemplo, o programa myschedtp.c a seguir adiciona informações sobre o PID de tarefa mais recente executado em uma CPU específica. Este programa atinge seu objetivo criando um mapa e definindo uma função tp_sched_switch que pode ser anexada ao evento de rastreamento sched:sched_switch . Para obter mais informações, consulte Anexando programas a pontos de rastreamento .
#include <linux/bpf.h>
#include <stdbool.h>
#include <stdint.h>
#include <bpf_helpers.h>
DEFINE_BPF_MAP(cpu_pid_map, ARRAY, int, uint32_t, 1024);
struct switch_args {
    unsigned long long ignore;
    char prev_comm[16];
    int prev_pid;
    int prev_prio;
    long long prev_state;
    char next_comm[16];
    int next_pid;
    int next_prio;
};
DEFINE_BPF_PROG("tracepoint/sched/sched_switch", AID_ROOT, AID_SYSTEM, tp_sched_switch)
(struct switch_args *args) {
    int key;
    uint32_t val;
    key = bpf_get_smp_processor_id();
    val = args->next_pid;
    bpf_cpu_pid_map_update_elem(&key, &val, BPF_ANY);
    return 1; // return 1 to avoid blocking simpleperf from receiving events
}
LICENSE("GPL");
 A macro LICENSE é usada para verificar se o programa é compatível com a licença do kernel quando o programa faz uso de funções auxiliares BPF fornecidas pelo kernel. Especifique o nome da licença do seu programa em forma de string, como LICENSE("GPL") ou LICENSE("Apache 2.0") .
Formato do arquivo Android.bp
 Para que o sistema de compilação do Android compile um programa eBPF .c , você deve criar uma entrada no arquivo Android.bp do projeto. Por exemplo, para construir um programa eBPF C chamado bpf_test.c , faça a seguinte entrada no arquivo Android.bp do seu projeto:
bpf {
    name: "bpf_test.o",
    srcs: ["bpf_test.c"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
}
 Esta entrada compila o programa C resultando no objeto /system/etc/bpf/bpf_test.o . Na inicialização, o sistema Android carrega automaticamente o programa bpf_test.o no kernel.
Arquivos disponíveis em sysfs
 Durante a inicialização, o sistema Android carrega automaticamente todos os objetos eBPF de /system/etc/bpf/ , cria os mapas que o programa precisa e fixa o programa carregado com seus mapas no sistema de arquivos BPF. Esses arquivos podem então ser usados para interação adicional com o programa eBPF ou leitura de mapas. Esta seção descreve as convenções usadas para nomear esses arquivos e suas localizações no sysfs.
Os seguintes arquivos são criados e fixados:
- Para qualquer programa carregado, assumindo que - PROGNAMEé o nome do programa e- FILENAMEé o nome do arquivo eBPF C, o carregador do Android cria e fixa cada programa em- /sys/fs/bpf/prog_FILENAME_PROGTYPE_PROGNAME.- Por exemplo, para o exemplo de tracepoint - sched_switchanterior em- myschedtp.c, um arquivo de programa é criado e fixado em- /sys/fs/bpf/prog_myschedtp_tracepoint_sched_sched_switch.
- Para qualquer mapa criado, supondo que - MAPNAMEseja o nome do mapa e- FILENAMEseja o nome do arquivo eBPF C, o carregador do Android cria e fixa cada mapa em- /sys/fs/bpf/map_FILENAME_MAPNAME.- Por exemplo, para o exemplo de tracepoint - sched_switchanterior em- myschedtp.c, um arquivo de mapa é criado e fixado em- /sys/fs/bpf/map_myschedtp_cpu_pid_map.
- bpf_obj_get()na biblioteca Android BPF retorna um descritor de arquivo do arquivo- /sys/fs/bpf. Este descritor de arquivo pode ser usado para outras operações, como ler mapas ou anexar um programa a um tracepoint.
Biblioteca Android BPF
 A biblioteca Android BPF é denominada libbpf_android.so e faz parte da imagem do sistema. Essa biblioteca fornece ao usuário a funcionalidade eBPF de baixo nível necessária para criar e ler mapas, criar sondas, pontos de rastreamento e buffers de desempenho.
Anexando programas a pontos de rastreamento
Os programas Tracepoint são carregados automaticamente na inicialização. Após o carregamento, o programa tracepoint deve ser ativado seguindo estas etapas:
-  Chame bpf_obj_get()para obter o programafddo local do arquivo fixado. Para obter mais informações, consulte os Arquivos disponíveis em sysfs .
-  Chame bpf_attach_tracepoint()na biblioteca BPF, passando o programafde o nome do tracepoint.
 O exemplo de código a seguir mostra como anexar o sched_switch definido no arquivo de origem myschedtp.c anterior (a verificação de erros não é mostrada):
  char *tp_prog_path = "/sys/fs/bpf/prog_myschedtp_tracepoint_sched_sched_switch";
  char *tp_map_path = "/sys/fs/bpf/map_myschedtp_cpu_pid";
  // Attach tracepoint and wait for 4 seconds
  int mProgFd = bpf_obj_get(tp_prog_path);
  int mMapFd = bpf_obj_get(tp_map_path);
  int ret = bpf_attach_tracepoint(mProgFd, "sched", "sched_switch");
  sleep(4);
  // Read the map to find the last PID that ran on CPU 0
  android::bpf::BpfMap<int, int> myMap(mMapFd);
  printf("last PID running on CPU %d is %d\n", 0, myMap.readValue(0));
Lendo dos mapas
 Os mapas BPF suportam estruturas ou tipos complexos arbitrários de chave e valor. A biblioteca Android BPF inclui uma classe android::BpfMap que faz uso de modelos C++ para instanciar BpfMap com base na chave e no tipo de valor para o mapa em questão. O exemplo de código anterior demonstra o uso de um BpfMap com chave e valor como números inteiros. Os inteiros também podem ser estruturas arbitrárias.
 Assim, a classe BpfMap facilita a definição de um objeto BpfMap personalizado adequado para o mapa específico. O mapa pode então ser acessado usando as funções geradas de forma personalizada, que reconhecem o tipo, resultando em um código mais limpo.
 Para obter mais informações sobre BpfMap , consulte as fontes do Android .
Problemas de depuração
Durante o tempo de inicialização, várias mensagens relacionadas ao carregamento do BPF são registradas. Se o processo de carregamento falhar por qualquer motivo, uma mensagem de log detalhada será fornecida no logcat. Filtrar os logs do logcat por "bpf" imprime todas as mensagens e quaisquer erros detalhados durante o tempo de carregamento, como erros do verificador eBPF.
Exemplos de eBPF no Android
Os seguintes programas em AOSP fornecem exemplos adicionais de uso do eBPF:
- O programa - netdeBPF C é usado pelo daemon de rede (netd) no Android para vários propósitos, como filtragem de soquete e coleta de estatísticas. Para ver como este programa é usado, verifique as fontes do monitor de tráfego eBPF .
- O programa - time_in_stateeBPF C calcula a quantidade de tempo que um aplicativo Android gasta em diferentes frequências de CPU, que é usado para calcular a potência.
- No Android 12, o programa - gpu_memeBPF C rastreia o uso total de memória da GPU para cada processo e para todo o sistema. Este programa é usado para perfis de memória GPU.
