ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android 5.1 Lollipop源码编译与AOSP定制开发实战指南

Android 5.1 Lollipop源码编译与AOSP定制开发实战指南 简介面向Android系统开发、ROM定制与应用工程人群这份资料以Android 5.1 Lollipop源码为对象按kernel、框架层、androidx、javax、org等目录逐层梳理系统运行机制。压缩包仅27.07MB便于快速下载查阅内容聚焦关键组件与底层设计而非完整源码树适合已有一定Android基础的读者用其分析Activity Manager、Content Provider、Broadcast Receiver等核心实现。目前已有661人浏览/学习对于希望深入理解多窗口支持、数据绑定、内存管理和电源优化的开发者而言参考价值比较明确。资料覆盖了内核调度、I/O与中断处理也涉及JUnit测试、JSR166并发API和性能基准测试代码可帮助读者建立从硬件交互到上层服务的整体认知。此外javax目录对应的标准Java接口、com目录下的Google服务与第三方库以及org目录中的开源组件都有助于后续进行系统级调试、功能裁剪或自定义ROM开发时快速定位代码路径。 2015年3月Google放出了Android 5.1 Lollipop的AOSP源码。放在今天看这个版本已经是老古董了但在系统开发这个圈子里它恰恰是一个特别能打的基础版本。API 225.x序列里的稳定修订版没有5.0那种半成品气质也没有后来Android 8.0之后项目体积膨胀到吓人的复杂结构。很多做行业定制设备、打车机、广告机、物联网平板的团队到现在还抱着5.1在维护。这篇文章不是科普“棒棒糖”设计多精美而是从源码开发者的角度把一套Android 5.1 Lollipop源码从下载、编译、拆目录、找改法到踩坑排查的完整链路过一遍。适合谁看想入门AOSP定制的新手手里正好有5.1设备要做系统的同学以及对系统底层好奇、想搞明白framework怎么跑起来的开发者。我默认你看过一点Linux命令行但不要求你有多深的嵌入式经验。1. 为什么5.1 Lollipop源码值得折腾1.1 一个版本的分水岭Android 5.0是Lollipop的开端Art运行时全面替换DalvikMaterial Design设计语言落地整个系统架构可以说翻了一次天。但5.0的问题也相当明显内存泄漏严重、Wi-Fi频繁断连、设备待机耗电异常这些怪毛病让很多第一时间升到5.0的用户骂声一片。5.1就是来收拾残局的。它更像是“Lollipop成熟版”把5.0最丢人的几个短板补了修复了内存泄漏、优化了Wi-Fi连接稳定性、改善电池续航表现还顺手加了几个新功能点。最直观的一点系统快速设置面板终于可以自定义了不用再忍受固定的那几个快捷开关。对做开发的人来说5.1的源码改动小、结构清晰、编译体系成熟是一个非常适合拿来深度阅读和二次开发的版本。换句话说5.0你踩坑5.1你干活5.1.1_r38则是这个系列里公认最稳的tag不折腾到它说不过去。从这套源码里你能看到完整的Native层C/C、Framework层Java、App层全套代码。相比Android 10、11那种动辄上百个repo的庞然大物5.1的代码规模对个人开发者友好得多。CPU 8核以上、内存16GB就足够编译这也是为什么时至今日还有人在这个版本上做文章。1.2 用它到底能做什么源码在手你能干的事不只是刷个ROM。我见过三类典型用途第一类是学习系统原理。SystemServer怎么启动、ActivityManagerService怎么管理组件、Binder怎么跨进程通信这些经典机制在5.1里比新版本清晰得多。新版Android为了兼容各种形态设备加了一大堆条件分支读起来容易迷路5.1没有这个负担。第二类是行业设备定制。很多广告机、收银机、人机交互终端至今还在用高通或全志方案的5.1平台。你有源码就能改开机动画、预装应用、精简系统服务、配置硬件权限这些全是真金白银的商业需求。第三类是系统安全研究。5.1默认开启了SELinux enforcing模式对比5.0的宽容模式它引入了完整的安全策略配置研究权限管控和审计日志5.1也是很好的起点。我自己的实践体会是这个版本的源码编译最省心改起来也最“痛快”。你不用理解一大堆新引入的构建系统和模块化概念改完代码make烧录就能看到效果整个反馈周期很短。2. 源码环境搭建的硬核细节2.1 硬件、系统与依赖先泼一盆冷水不要用Windows或macOS直接编译Android源码。虽然能折腾但各种路径分隔符、文件系统大小写、符号链接问题会让你怀疑人生。官方推荐的是Ubuntu 14.04Trusty64位系统我在实际编译中Ubuntu 16.04也能顺利过但再往后的版本就可能会出现GCC版本不兼容的问题得额外加补丁。这个版本对编译工具链的要求很苛刻不是越新越好。硬件方面我列一下我认为的保底配置CPU8核以上编译时并行度直接决定你等多久内存16GB低于这个数字很容易在链接阶段被OOM干掉磁盘至少200GB空闲空间源码编译产物占掉大半Swap建议再挂16GB Swap文件这是廉价保险依赖包一条命令装齐sudo apt-get install git-core gnupg flex bison gperf 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 openjdk-7-jdk注意这里OpenJDK 7是硬性要求。5.1的编译工具链对JDK版本极其敏感JDK 8和JDK 6都会在编译Java层时报错。我在Ubuntu 16.04上装OpenJDK 7还得自己加PPA源这点提前有个准备。2.2 repo拉取源码的正确姿势AOSP不是单仓库它由好几百个Git仓库组成Google提供了repo这个Python工具来管理这些仓库的同步。第一步先装repomkdir ~/bin curl https://commondatastorage.googleapis.com/git-repo-downloads/repo ~/bin/repo chmod x ~/bin/repo export PATH~/bin:$PATH然后初始化工作目录我习惯放在~/aosp/lollipopmkdir -p ~/aosp/lollipop cd ~/aosp/lollipop repo init -u https://aosp.googlesource.com/platform/manifest -b android-5.1.1_r38这里涉及两个关键决定。第一个是分支android-5.1.1_r38是5.1.1的最终稳定版tagAOSP官方推荐使用如果你要研究5.1最早发布时的样子可以选android-5.1.0_r1。第二个是仓库地址在国内直接连官方源基本走不动我用的是清华开源软件镜像站或中科大镜像站把-u后面的URL换成镜像地址速度立刻从个位数KB涨到几十MB。同步代码耐心等就行repo sync -j8这里我多说一句-j参数不是越大越好。如果你网络不稳定并发太高反而容易触发仓库下载失败导致整个sync中断。我的习惯是先repo sync -j8如果中途失败再执行一次repo sync -j4接着同步repo会自动跳过已经完成的部分。源码全部落地后大概占用20GB左右空间。用du -sh确认一下别等编译到一半才发现磁盘满了。2.3 检查文件系统与环境变量源码下载完先别急着编译检查三件事文件系统必须是大小写敏感的所以ext4没问题NTFS、FAT32绝对不行磁盘剩余空间要够最好再留出60GB以上给编译产物/bin/sh必须是bash或dash不要动它还有一个环境变量建议现在exportexport USE_CCACHE1并设置缓存目录和大小export USE_CCACHE1 export CCACHE_DIR~/aosp/.ccache prebuilts/misc/linux-x86/ccache/ccache -M 50Gccache是编译加速的神器你改一个模块后重新编译如果缓存命中率高编译时间能压缩到原来的十分之一。第一次全量编译时它帮不上忙但后续增量编译全看它。3. 源码目录结构与核心模块拆解3.1 顶层目录速览源码同步完成后顶层目录几十个但真正核心的就这几个目录作用关键程度build/编译系统和构建脚本Makefile核心高frameworks/Framework层代码系统的Java大脑高packages/系统自带App设置、桌面、联系人等高hardware/硬件抽象层HAL连接内核和Framework高kernel/Linux内核相关代码和配置中external/第三方开源库SQLite、Webkit等中device/具体设备的配置文件和板级支持高vendor/厂商私有库和App中system/底层系统组件C/C为主高初学者最容易忽视的是device目录。这个目录决定了你编译出的设备镜像长什么样里面定义board配置文件、Product makefile、内存分区表。你要编译Nexus 5的镜像就看device/lge/hammerhead/编译通用模拟器镜像就看device/generic/goldfish/。3.2 5.1相比5.0的核心改进点如果你是从5.0的代码切到5.1最先感受到的是这些变化ART运行时继续加固5.1修复了大量5.0里ART导致的崩溃应用安装后的dex2oat优化策略也做了调整设备开机速度明显提升SELinux全面启用从5.0的permissive宽容模式切到enforcing强制模式系统安全策略正式生效很多厂商的私有服务因为没配SELinux规则直接跑不起来快速设置面板可编辑下拉通知栏里那排快捷开关终于支持增删排序这个功能从系统UI到Settings都加了不少代码双卡双待能力增强在Framework层完善了多SIM卡的接口支持给后面的双卡机铺路内存管理优化改进了lowmemorykiller的判压逻辑对高占用App的处理更主动后台进程被误杀的几率降低Wi-Fi稳定性修复这是5.0最被诟病的问题之一5.1从Wi-Fi状态机和控制逻辑上做了不少修复对做源码开发的人来说SELinux这个改动最值得关注。你在5.0上能跑的底层服务到了5.1可能被SELinux策略拦死。遇到这种问题思路不是关SELinux而是去补device/厂商/平台/sepolicy/目录下的te策略文件把该给的权限用allow规则写清楚。3.3 关键源码位置清单做定制开发时经常要改的地方我整理了一个位置清单系统启动入口frameworks/base/services/java/com/android/server/SystemServer.java这里是系统服务的总闸Activity管理frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java包管理frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java通知栏和快捷设置frameworks/base/packages/SystemUI/系统设置Apppackages/apps/Settings/桌面Launcherpackages/apps/Launcher3/开机动画frameworks/base/cmds/bootanimation/真机定制第一步基本都是改这里系统属性定义build/target/product/和build/make/core/这套位置清单几乎是老开发者的路径肌肉记忆。在5.1上改Launcher3的图标排列或者默认壁纸比新版简单太多因为那时候的Launcher3逻辑不算复杂搞清楚LauncherAppState和Workspace两个类基本就能上手。4. 完整编译“原生Lollipop”的实操过程4.1 初始化编译环境和核心参数源码编译的第一步是导入编译环境的初始化脚本cd ~/aosp/lollipop source build/envsetup.sh这个脚本会设置一系列环境变量并定义lunch、mm、mmm、croot等便捷命令。lunch就是选择你要编译的目标产品。运行lunch不带参数会列出所有可用的product combo我常选的几个是aosp_arm-eng纯armeabi架构的工程版适合32位模拟器aosp_arm64-eng64位ARM架构适合64位模拟器aosp_x86_64-engx86_64架构办公电脑上跑模拟器最流畅aosp_hammerhead-userdebugNexus 5真机调试版用户版本选型也是有讲究的。eng是工程版带完整调试工具和root权限适合开发调试userdebug比eng更接近正式版同时保留root权限适合做真机测试user是纯净用户版锁了root没有debug工具适合最终交付。我刚开始搞定制的时候不懂这些全部用user编译结果连logcat都看不到有的调试开关也没开排查问题特别费劲。现在做开发验证一律eng或userdebug发布时才切user。4.2 选择合适的lunch目标并触发编译以64位模拟器为例执行lunch aosp_arm64-eng make -j16-j后面的数字是并行编译任务数理论上设置成CPU物理核数的两倍能让CPU跑满。我用8核机器make -j16通常能把四个线程都喂饱。但这一步有个容易被忽略的坑并行的本质是给每个任务分配内存并行数越高内存峰值越大。16GB内存开-j16编译5.1有点悬我实测在JACK编译器吃内存最狠的阶段内存占用轻松顶到14GB以上。如果你内存只有12GB老老实实make -j8慢点但稳定。会问为什么5.1的编译特别吃内存因为5.1从Java层编译上做了件大事——引入了Jack编译器Java Android Compiler Kit。它把Java源码直接编译成dex格式跳过了传统的javacdx两步效率理论上更高但代价是它是一个常驻内存的后台服务。如果你的机器内存不够Jack服务分分钟OOM编译戛然而止。这也是5.1编译特有的一个坎。8.0之前你都要跟它打交道到Android 9才把Jack彻底移除R8和D8重新上位。4.3 编译产物与刷机验证第一次全量编译4核配置大概要跑4个小时8核大概2个多小时16核机器能压到1小时内。看到最后一屏“### make completed successfully ###”就成功了。产物全部在out/target/product/产品名/目录下文件作用system.img系统分区镜像放Framework和Appboot.img内核与ramdisk系统启动的关键userdata.img用户数据分区镜像recovery.img恢复模式镜像cache.img缓存分区镜像模拟器直接执行emulator即可起飞它会自动加载out目录下的镜像。真机的话用fastboot刷入。比如Nexus 5adb reboot bootloader fastboot flash boot out/target/product/hammerhead/boot.img fastboot flash system out/target/product/hammerhead/system.img fastboot flash userdata out/target/product/hammerhead/userdata.img fastboot reboot这里有个经验分享刷机前一定要备份原厂userdata和boot万一编译的镜像有问题还能刷回去。我头一回刷机就手滑把原厂recovery都覆盖了当时没有备份折腾了一整天才把原厂镜像找回来。便宜Nexus设备还好到了后来的定制行业设备恢复工具时常不齐全备份这步真不能省。4.4 增量编译的正确姿势第一次全量编译之后你再改Android代码不需要全部重新make。比如你改了SystemUI里的状态栏代码只需要这么干cd frameworks/base/packages/SystemUI/ mmmmmm命令会自动检测当前目录对应的模块只编译这个模块并生成新的包。然后你再把生成的apk用adb push到设备上重启SystemUI进程整个调试周期能缩短到两分钟以内。增量编译最重要的前提就是ccache配置好。我见过一个同事改了Settings的一个字符串然后跑make -j16等十分钟还没编完。他压根没用mm/mmm直接全量编译纯粹浪费生命。5. 新手最容易踩的坑实操问题排查实录5.1 Jack服务崩溃与内存OOM前面说过Jack编译器是5.1编译的特产坑。我遇到过的典型报错Out of memory error when loading java class. Try increasing heap size with java -Xmxsize.解决方式有两个方向。第一个是调整Jack服务自己的堆内存export JACK_SERVER_VM_ARGUMENTS-Xmx4096m -Dfile.encodingUTF-8把4GB堆内存分给Jack能缓解大部分OOM问题。第二个是编译前把不必要的图形界面程序关掉、浏览器标签全关尽量释放内存给编译进程。如果还是崩溃还有一个绝招清理Jack的临时状态然后重启cd ~/aosp/lollipop export JACK_SERVER_VM_ARGUMENTS-Xmx4096m ./prebuilts/sdk/tools/jack-admin kill-server ./prebuilts/sdk/tools/jack-admin start-server清理之后重跑make通常都能续上。别一遇到OOM就重启整个编译Android的编译流程会把没完成的任务自动重做重启机器再compile等于把所有模块重新编一遍太亏了。5.2 repo sync中断与“uncommitted changes”repo sync下载了半个小时结果报了一堆error想二次同步又提示error: Your local changes to the following files would be overwritten by merge这是你之前可能手动修改过源码树里的某个文件比如为了验证某个patch导致repo sync时git发现本地变更和远端冲突拒绝覆盖。解决方法是把这棵树的改动先藏起来同步完再恢复repo forall -c git stash repo sync -j8如果是你自己准备长期保留的修改更好的做法是先提交到本地git再走repo sync。我后来养成一个习惯任何对AOSP源码的手动修改先记在git的commit里绝不裸改。这样不管是repo sync还是diff对比、回溯都有据可依。另外还有种情况repo sync一直卡在某个仓库不动多半是网络问题。这时候CtrlC中断重新跑repo sync -j4就行。repo设计上就是可重复执行的你不必追求一次成功。5.3 编译时找不到某个模块的依赖No rule to make target framework-res.apk, needed by xxx. Stop.这种报错多半是因为源码没完全同步或者你之前只同步了部分仓库。好一点的解决办法是重新执行完整repo sync如果你想精准补拉可以确认是哪个仓库没同步全单独进去补cd frameworks/base repo sync .我自己还遇到过一个更隐蔽的情况mmm之前忘了source envsetup.sh导致模块搜索路径不对报一堆找不到模块的错误。建议每个新开的终端窗口先执行source build/envsetup.sh再lunch再操作顺序别乱。5.4 常见错误速查表错误现象最可能的根因解决动作Jack Out of MemoryJack堆内存设置太小或系统内存不足调大JACK_SERVER_VM_ARGUMENTS关后台程序编译中途KilledSwap不足或内存耗尽增加Swap降低-j并行数找不到编译工具ccachePATH未设置或未build/envsetup.sh检查环境变量重新source build/envsetup.shrepo sync一直失败网络不稳定/镜像站压力大换镜像降低并发数反复重试make: No rule to make target源码不同步/某个repo缺失完整repo sync确认依赖仓库存在SELinux权限拒绝服务跑不起来sepolicy策略没配置在对应te文件里补充allow规则刷机后开不了机boot.img和system.img版本不匹配确认lunch产品一致重新全量编译烧录再提一个很多人不知道的小技巧编译前台输出信息太多建议把log存文件再看make -j16 21 | tee build.log排查的时候直接grep -i error build.log效率比盯着屏幕高十倍。编译挂掉时看的是第一个error不是最后一个。很多新手喜欢拉到最后看状态结果最后一个error只是连锁反应导致的根本原因藏在前面。写在后面这套源码值得花时间我个人的看法是Android 5.1 Lollipop源码是当前所有AOSP版本里“性价比”最高的学习样本。它的结构和Android 15比少了一大堆抽象层和动态特性框架Binder、Handler、MessageQueue这些核心机制又都已经成型恰恰是理解整个Android体系最好的切入点。你要是能把SystemServer启动流程、AMS/PMS的工作方式在这套源码里读明白后面再去看新版本完全是一通百通。另外给想做定制落地的朋友一个提醒拿到一个5.1的设备后不要着急改代码先把原厂的qemu配置、设备树、内核config、分区表这些底料理清楚。很多时候设备起不来不是代码的问题而是你并没有真正自定义刷入环境。源码这条路没有捷径搭好环境、读透结构、跑通编译一次完整的闭环体验胜过看十篇教程。本文还有配套的精品资源点击获取
返回列表