1. 环境准备与基础概念在开始构建自定义Android系统镜像之前我们需要先搭建好开发环境。我建议使用Ubuntu 20.04 LTS作为基础系统因为这是Google官方推荐的AOSP开发环境。你需要准备至少16GB内存和200GB以上的磁盘空间编译Android 12的源码相当消耗资源。安装基础依赖包时我习惯一次性把可能用到的工具都装上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下载AOSP源码是个漫长的过程我通常会选择清华镜像源来加速repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-12.0.0_r15 repo sync -j4这里有个小技巧第一次同步源码时可以先用-j4参数等同步完成后再用-j8或更高并行数重新同步这样能避免网络不稳定导致的中断。我曾经因为网络问题反复同步了三次才成功浪费了不少时间。2. 预装APK的目录结构设计在AOSP中预装第三方APK时目录结构的设计直接影响后续维护的便利性。根据我的经验主要有三种常见的放置位置packages/apps目录适合预装少量应用结构简单明了vendor目录适合OEM厂商预装自己的应用product目录Android 10引入的新特性支持模块化分区管理我最近一个项目采用了product分区的方案目录结构是这样的product/ └── my_product/ ├── AndroidProducts.mk ├── my_product.mk └── apps/ ├── App1/ │ ├── App1.apk │ └── Android.mk └── App2/ ├── App2.apk └── Android.bp这种结构的优势在于应用与系统核心分离便于单独更新支持动态分区符合Treble架构规范可以针对不同产品线灵活配置3. Android.mk与Android.bp配置详解Android.mk是传统的Makefile配置方式我在处理遗留项目时经常使用。下面是一个经过实战检验的模板LOCAL_PATH : $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE : MyApp LOCAL_MODULE_TAGS : optional LOCAL_SRC_FILES : MyApp.apk LOCAL_MODULE_CLASS : APPS LOCAL_MODULE_SUFFIX : $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE : platform LOCAL_PRIVILEGED_MODULE : true LOCAL_DEX_PREOPT : false LOCAL_ENFORCE_USES_LIBRARIES : false include $(BUILD_PREBUILT)这里有几个关键参数需要注意LOCAL_CERTIFICATEplatform表示使用系统签名PRESIGNED保留原签名LOCAL_PRIVILEGED_MODULEtrue表示安装到system/priv-app获取更高权限LOCAL_DEX_PREOPT关闭可以节省首次启动时间但会增加存储占用对于新项目我推荐使用Android.bp这是Soong构建系统采用的配置方式android_app_import { name: MyApp, apk: MyApp.apk, certificate: platform, privileged: true, dex_preopt: { enabled: false, }, product_specific: true, }Android.bp的语法更简洁而且支持更好的增量编译。我在迁移旧项目时发现编译速度能提升20%左右。4. 常见问题排查与解决方案在实际项目中我遇到过各种奇怪的编译错误和运行时问题这里分享几个典型案例案例一ABI兼容性问题错误信息INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries解决方法检查APK包含的so库架构unzip -l YourApp.apk | grep .so在Android.mk中添加多架构支持LOCAL_MULTILIB : both案例二签名冲突症状系统卡在开机动画无法进入 根本原因多个应用使用了冲突的签名证书 我的排查步骤通过adb获取启动日志adb logcat -b all -v threadtime boot.log搜索PackageManager关键字找到冲突的包名后修改签名配置或移除冲突应用案例三资源文件缺失错误现象应用图标显示为默认安卓机器人 解决方法确保APK包含完整的res资源在Android.bp中添加资源声明resource_dirs: [res],5. 进阶技巧模块化产品配置在为企业客户定制系统时我总结出一套模块化管理方案产品差异化配置 在product目录下为每个产品线创建独立的mk文件PRODUCT_PACKAGES \ AppA \ AppB \ AppC PRODUCT_PROPERTY_OVERRIDES \ ro.product.featurepremium条件编译 通过TARGET_BUILD_VARIANT判断编译类型ifeq ($(TARGET_BUILD_VARIANT),userdebug) LOCAL_CFLAGS -DDEBUG_MODE endif动态分区配置 在BoardConfig.mk中设置BOARD_PRODUCTIMAGE_PARTITION_SIZE : 314572800 BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE : ext4最近一个汽车项目中使用这套方案成功将编译配置时间从2小时缩短到15分钟产品线间的差异化管理也变得非常清晰。6. 性能优化实践系统预装应用对启动速度和存储空间的影响很大我通常会做这些优化Dex优化配置LOCAL_DEX_PREOPT : true LOCAL_DEX_PREOPT_IMAGE : true LOCAL_DEX_PREOPT_GENERATE_PROFILE : true资源压缩 在product配置中添加PRODUCT_MINIMIZE_JAVA_DEBUG_INFO : true PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER : speed按需加载 对于不常用的预装应用可以设置为LOCAL_OVERRIDES_PACKAGES : OriginalApp这样当用户安装市场版本时系统会自动禁用预装版本。7. 调试与验证技巧项目后期最花时间的就是调试阶段我常用的调试命令组合检查预装结果adb shell pm list packages -f | grep -i myapp adb shell dumpsys package my.package.name验证文件位置adb shell ls -l /system/priv-app/MyApp/ adb shell ls -l /product/app/MyApp/性能监控adb shell top -n 1 | grep MyApp adb shell dumpsys meminfo my.package.name有个特别实用的技巧在开发阶段可以先用adb install安装测试确认没问题后再集成到系统镜像中能节省大量编译等待时间。8. 持续集成方案对于需要频繁更新的项目我建议搭建自动化构建系统。我的Jenkins配置包含以下关键步骤代码同步repo sync -c -j8 --force-sync增量编译source build/envsetup.sh lunch my_product-userdebug make -j16 MyApp镜像生成make snod自动化测试adb install -t -r MyApp.apk adb shell am instrument -w my.package.name.test/androidx.test.runner.AndroidJUnitRunner这套方案在我负责的智能家居项目中将版本迭代周期从2周缩短到了3天而且质量稳定性反而提高了。