Understanding eBPF and Its Use on Android for System Call Counting
The article explains eBPF’s evolution from packet filtering to a C‑compiled, sandboxed kernel framework, describes its core concepts of bytecode, JIT, and maps, and walks through building, loading, and using an Android eBPF program that counts system calls per PID via tracepoint hooks.
eBPF (extended Berkeley Packet Filter) expands the original BPF virtual machine used for packet filtering, allowing C code to be compiled into eBPF bytecode and executed in a sandboxed environment inside the Linux kernel.
Key differences from classic BPF include: (1) C language support compiled via LLVM; (2) additional hook types such as KPROBE and PERF; (3) a dedicated system call for loading programs and managing maps; (4) a generic map mechanism for key‑value storage in the kernel.
eBPF is primarily used for performance monitoring. By attaching to various kernel hooks, it can collect metrics ranging from overall system statistics to per‑function execution times.
Typical use cases illustrated include monitoring application/VM metrics, library performance, system‑call latency, filesystem, network, CPU scheduler, memory management, and interrupt performance.
The eBPF framework consists of three core concepts:
eBPF bytecode – compiled from C with clang --target=bpf and loaded into the kernel.
JIT compilation – translates bytecode to native machine code for faster execution.
Maps – key‑value stores that allow eBPF programs to exchange data with user‑space.
On Android, eBPF support is integrated into the build system via android.bp . The compiled *.o files are placed in /system/etc/bpf and loaded at boot by the bpfloader service, which creates corresponding entries under /sys/fs/bpf .
To implement a system‑call counting example:
Write a kernel‑space hook (e.g., a tracepoint for sys_enter and sys_exit ) in C, defining a map to store per‑PID call counts.
Compile the hook with clang --target=bpf to produce an object file.
Load the program on the device; the loader writes to /proc/sys/net/core/bpf_jit_enable and /proc/sys/net/core/bpf_jit_kallsyms to enable JIT and symbol access.
In user space, open the map via bpf_obj_get , wrap the file descriptor with BpfMap , and iterate over entries to display PID and call count.
The result appears as a list of PIDs followed by their respective system‑call invocation counts, demonstrating a complete eBPF workflow on Android.
OPPO Kernel Craftsman
Sharing Linux kernel-related cutting-edge technology, technical articles, technical news, and curated tutorials
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.