Skip to content

AOSP android-12.0.0_r3 revision Android Manifest repository with Event Stream Model changes

Notifications You must be signed in to change notification settings

esm-android/esm-manifest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 

Repository files navigation

Event Stream Model (ESM) for Android 12

A push-based event delivery mechanism for Android that replaces epoll-based input handling, designed to reduce latency, syscall overhead, and power consumption.

Support this project:

GitHub Sponsors PayPal Buy Me A Coffee Bitcoin Ethereum Solana Monero

đź’° Crypto Donations

Bitcoin (BTC)

3QVD3H1ryqyxhuf8hNTTuBXSbczNuAKaM8

Ethereum (ETH)

0xaFE28A1Dd57660610Ef46C05EfAA363356e98DC7

Solana (SOL)

6uWx4wuHERBpNxyWjeQKrMLBVte91aBzkHaJb8rhw4rn

Monero (XMR)

8C5aCs7Api3WE67GMw54AhQKnJsCg6CVffCuPxUcaKoiMrnaicyvDch8M2CXTm1DJqhpHKxtLvum9Thw4yHn8zeu7sj8qmC

Table of Contents

  1. What is ESM?
  2. Why ESM? (ESM vs epoll)
  3. Performance
  4. Quick Start
  5. Detailed Build Instructions
  6. Flashing to Device
  7. Verifying ESM is Working
  8. Technical Architecture
  9. Modified Components
  10. Troubleshooting
  11. Known Limitations
  12. License

What is ESM?

ESM (Event Stream Model) is a kernel-level innovation that fundamentally changes how Android handles input events. Instead of the traditional epoll model where processes wake on timeout to check for events, the kernel actively pushes events directly to waiting processes.

The Problem with epoll

Android's InputFlinger traditionally uses epoll to monitor input device file descriptors (/dev/input/event*). This approach requires:

1. Process calls epoll_wait() with a timeout
2. Process blocks until event arrives OR timeout expires
3. Timeout expires frequently, waking process to check for events
4. If events ready, process calls read() to get the event data
5. Process handles event
6. Repeat from step 1

Problems with this approach:

  • Frequent timeout wakeups: Process wakes up repeatedly even when no events are ready
  • Extra syscall overhead: Separate read() required after each epoll_wait() notification
  • Context switch overhead: Frequent transitions between kernel and user space
  • Poor event batching: Each file descriptor handled separately
  • Higher CPU usage: More wakeups and syscalls = more CPU cycles wasted

The ESM Solution (Push Model)

ESM provides a new system call interface that delivers events directly to userspace:

1. Process calls esm_wait() with a buffer - "Wake me when events arrive"
2. Process blocks in TASK_EV_WAIT state
3. Kernel pushes events directly to process's queue as they arrive
4. Kernel wakes process with events already in the buffer
5. Process handles events (no additional read() needed!)
6. Repeat from step 1

Benefits:

  • Lower latency: Events delivered directly, no extra read() syscall
  • Better batching: Multiple events from multiple devices delivered in single wakeup
  • Reduced CPU: Fewer context switches and syscalls
  • Simpler code: Single interface for registration and waiting
  • Lower power: Fewer wakeups means better battery life

Why ESM? (ESM vs epoll)

Syscall Comparison

epoll approach (traditional):

// Setup
int epfd = epoll_create1(EPOLL_CLOEXEC);
struct epoll_event ev = {.events = EPOLLIN, .data.fd = fd};
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

// Wait for events
struct epoll_event events[64];
int nfds = epoll_wait(epfd, events, 64, timeout);  // Syscall #1

// Read each event separately
for (int i = 0; i < nfds; i++) {
    struct input_event iev;
    read(events[i].data.fd, &iev, sizeof(iev));    // Syscall #2, #3, #4...
    // Process event...
}

ESM approach (push-based):

// Setup - register device once
esm_register(fd, (1 << EV_KEY) | (1 << EV_ABS));

// Wait AND receive events in one call
struct esm_event events[64];
int n = esm_wait(events, 64, timeout);             // Single syscall!

// Events already delivered - no read() needed
for (int i = 0; i < n; i++) {
    // Process events[i].event directly
}

Architectural Comparison

Metric epoll ESM
Syscalls per event batch epoll_wait + N Ă— read() Single esm_wait()
Context switches per wakeup 2 (notify + read) 1 (events in buffer)
Event batching Per-fd notification Cross-device batching

Architectural Benefits

  1. Push vs Pull Semantics: The kernel knows when events happen; pushing is inherently more efficient than polling
  2. Better Event Coalescing: Kernel batches events from multiple sources before waking the process
  3. Reduced Scheduler Pressure: Fewer wakeups = better power management
  4. Unified Interface: Single mechanism for all input events across all devices

Expected Performance Improvements

ESM's push-based architecture is designed to improve performance in the following areas:

Metric Expected Improvement Rationale
Input latency Lower Direct event push eliminates extra read() syscall
Syscall count Significantly fewer esm_wait() combines notification + data delivery
CPU usage Lower Fewer context switches and syscalls
Power consumption Lower Fewer wakeups enables deeper CPU sleep states

A comprehensive testing framework has been developed to empirically measure these improvements.


Quick Start

Prerequisites

  • Ubuntu 18.04+ (20.04/22.04 recommended)
  • 16GB+ RAM (32GB recommended)
  • 250GB+ free disk space
  • Google Pixel 5 with unlocked bootloader

Build Commands (4 Steps)

# 1. Initialize and sync (2-6 hours for download)
mkdir ~/android/esm && cd ~/android/esm
repo init -u https://github.com/esm-android/esm-manifest.git
repo sync -c -j8

# 2. Download proprietary binaries
wget https://dl.google.com/dl/android/aosp/google_devices-redfin-sp1a.210812.016.a1-fe9bc5fb.tgz
wget https://dl.google.com/dl/android/aosp/qcom-redfin-sp1a.210812.016.a1-28a4cf6d.tgz
tar -xzf google_devices-redfin-*.tgz && tar -xzf qcom-redfin-*.tgz
./extract-google_devices-redfin.sh  # Type "I ACCEPT"
./extract-qcom-redfin.sh            # Type "I ACCEPT"

# 3. Build (1-4 hours)
source build/envsetup.sh && lunch aosp_redfin-userdebug
export PRODUCT_KERNEL_VERSION=6.1
./build.sh -j$(nproc)

# 4. Flash
adb reboot bootloader
fastboot flashall -w

That's it! No patches to apply - ESM is already integrated.


Detailed Build Instructions

Step 1: Set Up Build Environment

Install Required Packages

sudo apt-get update
sudo apt-get install -y \
    git-core gnupg flex bison build-essential zip curl zlib1g-dev \
    gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev \
    x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev \
    libxml2-utils xsltproc unzip fontconfig python3 python-is-python3 \
    bc cpio rsync libssl-dev openjdk-11-jdk ccache

Configure Git

git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

Install Repo Tool

mkdir -p ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH=~/bin:$PATH
echo 'export PATH=~/bin:$PATH' >> ~/.bashrc

Set Up ccache (Recommended - speeds up rebuilds)

export USE_CCACHE=1
export CCACHE_DIR=$HOME/.ccache
ccache -M 50G
echo 'export USE_CCACHE=1' >> ~/.bashrc
echo 'export CCACHE_DIR=$HOME/.ccache' >> ~/.bashrc

Step 2: Download ESM-Enabled AOSP

mkdir -p ~/android/esm
cd ~/android/esm

# Initialize with ESM manifest (includes all ESM changes!)
repo init -u https://github.com/esm-android/esm-manifest.git

# Download source (~100 GB, 2-6 hours depending on connection)
repo sync -c -j8 --force-sync --no-clone-bundle

Tip: If download fails, just run the same command again to resume.

Step 3: Download Proprietary Binaries

Google Pixel devices require proprietary binaries for full functionality (GPU drivers, camera, etc.):

cd ~/android/esm

# Download driver binaries for Pixel 5
wget https://dl.google.com/dl/android/aosp/google_devices-redfin-sp1a.210812.016.a1-fe9bc5fb.tgz
wget https://dl.google.com/dl/android/aosp/qcom-redfin-sp1a.210812.016.a1-28a4cf6d.tgz

# Extract
tar -xzf google_devices-redfin-sp1a.210812.016.a1-fe9bc5fb.tgz
tar -xzf qcom-redfin-sp1a.210812.016.a1-28a4cf6d.tgz

# Run extraction scripts (read licenses, type "I ACCEPT" for each)
./extract-google_devices-redfin.sh
./extract-qcom-redfin.sh

Step 4: Build

cd ~/android/esm

# Set up build environment
source build/envsetup.sh

# Select build target (Pixel 5, userdebug variant)
lunch aosp_redfin-userdebug

# Set kernel version and build everything including kernel (1-4 hours)
export PRODUCT_KERNEL_VERSION=6.1
./build.sh -j$(nproc)

When successful, you'll see:

#### build completed successfully (01:23:45 (hh:mm:ss)) ####

Flashing to Device

Unlock Bootloader (One Time Only)

WARNING: This will factory reset your device!

  1. On device: Settings > About Phone > Tap "Build Number" 7 times
  2. On device: Settings > System > Developer Options > Enable "OEM unlocking"
  3. On device: Settings > System > Developer Options > Enable "USB debugging"
adb reboot bootloader
fastboot flashing unlock
# Use volume keys to select "Unlock", press power to confirm

Flash ESM Android

cd ~/android/esm

# Reboot to bootloader
adb reboot bootloader

# Flash all partitions (-w wipes userdata for clean install)
fastboot flashall -w

# Device will reboot automatically

First boot takes 2-5 minutes. ESM is now active!


Verifying ESM is Working

Check Kernel Has ESM

adb shell

# Verify ESM symbols exist in kernel
cat /proc/kallsyms | grep esm

You should see:

ffffffc010xxxxx T esm_register
ffffffc010xxxxx T esm_wait
ffffffc010xxxxx T esm_ctl
ffffffc010xxxxx T is_in_esm_wait
ffffffc010xxxxx T esm_push_event

Check ESM Initialization

adb shell dmesg | grep -i esm

Monitor ESM Activity

adb logcat | grep -i esm
# Touch the screen - you should see ESM log messages

Technical Architecture

System Overview

+------------------------------------------------------------------+
|                         USERSPACE                                 |
+------------------------------------------------------------------+
|  InputFlinger (system_server)                                     |
|    +------------------+                                           |
|    | EventHub         |                                           |
|    |  - esm_register() to register input devices                  |
|    |  - esm_wait() to receive batched events                      |
|    +------------------+                                           |
+------------------------------------------------------------------+
|                      SYSCALL INTERFACE                            |
|  esm_register(fd, event_mask)    - Register device for events     |
|  esm_wait(events, count, timeout) - Wait and receive events       |
|  esm_ctl(cmd, arg)               - Control ESM behavior           |
|  is_in_esm_wait(pid)             - Check if process is waiting    |
+------------------------------------------------------------------+
                              |
                              v
+------------------------------------------------------------------+
|                       KERNEL SPACE                                |
+------------------------------------------------------------------+
|  ESM Core (kernel/esm.c)                                          |
|    +------------------------------------------------+            |
|    | Per-Process ESM Context                        |            |
|    |  - Registered device list (hash table)         |            |
|    |  - Per-device event queues (kfifo, 128 events) |            |
|    |  - Wait queue for process blocking             |            |
|    +------------------------------------------------+            |
|                                                                   |
|  Input Drivers (evdev)                                            |
|    +------------------+                                           |
|    | Touch, Keyboard, |  ---> esm_push_event() --->  ESM Core     |
|    | Buttons, etc.    |                                           |
|    +------------------+                                           |
+------------------------------------------------------------------+

Event Flow

  1. Registration: InputFlinger opens /dev/input/event* and calls esm_register(fd, event_mask)
  2. Waiting: InputFlinger calls esm_wait(), blocking in TASK_EV_WAIT state
  3. Event Generation: Hardware generates input, driver calls esm_push_event()
  4. Distribution: ESM core finds registered contexts by inode, queues event
  5. Delivery: ESM wakes process, events already in buffer - no read() needed

Key Design Decisions

  • Inode-based matching: Events matched by inode (not fd), so fork() and multiple opens work correctly
  • Per-device queues: 128-event kfifo per registered device prevents cross-device blocking
  • TASK_EV_WAIT state: New task state lets watchdog distinguish ESM wait from hangs
  • Batch delivery: Multiple events from multiple devices returned in single esm_wait() call

Modified Components

ESM requires changes across the Android stack:

Kernel (kernel-msm-esm)

  • kernel/esm.c - Core ESM implementation (~1000 lines)
  • drivers/input/evdev.c - Event push integration
  • include/linux/sched.h - TASK_EV_WAIT state
  • arch/arm64 syscall tables - Four new syscalls

Bionic (aosp-bionic-esm)

  • libc/SYSCALLS.TXT - ESM syscall definitions
  • libc/include/sys/esm.h - Userspace API header

Frameworks (aosp-frameworks-native-esm, aosp-frameworks-base-esm)

  • services/inputflinger/reader/EventHub.cpp - ESM integration replacing epoll
  • Watchdog.java - ESM-aware ANR detection

Other (aosp-libcore-esm, aosp-build-esm, aosp-device-redfin-esm)

  • Java syscall constants
  • Build system integration
  • Device configuration

Troubleshooting

Build Fails: "esm_register not declared"

Bionic syscall headers not synced properly.

repo sync bionic
export PRODUCT_KERNEL_VERSION=6.1
./build.sh -j$(nproc)

Kernel Doesn't Have ESM Symbols

Wrong kernel was built/flashed.

# Rebuild kernel and boot image
export PRODUCT_KERNEL_VERSION=6.1
./build.sh -j$(nproc)
adb reboot bootloader
fastboot flash boot out/target/product/redfin/boot.img
fastboot reboot

Device Bootloops

Flash stock factory image to recover:

# Download from https://developers.google.com/android/images
# Extract and run:
./flash-all.sh

Touch Not Working

Check if ESM is receiving events:

adb shell dmesg | grep -i esm
adb logcat | grep -i inputflinger

If no ESM messages, kernel may have fallen back to epoll (check for epoll_wait in strace).


Known Limitations

  1. Input events only - ESM currently handles input events only, not sockets/files
  2. ARM64 only - Syscall numbers defined for ARM64 architecture
  3. Fixed queue size - 128 events per device; events dropped if queue full
  4. Single registration per FD - Re-registering overwrites previous registration
  5. Android 12 only - Would need porting for other Android versions

License

This project contains modifications to the Android Open Source Project (AOSP) and Linux kernel.

  • AOSP components: Apache License 2.0
  • Linux kernel components: GPL v2
  • Documentation: Apache License 2.0

Repository Structure

This manifest pulls from the following ESM-modified repositories:

Repository Description
esm-manifest This manifest
bionic Bionic with ESM syscalls
build Build system integration
device-redfin Pixel 5 device config
frameworks-base Framework with ESM watchdog
frameworks-native InputFlinger ESM integration
libcore Java ESM constants
kernel Kernel with ESM implementation

All other AOSP components are pulled from the official Google repositories at android-12.0.0_r3.


Target: Android 12 (android-12.0.0_r3) | Device: Google Pixel 5 (redfin) | Kernel: 4.19 (redbull)

About

AOSP android-12.0.0_r3 revision Android Manifest repository with Event Stream Model changes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published