mmap System Call
The mmap (memory map) system call maps files or devices into memory. This creates a direct mapping between a process's virtual address space and a file on disk or a region of physical memory. Accessing the mapped memory directly modifies or reads the underlying file or device, bypassing the need for standard read() and write() calls and minimizing user/kernel space context switches.
#include <sys/mman.h>
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
prot: Desired memory protection (e.g.,PROT_READ,PROT_WRITE).flags: Mapping type (MAP_SHAREDfor visible to other processes,MAP_PRIVATEfor copy-on-write).fd: File descriptor to map.offset: Starting point in the file.
File-Backed Mapping
File-backed mapping binds a region of virtual memory directly to a file on a storage device. When a process reads from the mapped memory, the OS automatically loads the corresponding pages from the disk into the page cache (if they aren't already there).
In AOSP, file-backed mappings are pervasive. For example, when Android loads an APK or a shared library (.so), the dynamic linker does not read the entire file into memory using read(). Instead, it uses mmap with MAP_PRIVATE to map the ELF segments directly into the process's address space. The pages are loaded on demand as the code executes, saving memory and decreasing startup time.
int fd = open("large_data.bin", O_RDONLY);
struct stat sb;
fstat(fd, &sb);
// Map the file read-only
void* mapped = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
// Read from 'mapped' as if it were a normal array
Anonymous Mapping
Anonymous mappings are not backed by any file. They are simply contiguous blocks of RAM initialized to zero. Anonymous mappings are typically used by memory allocators (like malloc or jemalloc in Android) to allocate large blocks of memory directly from the kernel.
To create an anonymous mapping, the MAP_ANONYMOUS (or MAP_ANON) flag is used, and the fd argument is set to -1.
// Allocate 1MB of anonymous, private memory
size_t size = 1024 * 1024;
void* mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Android's Dalvik/ART virtual machines use large anonymous mappings to reserve the Java heap space contiguous in virtual memory.
Memory-Mapped I/O in Drivers
Memory-Mapped I/O (MMIO) is a technique used in device drivers to communicate with hardware peripherals. Instead of using specialized I/O instructions, the CPU accesses hardware registers through standard memory addresses.
When an Android hardware driver (often running in the kernel, or a HAL running in user space via mechanisms like UIO) needs to interact with a GPU, camera ISP, or DSP, it maps the physical addresses of the device's control registers into virtual memory.
In user space, writing to these virtual addresses translates directly to electrical signals sent across the system bus to the hardware peripheral.
// Conceptual example of MMIO
volatile uint32_t* hardware_register = (uint32_t*)mmap(NULL, 4096,
PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, physical_offset);
// Write to the hardware register to trigger an action
*hardware_register = 0x01;