Android Emulator Development, Anbox, & Waydroid

Debugging Native Code in Custom AOSP ROMs Running on Android Emulators: A Practical Walkthrough

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction

Debugging native code within custom Android Open Source Project (AOSP) ROMs running on emulators presents unique challenges compared to standard app development. When working deep within the Android framework, system services, or custom HALs, traditional Android Studio debugging might fall short. This guide provides a practical, expert-level walkthrough on setting up a robust debugging environment using GDB (or LLDB) to inspect native processes directly on an Android emulator flashed with your custom AOSP build.

Prerequisites for Native Debugging

Before diving into the debugging process, ensure you have the following components and expertise:

  • AOSP Source Code: A complete synchronized AOSP source tree.
  • Build Environment: A Linux machine configured for AOSP compilation (Ubuntu 18.04/20.04 recommended).
  • Android SDK/Platform Tools: Essential for adb and emulator commands.
  • GNU Debugger (GDB) or LLDB: Installed on your host machine. LLDB is often preferred for newer AOSP versions due to its tighter integration with Clang/LLVM.
  • Familiarity with Shell: Command-line proficiency is crucial for `adb` and debugger interactions.

Building a Custom AOSP ROM for Emulator Debugging

The first step involves building an AOSP ROM specifically configured for emulation and debugging. The `userdebug` build variant is critical as it includes debugging symbols and enables root access via adb, which is necessary for pushing debugging tools and attaching debuggers.

1. Set Up Your Build Environment

Navigate to your AOSP source directory:

cd /path/to/your/aosp/source

2. Configure the Build Target

For emulator builds, you’ll typically select a target like `aosp_emu-userdebug` (for x86) or `aosp_x86_64-userdebug` (for 64-bit x86 emulators). This example will use `aosp_x86_64-userdebug`.

source build/envsetup.shlunch aosp_x86_64-userdebug

The `userdebug` variant provides root access with adb and includes debugging symbols, which are vital for effective native debugging.

3. Compile AOSP

Start the compilation process. Using `make -jX` where X is 1.5-2 times your CPU cores significantly speeds up the build.

make -j$(nproc --all)

This process can take several hours depending on your hardware. Once complete, your build artifacts will be located in the `out/target/product/generic_x86_64` directory (or similar, based on your `lunch` target).

Launching the Emulator with Your Custom ROM

With the custom ROM built, you can now launch it using the Android Emulator. Ensure your `emulator` binary is in your PATH or specify its full path.

emulator -kernel /path/to/your/aosp/source/prebuilts/qemu-kernel/x86_64/kernel-qemu-x86_64 -system /path/to/your/aosp/source/out/target/product/generic_x86_64/system.img -data /path/to/your/aosp/source/out/target/product/generic_x86_64/userdata.img -ramdisk /path/to/your/aosp/source/out/target/product/generic_x86_64/ramdisk.img -debug-init -show-kernel

Note: Adjust paths to `kernel-qemu`, `system.img`, `userdata.img`, and `ramdisk.img` according to your AOSP version and `lunch` target. The `-debug-init` and `-show-kernel` flags are useful for initial boot diagnostics.

Wait for the emulator to fully boot. Verify `adb` connectivity:

adb devices

You should see your emulator listed. If not, troubleshoot `adb` connectivity before proceeding.

Preparing for Native Debugging on the Emulator

To debug native code, you need a debugger server running on the emulator. AOSP builds typically include `lldb-server` in `userdebug` variants, but `gdbserver` can also be pushed if preferred.

1. Push the Debugger Server

If you used a `userdebug` build, `lldb-server` is usually present at `/system/bin/lldb-server`. If not, or if you prefer `gdbserver`, you can push it from your AOSP build output.

# For LLDB:adb shell "cp /system/bin/lldb-server /data/local/tmp/"# For GDB (if lldb-server is not suitable or missing):# Locate gdbserver in your AOSP output (e.g., prebuilts/tools/linux-x86_64/gdb/gdbserver)# adb push /path/to/your/aosp/prebuilts/tools/linux-x86_64/gdb/gdbserver /data/local/tmp/# adb shell "chmod 777 /data/local/tmp/gdbserver"

