Building a fully functional AOSP ROM for a commercial device requires more than just compiling the open-source code. Modern smartphones rely heavily on proprietary, closed-source components provided by the silicon vendor (Qualcomm, MediaTek, Google Tensor) or the device manufacturer. These are commonly referred to as "vendor blobs."
Vendor blobs include:
- Precompiled HALs (Hardware Abstraction Layers) as
.sofiles (e.g., camera processing algorithms). - Closed-source daemons executable binaries (e.g., RIL daemon for modem communication).
- Firmware files loaded directly into hardware components (e.g., Wi-Fi MAC firmware, GPU microcode).
Extracting Proprietary Blobs from Stock Firmware
To build AOSP for a device, you must extract these blobs from a running device or a factory firmware image and place them into your AOSP source tree.
The most common approach for custom ROM developers (like LineageOS) involves extracting files directly from a rooted device running the stock OS via adb pull.
Alternatively, developers can extract the vendor.img, system_ext.img, and odm.img from an OTA update payload or factory zip, mount them locally on a Linux machine, and copy the required files.
The extract-files.sh Script
To automate the extraction process, device maintainers write shell scripts, conventionally named extract-files.sh and setup-makefiles.sh.
A companion text file, usually proprietary-files.txt, lists exactly which files are needed:
# Camera
vendor/lib64/hw/camera.qcom.so
vendor/lib64/libcamalgo.so
vendor/bin/mm-qcamera-daemon
# RIL (Radio Interface Layer)
vendor/lib64/libril-qc-hal-qmi.so
# Firmware
vendor/firmware/venus.mdt
vendor/firmware/venus.b00
The extract-files.sh script iterates through this list, pulls each file from the connected device (or a mounted dump directory), and places them into the correct location in the AOSP build tree.
It then calls setup-makefiles.sh, which automatically generates the Android.mk or Android.bp files needed to instruct the AOSP build system to copy these prebuilt blobs into the final output images.
Blob Patching with patchelf
Often, a proprietary .so file extracted from a stock ROM expects certain dependencies that differ in a custom AOSP build. For example, a blob might link against a specific version of libutils.so or expect a library to be named differently.
Because we do not have the source code to recompile the blob, we must modify the compiled binary directly. This is done using tools like patchelf.
patchelf allows developers to modify the ELF headers of a binary:
- Replacing Dependencies:
patchelf --replace-needed libstdc++.so libstdc++_vendor.so vendor/lib64/libclosed.so - Removing Dependencies: If a blob links to a library that isn't strictly necessary and is causing build or runtime failures, the dependency can be stripped out.
- Changing RPATH/RUNPATH: Modifying where the dynamic linker searches for dependencies.
The vendor/<vendor>/<device>/ Directory Structure
Extracted blobs and their generated Makefiles are not placed in the device/ tree. Instead, they reside in the vendor/ tree, mirroring the device tree's structure.
If your device tree is device/google/panther, your proprietary blobs should be located in vendor/google/panther/.
A typical vendor/ tree structure looks like this:
vendor/google/panther/
├── Android.bp # Automatically generated
├── proprietary/ # The actual extracted blobs
│ ├── vendor/
│ │ ├── bin/
│ │ │ └── mm-qcamera-daemon
│ │ ├── lib64/
│ │ │ └── camera.qcom.so
│ │ └── firmware/
└── panther-vendor.mk # Included by the device tree
The panther-vendor.mk file defines PRODUCT_COPY_FILES or includes the Android.bp modules, ensuring that when make is executed, the proprietary blobs are bundled into the final ROM.