January 10, 2024
8 min read

Custom ROM Development: Best Practices and Common Pitfalls

Custom ROM
Android
Development
Best Practices
SSamir Dubey
Samir Dubey

AOSP Engineer

Learn industry best practices for custom ROM development and how to avoid common mistakes that can break your builds or devices.

Developing custom ROMs is both an art and a science. While AOSP provides the foundation, creating a stable, feature-rich custom ROM requires careful attention to detail and adherence to best practices. In this guide, we'll explore the most important practices and common pitfalls to avoid.

Project Structure and Organization

Directory Structure

Organize your project with a clear, logical structure:

custom_rom/
├── device/
│   └── manufacturer/
│       └── device_name/
├── vendor/
│   └── manufacturer/
│       └── device_name/
├── kernel/
│   └── manufacturer/
│       └── device_name/
└── patches/
    ├── frameworks/
    ├── packages/
    └── system/

Version Control Best Practices

  1. Use Git Flow: Implement a branching strategy
  2. Commit Often: Make small, logical commits
  3. Write Descriptive Messages: Include what and why
  4. Tag Releases: Use semantic versioning

Device Tree Configuration

Essential Files

Every device tree should include:

  • AndroidProducts.mk: Product definition
  • BoardConfig.mk: Board-specific configuration
  • device.mk: Device-specific makefiles
  • lineage.mk or aosp.mk: ROM-specific configuration

BoardConfig.mk Best Practices

Always specify target architecture:

TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_ABI := arm64-v8a

Bootloader and recovery:

TARGET_BOOTLOADER_BOARD_NAME := device_name
TARGET_NO_BOOTLOADER := true
TARGET_NO_RADIOIMAGE := true

Kernel configuration:

BOARD_KERNEL_CMDLINE := console=ttyMSM0,115200,n8 androidboot.console=ttyMSM0
BOARD_KERNEL_BASE := 0x80000000
BOARD_KERNEL_PAGESIZE := 4096

Security Considerations

SELinux Policies

Never use permissive SELinux in production:

Bad practice:

BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive

Good practice - fix policies instead:

BOARD_SEPOLICY_DIRS += device/manufacturer/device_name/sepolicy

Verified Boot

Implement proper verified boot when possible:

BOARD_AVB_ENABLE := true
BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flags 3

Performance Optimization

Compiler Optimizations

Enable optimizations:

USE_O3_OPTIMIZATIONS := true
ENABLE_OPTIMIZATIONS := true

Target-specific optimizations:

TARGET_CPU_VARIANT := cortex-a53
TARGET_2ND_CPU_VARIANT := cortex-a53

Memory Management

Optimize for device RAM:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.config.low_ram=false \
    ro.config.zram=true

Common Pitfalls to Avoid

1. Ignoring Dependencies

Always check and include all required dependencies:

In device.mk:

PRODUCT_PACKAGES += \
    libril \
    libbinder \
    libutils

2. Hardcoded Values

Avoid hardcoding device-specific values:

Bad:

BOARD_KERNEL_CMDLINE += androidboot.serialno=123456789

Good:

BOARD_KERNEL_CMDLINE += androidboot.serialno=$(shell cat /proc/cmdline | grep -o 'androidboot.serialno=[^ ]*' | cut -d= -f2)

3. Copying Without Understanding

Don't blindly copy configurations from other devices. Understand what each setting does.

4. Skipping Testing

Test thoroughly on actual hardware:

  • Basic functionality (calls, SMS, data)
  • Hardware features (camera, GPS, sensors)
  • Performance benchmarks
  • Battery life tests

Build System Optimization

Parallel Builds

Optimize build times:

Use all available cores:

make -j$(nproc)

Or limit if running out of memory:

make -j$(($(nproc) / 2))

ccache Configuration

Enable ccache for faster rebuilds:

export USE_CCACHE=1
export CCACHE_DIR=/path/to/ccache
ccache -M 50G

Quality Assurance

Automated Testing

Implement automated testing:

Build test script:

#!/bin/bash
make clean
make -j$(nproc) 2>&1 | tee build.log
if [ $? -eq 0 ]; then
    echo "Build successful"
else
    echo "Build failed"
    exit 1
fi

Code Review Process

  1. Review All Changes: Don't commit untested code
  2. Test on Hardware: Emulator testing isn't enough
  3. Document Changes: Maintain a changelog
  4. Peer Review: Have others review your code

Maintenance and Updates

Regular Updates

Keep your ROM updated:

  1. Security Patches: Monthly security updates
  2. Bug Fixes: Address reported issues promptly
  3. Feature Updates: Add new features carefully
  4. Upstream Merges: Regularly merge upstream changes

User Support

Provide good user support:

  • Clear installation instructions
  • Troubleshooting guides
  • Bug reporting templates
  • Active community support

Documentation

Essential Documentation

Always document:

  • Build instructions
  • Installation procedures
  • Known issues
  • Feature list
  • Changelog

Example Build Instructions

Create comprehensive build instructions that include:

  • Prerequisites and system requirements
  • Step-by-step build process
  • Troubleshooting common issues
  • Installation and flashing procedures

Conclusion

Custom ROM development requires patience, attention to detail, and continuous learning. By following these best practices and avoiding common pitfalls, you'll create more stable, secure, and maintainable ROMs.

Remember that the Android ecosystem is constantly evolving, so stay updated with the latest changes and best practices in the AOSP community.