Using `lldb-server` is generally recommended for modern AOSP versions.

2. Identify the Target Process

Decide which native process you want to debug. This could be a system service (e.g., `mediaserver`), a daemon, or a native library loaded by an app. Get its PID:

adb shell ps -Ao PID,CMD | grep mediaserver

Let’s assume the `mediaserver` PID is `1234` for this example.

3. Set Up Port Forwarding

The debugger client on your host machine needs to connect to the debugger server on the emulator. Use `adb` to forward a local port to a remote port on the emulator.

adb forward tcp:5039 tcp:5039

Here, port `5039` on your host is forwarded to port `5039` on the emulator.

4. Launch the Debugger Server on the Emulator

Now, launch `lldb-server` on the emulator, instructing it to attach to the target process and listen on the forwarded port.

adb shell "/data/local/tmp/lldb-server platform --listen *:5039 --attach 1234"

Replace `1234` with the actual PID of your target process. The `platform` argument ensures it uses the correct AOSP-specific platform debugging features.

Debugging with LLDB on the Host

With the server running, you can now connect your host-side LLDB client.

1. Prepare LLDB Client

Open a new terminal on your host machine and launch `lldb`.

lldb

2. Connect to the Remote Server

Tell LLDB to connect to the remote `lldb-server` running on your emulator via the forwarded port.

(lldb) platform select remote-android(lldb) target create --remote-platform /path/to/your/aosp/out/target/product/generic_x86_64/symbols/system/bin/mediaserver(lldb) gdb-remote 5039

Replace `/path/to/your/aosp/out/target/product/generic_x86_64/symbols/system/bin/mediaserver` with the actual path to the unstripped binary (with debug symbols) corresponding to the process you are debugging. This path is crucial for LLDB to load symbols correctly.

3. Load Additional Symbols (if necessary)

If your target process uses dynamically loaded libraries, you might need to manually add their symbols. For example, if `mediaserver` uses `libmedia.so`:

(lldb) add-symbol-file /path/to/your/aosp/out/target/product/generic_x86_64/symbols/system/lib64/libmedia.so

You can find the loaded libraries and their addresses using `adb shell cat /proc/<PID>/maps` and then load symbols for those you are interested in.

4. Set Breakpoints and Inspect

Now you can set breakpoints, step through code, and inspect variables just like in any other debugging session.

  • Set a breakpoint: `(lldb) b ANativeFunctionInMediaServer`
  • Continue execution: `(lldb) c`
  • Step over: `(lldb) n`
  • Step into: `(lldb) s`
  • Print a variable: `(lldb) p myLocalVariable`
  • View backtrace: `(lldb) bt`

Trigger the action on the emulator that calls the function where you’ve set a breakpoint. The LLDB client on your host should hit the breakpoint.

Advanced Debugging Considerations

  • Crash Dumps: For hard-to-catch crashes, analyze crash dumps. Enable `coredump` generation on userdebug builds or use `tombstones` located at `/data/tombstones`.
  • `strace`/`ltrace`: For system call tracing or library call tracing, `adb shell strace -p ` or `adb shell ltrace -p ` can be invaluable for understanding runtime behavior. These tools require root and are usually present in `userdebug` builds.
  • Source Code View: Configure your LLDB client to locate your source files so you can see the source code alongside the assembly during debugging. Use `settings set target.source-map /remote/path /local/path`.

Conclusion

Debugging native code in custom AOSP ROMs on an Android emulator is a powerful technique for low-level system development and bug hunting. By correctly building a `userdebug` AOSP image, setting up port forwarding, and leveraging `lldb-server` with the host-side `lldb` client, developers gain deep insights into the runtime behavior of native Android components. This expert-level approach ensures you can effectively troubleshoot and optimize even the most intricate parts of your custom Android system.

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner