用安卓SDK制作怎么原生安卓刷机包制作教程

不知道是因为最近kaihui还是怎么的,打开特别的慢,想下载最新版本的platform几乎变成不可能完成的任务,不知道为什么Google不像Apache那样在各国设立镜像站。为了预防今后再出现这样的情况,这次干脆把android开发所需要的各种包总结一下,顺便提供本地下载链接,省得以后找起来麻烦。
通过分析SDK Manager里要用到的文件,我下载了目前google提供的各类安卓开发包并上传到了网盘。由于网盘有CDN支持,即使不用迅雷,下载速度依然很快。如果你从官网下载很慢,不妨试试这些国内链接。
更新:增加了android 6.0 (level 23)的sdk下载;增加support r22和support r23的下载。
更新:增加了android 5.1.1的platform下载。
更新:完善了sysimg部分,增加了Level 21的x86平台sysimg链接。
更新:增加了android 5.0的sample下载。
更新:增加了Support包下载,更新了doc资源版本和下载链接;更新了Android Studio版本到1.0.1,更新了SDK Tools到r24。
更新:更新了SDK Tools的版本,从22.6到23.0.2;增加了Android Studio下载。
更新:增加了部分Android-L资源下载。
更新:感谢CodeDream分享的另一个国内,内容比较全(没有adt-bundle)速度较快,推荐。
更新:更新了level14-17的samples包;增加了level18-20的samples包;增加了level20版本的源码包;增加了level18-20的platform包。
更新:增加了level18和level19的源码包,并更新了其他版本源码包的链接。
更新: 百度和微云的大部分链接都失效了,重新更新了adt-bundle和sdk的下载链接,部分文件版本有升级。
更新: 更新了adt-bundle和sdk的下载链接,sdk版本由22.3更新为22.6,增加了腾讯微云的下载链接作为备份。
更新: bd网盘病得不轻,分享链接以后几分钟再访问,就显示&啊哦,你来晚了&。甚至网盘里的文件都被删除,导致楼主硬盘里也没有这些文件了,回收站里只能恢复出空文件夹。楼主会再花几天时间重新下载,放到其他网盘里,见谅。&善待生命,远离bd网盘。&
更新: 最近bd网盘又犯病,导致很多链接都失效了,如果楼主更新链接不及时,请访问后面这个地址对照文件名挑选所需文件:,口令eer5。
更新: 更新了adt-bundle的版本到,更新了android sdk的版本到r22.3。
更新: 更新了adt-bundle的版本到。
更新:更新了adt-bundle-17-windows-64bit.zip的网盘链接。
更新:有一小部分下载链接失效,经查是由于未知原因被百度网盘禁止分享了,请过一段时间再试。
更新2013/3: 有些包分操作系统版本,例如windows版、macos版和linux版,下载时注意文件名里的标识。
此帖长期更新,若有未及时更新的版本或失效链接,请留言通知主页君。
Android Studio
官方推荐新入门用户使用基于IntelliJ的Android Studio IDE进行开发,提供了更多的功能,原有基于Eclipse的ADT开发环境已降低更新频率。
其他下载地址
1.0.1版,包含SDK
注:Android Studio有自动更新功能,即使是旧版本(v0.8.x)的,也可以先升级到v0.9.9,然后再升级到v1.x,升级包不大比较方便。
可能是我电脑比较差(i5/8G/250G),感觉Android Studio运行起来比基于Eclipse的开发环境卡很多,加上操作方式和工程结构不一样,一下子很难适应。
ADT Bundle
多合一下载包,里面包含了:sdk + 特定版本platform + eclipse + adt + 兼容包,解压缩即可使用。唯一的缺点是体积比较大,如果你是从零开始配Android开发环境就下载吧。
其他下载地址
Android 4.2多合一开发包, Windows 32位。
Android 4.2(4.4?)多合一开发包, 注意所含eclipse是64位的。
Linux 32位
Linux 64位
假设你把sdk安装到d:\android-sdk,则里面的目录结构应该是这样的:
d:\android-sdk\tools
这个目录里有ddms.bat等文件
d:\android-sdk\system-images\android-17\armeabi-v7a
这个目录里有userdata.img等文件(r14及以上才有这个目录)
d:\android-sdk\platforms\android-4.0.2
这个目录里有android.jar等文件
d:\android-sdk\platform-tools
这个目录里有adb.exe等文件
d:\android-sdk\extras
这个目录里有android等目录
当你下载下面列出的部件时,也请参考上面的目录结构示例将内容放在正确的位置。
Android SDK
SDK就是开发包,里面包含了两大类命令行工具:一类是SDK Tools,如android.bat、ddms.bat和emulator.exe等等,这些命令位于&sdk&\tools目录,但运行仿真器所需的rom并不包含在内;另一类是Platform Tools,包含了如adb.exe、aidl.exe、aapt.exe等等命令,它们位于&sdk&\platform-tools目录。
请区别清这几个名称:SDK、SDK Tools、Platform Tools、Platform Package。
其他下载地址
官方推荐下载这个安装包,是32位和64位通用的。
文件名里虽然是"sdk",其实不含platform-tools,叫"sdk tools"更合适。
SDK安装/解压缩后,只具有基本的功能,还无法开始进行开发。你还需要platform-tools和至少一个platform package才算完整。在eclipse里通过SDK Manager是可以在线安装的,但有时手动安装也许更快。
其他下载地址
将platform-tools目录解压到sdk所在目录 &&
假如你已经安装过android sdk,想单独升级tools,可以从下面的文件中选择所需要的压缩包下载,然后替换掉sdk目录下的对应子目录。
其他下载地址
和第一个表里的"sdk"相比,只少了avd manager和sdk manager。建议仅在需要升级时下载,用tools目录替换原来的同名目录。
(Android Development Tools)是一个Eclipse插件,如果没有这个插件,我们开发Android应用就得不停在命令行里敲各种命令,除非你是记事本开发狂人,否则还是老老实实享受ADT带来的方便吧。至于Eclipse本身可以去下载,这里就不再提供了。
其他下载地址
如果你不习惯新版的ADT,这个版本也许适合你。
ADT的版本号基本上是跟着SDK Tools走,即每出一个新版本的SDK Tools,就出一个同样版本的ADT。不过实际使用中,即使是老版本的ADT也能对新版SDK支持得不错。
Android系统版本从1.0到写这篇帖子时的4.2,大大小小已经经历了10多个版本,每个版本发布时Google都会提供一个sdk platform package供开发者使用。一般这个压缩包是在Eclipse开发环境里用SDK Manager来下载的,但在国内选择这种方式会很痛苦,因为每个platform都有几十上百兆大,装一个就得几个小时,好像还不能断点续传(?)。
在国内,更方便的做法是先下载离线包,然后解压缩到android sdk的安装目录下,重启Eclipse后就会自动识别出来。
其他下载地址
Android 6.0
Android 5.1.1
Android 5.0
Android 4.2
Android 4.1, 4.1.1, JELLY_BEAN
android-15_r03.zip
Android 4.0.3, 4.0.4,&ICE_CREAM_SANDWICH_MR1
Android 4.0, 4.0.1, 4.0.2, ICE_CREAM_SANDWICH
android-3.2_r01-linux.zip
API Level 13, HONEYCOMB_MR2文件名虽然有linux但其实是平台无关的,下同,直至2.1。
android-3.1_r03-linux.zip
API Level 12, HONEYCOMB_MR1
android-3.0_r02-linux.zip
API Level 11, HONEYCOMB
API Level 10, GINGERBREAD_MR1
android-2.3.1_r02-linux.zip
API Level 9, GINGERBREAD
android-2.2_r03-linux.zip
API Level 8, FROYO
android-2.1_r03-linux.zip
API Level 7, ECLAIR_MR1
android-2.0_r01-windows.zip
API Level 5, ECLAIR
API Level 6, ECLAIR_0_1
API Level 4, DONUT
API Level 3, CUPCAKE
API Level 2&&&
更详细的Android版本对照表可以参考。
System Images
从Level 14开始,每个platform package都被分为两部分了,一部分包含这个版本下开发所需的jar包,例如android-16_r03.zip;另一部分是system image(即仿真器rom文件),例如sysimg_armv7a-16_r03.zip。如果你要在电脑上使用仿真器,需要有对应版本的system image文件;而如果你只在真机上调试程序,则不需要下载仿真器rom。
下载后的sysimg文件直接解压缩到sdk/system-images目录下,例如sdk/system-images/android-17。
其他下载地址
仅仿真器rom
仅仿真器rom
sysimg_armv7a-15_r02.zip
仅仿真器rom
sysimg_armv7a-14_r02.zip
仅仿真器rom
最近的版本除了arm仿真器,还有x86仿真器可供下载(由intel提供),在x86电脑上运行能够提速。
另:补充&凌寒00&网友提供的安装说明:&在sdk下建system-images文件夹,然后进入其中建立对应于api level的文件夹 类似于这样 android-17 ,然后把下载的映像文件解压后放到里面就可以了。...路径示例 F:\adt-bundle-windows-x86_64-\sdk\system-images\android-17\armeabi-v7a。&
供Android开发参考用的官方文档,文件比较大。我习惯有一个本地的文档,然后配合使用,非常方便,文档里有不少内容源码里是没有的。
其他下载地址
docs-17_r01.zip
docs-16_r03.zip
docs-15_r02.zip
docs-14_r01.zip
我比较懒,从来没有用git下载过android源代码,如果你想用git下载,可以参考里的操作方法。
官方目前提供了一些源代码压缩包,如下表所列,这些压缩包可以attach到eclipse里方便随时F3查看;最重要的是,有了源代码以后,Eclipse里代码辅助出来的参数名再也不会是"arg0"、"arg1"这样的了。
其他下载地址
Google提供了丰富的开发示例,如果时间允许多看看这些例子代码和运行效果,对提升手机应用的设计开发能力肯定大有帮助。
其他下载地址
从官方下载后压缩得到。
samples-3.2_r01-linux.zip
samples-3.1_r01-linux.zip
samples-3.0_r01-linux.zip
samples-2.3_r01-linux.zip
samples-2.3.3_r01-linux.zip
samples-2.2_r01-linux.zip
samples-2.1_r01-linux.zip
兼容包。要支持低版本android系统需要在项目里引入相应的兼容包,例如Android 2.1里没有Fragment的概念,那么要开发一个使用Fragment的应用,就要引入support-v4这个jar包,并使用android.support.v4.Fragment来(替代android.app.Fragment)进行开发。
其他下载地址&
CardView,GridLayout都在这里面,Library源码形式
补充解释一下,support-v4表示需要手机上的android版本至少是level 4(即1.6)才能运行;support-v13包含support-v4里的所有api,所以如果项目里包含了v13.jar就不用再包含v4.jar。
除了上面这些以外,还有AddOns等分类没来得及整理,等有时间了找一下。
以上内容随时补充更新,欢迎提醒和纠错。
阅读(...) 评论()今天看啥 热点:
Android4.4制作自有SDK探析,android4.4sdk探析
Android4.4制作自有SDK探析&& & & &最近研究了一下android4.4制作自有SDK的东西。我们都知道,拿到Google的原始代码后,芯片公司会把它结合芯片去平台化,再发出芯片公司的SDK给客户,这种SDK通常情况下都是含全部工程代码环境的,当然里面有一些是以库形式发布的,是需要保密的。那么我们作为中游的技术公司,又有一定深度的功能定制、产品形态变更带来的SDK大量的修改,很多是费尽心血完成,当然这部分代码我们也是要完全保密的,及时我们把它包得再好,也费精力,还要给完整过程代码,好庞大,这种方式的延伸性不好,扩展性也不佳,同步代码相当的麻烦,那我们就可以把api留好,我们发布自己的SDK给第三方的合作方,这样第三方可以调到自己提供的私有api工作,又保护了自己的代码,也节省精力。那我们怎么制作SDK呢?下面介绍一下:& /****************************************************************************************************/声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处,谢谢!/*****************************************************************************************************/& & & & Android4.4代码量是相当巨大的,首先我们需要设置一下环境:& & & &$. Build/setupenv.sh& & & &如果是编译具体产品就是lunch具体的产品型号,再去make就可以了。& & & &我们要的是SDK,直接使用“make sdk”是不行的,网上有一些网友有提到,笔者也试过,会报一个Bluetooth方面的错误,往下走还会有其他的错误,具体原因得好好分析一下编译系统才知道,按理说也可以走通,笔者未试过。笔者接着用的是“make PRODUCT-sdk-sdk”& & & & &$make PRODUCT-sdk-sdk&& 一开始编译也是大量的错误上来,首先就是“sdk/eclipse/scripts/create_all_symlinks.sh:&第&285&行:&cd:&tools/base:&没有那个文件或目录”& & & &怎么办呢?有网友说用“repo init –reposync”,笔者用的是芯片公司提供的SDK,不是原生的SDK,所以这种方法是不大可行的。在我们的SDK里面确实没有发现tools/base目录,那怎么办呢?先屏蔽掉吧!相关的屏蔽如下:& & &&接着往下继续编译。又发现“device\generic\goldfish\camera\EmulatedCamera.cpp”这个文件有错误,只好手动把相应错误给亲手杀死,直接屏蔽。继续往下走,顺利的话可以build一会,然后就到自己的修改的代码里面了,假如我们在开发中大量使用了overlay的话,可能会有不少错误上来,这主要源于我们平时开发不够严谨,假如是在代码里引用了一个资源的字符串,放在了overlay里面,你编译特定产品的时候,因为overlay里面有,当然不会报错,但是你编译sdk,那对不起,没那么好说话,直接是找不到资源,退出编译,还有一些布局的xml文件,图片文件,字符串都需要拷贝一份到原始代码位置,平时偷懒的后果就是编译sdk的时候巨大的惩罚,那一个一个错误上来,好烦人,死伤大脑细胞无数。& & & & 基于这一点,平时在做应用的时候,大家还是要严谨一些。养成一个好习惯,日后工作都会顺畅很多。这些APK编译的问题都是可见的,也蛮繁重的,一个个来吧,没办法。接下来编译又遇到如下错误:frameworks/base/core/java/android/widget/earthrotate/GLRender.java:44: error 104: @param tag with name that doesn't match the parameter list: 'degree:'
frameworks/base/core/java/android/widget/earthrotate/GLRender.java:77: error 104: @param tag with name that doesn't match the parameter list: 'rox'
frameworks/base/core/java/android/widget/earthrotate/GLRender.java:78: error 104: @param tag with name that doesn't match the parameter list: 'degree:'
DroidDoc took 144 sec. to write docs to out/target/common/docs/offline-sdk
make: *** [out/target/common/docs/offline-sdk-timestamp] 错误 45
& 后面看了一下,也就是注释的部分出的问题。&修改前后对比如下:-
* dynamic rotation angle to rox
* @param rox
* @param degree: change degree every time
* dynamic rotation angle to rox
* @param rox the rox
* @param degree the degree change every time.
public void toRoatX(final float rox, final float degree) {
int what = 1;
float dx = rox - roatX;
@@ -70,11 +72,13 @@ public class GLRender implements Renderer {
h.sendEmptyMessage(what);
* dynamic rotation angle to rox
* @param rox
* @param degree: change degree every time
* dynamic rotation angle to rox
* @param roy the roy
* @param degree the degree every time.
public void toRoatY(final float roy, final float degree) {
int what = 1;
float dy = roy - roatY;
(END) & & & 差异一看就知道了,所以平时写这些注释也要严谨啊!& & & 解决完这些自己埋下的隐患,继续往下走,会出现如下错误:sdk/build/tools.atree:124: couldn't locate source file:tools/base/templates/projects
sdk/build/tools.atree:125: couldn't locate source file:tools/base/templates/activities
sdk/build/tools.atree:126: couldn't locate source file:tools/base/templates/gradle
sdk/build/tools.atree:127: couldn't locate source file:tools/base/templates/other
make: *** [out/host/linux-x86/sdk/android-sdk_eng.desheng_linux-x86.zip]错误 44& & & & &&因为没有tools/base,所以我们把它先屏蔽掉,继续编译,顺利完成!看到如下的图片,心中一阵窃喜。& & & &生成的sdk在“android\out\host\linux-x86\sdk”下面,android-sdk_eng.desheng_linux-x86.zip,一个680M的大家伙!& & & & &接下来就是验证这个sdk是否可用了。& & & & &验证的方法也就是解压这个压缩文件,再拿一个需要调用私有api的应用去依赖这个sdk,编译一下,看看能不能编译通过,再推送到机器里面去跑一下就知道了。很幸运,笔者的sdk验证通过!& & & & 笔者验证的时候遇到新建项目会有些问题,主要是一些工具的问题,这可能跟 tools/base下面的东西有关,那么针对这个问题,我想可以这样去解决,用自己平时编译用的SDK环境,再替换相应api级下的android.jar即可,这种方法验证是可行的。制作SDK还是蛮辛苦的一件事,辛苦归辛苦,后面工作高效了就是巨大的汇报!加油!&
相关搜索:
相关阅读:
相关频道:
Android教程最近更新最新安卓5.0系统下载:
安卓5.1刷机包 官方下载地址
包是一款最新版本的,这款最新版的全面升级安卓智能系统对桌面及其透明度进行修整解决碎片化问题,相比现在的版本来说,会有很大的改变和突破,安卓5.0刷机包还未发布,小编会第一时间带给大家。&
android5.0系统介绍&
1.谷歌每半年就更新一次Android,然而硬件厂商并未按图索骥,往往忽略一些不重要的版本跨代升级,用户也会用&刷机&来投票。比较目前Android各版本的占有率,Android&4.1和2.3仍然占据绝对优势,充分证明了这两个版本在Android迭代进程中举足轻重的地位。如此看来,Android的重大更新也是大概2年1次。因此2014年的Android&5.0值得期待。&
2.Android的2013年并不顺利,虽然席卷新兴市场,然而在高端市场面对i7和iPhone5s信心不足。在美国日本,Android的份额持续失血,圣诞消费季的表现被完全压制。2014年,传闻中的大屏iPhone即将到来,Android阵营的领袖三星却遇到了增长瓶颈,谷歌自家的Moto&X仍是小众的玩物。因此在5月份I/O大会(开发者大会)上,Android&5.0必须要证明自己。&
安卓5.0系统新增功能:&
1.碎片化问题得到解决&
据说,此版本解决碎片化问题,碎片化问题将不那么严重,之后版本碎片化问题将越来越少。&
2.个人数据无痛迁移&
iPhone用户忠诚度高,一方面由于其用户体验更具黏性,而常被忽视的一点是Android至今尚未实现个人数据跨终端的转移。谷歌董事长施密特上个月亲自撰写博客,教用户如何从iPhone向Android手机导入通讯录。谷歌账户只能保存通讯录、日历等。而照片、音乐、进度的迁移需要繁琐的第三方甚至是ROOT权限。Android目前的MD5签名验证规则导致很多数据的备份还原只能在同一手机上进行,希望Android&5.0至少在AOSP项目内的旗舰机型之间能实现数据无痛迁移。&
3.独立的平板生态&
去年11月谷歌终于在Play商店中开放了平板专区,更早些时候在SDK中加入了平板优化。Nexus平板比iPad落后太多。杜阿尔特似乎对于硬件的设计不如软件那么得心应手,谷歌是否应该考虑引入一个更强势的硬件设计VP。而且并不是所有的开发者都有精力制作独立的平板应用,手机仍是移动互联网的主战场,即使是腾讯和阿里这样的巨头,你也能从HD版应用中看出他们的三心二意。在Android&5.0的SDK中,如果能引入对大屏设备的自动优化,可以极大减轻开发者的负担,比如增大图片占比,优化字体,button自适应。&
4.优化功能键&
推荐内容:33332人阅读
&&&&&& 前面101篇文章都是分析Android系统源码,似乎不够接地气。如果能让Android系统源码在真实设备上跑跑看效果,那该多好。这不就是传说中的刷ROM吗?刷ROM这个话题是老罗以前一直避免谈的,因为觉得没有全面了解Android系统前就谈ROM是不完整的。写完了101篇文章后,老罗觉得第102篇文章该谈谈这个话题了,并且选择CM这个有代表性的ROM来谈,目标是加深大家对Android系统的了解。老罗的新浪微博:,欢迎关注!&&&&&& 说起刷ROM的动机,除了上面说的用来看Android系统源码在真实设备上的运行效果,还有很多值得说的。回想起PC时代,我们对我们自己拥有的设备(电脑),基本上能做的就是在上面重装系统。这个系统是厂商做好给我们的,里面有什么我们就用什么,不能随心所欲地定制。当然,如果你用的是Linux系统,你是可以随心所欲地对它进行定制的。不过可惜的是,我们的女神用的都是Windows系统。你和女神说你想要什么样的Linux系统,我给你定制一个,她会不知道你说的是什么——她需要的是一个不会中毒的又跑得快的Windows系统而已。现如今虽然很多女神用的是仍然是我们不能随心所欲定制的iOS系统,但是在移动设备上,iOS系统毕竟不能做到Windows在PC那样的一家独大——我们还有不少女神是用Android系统的。所以,如果你现在和女神说,我可以帮你刷一个专属的精简Android系统,里面没有一堆你不需要的预装软件,会让你的手机跑得很快,那女神得有多崇拜你啊。&&&&&& 当然,刷ROM的动机不能只是为了让女神崇拜,作为一个程序猿,我们的首要任务是维护宇宙和平。怎么维护呢?至少程序有BUG不能不改吧。你不改的话,老板是不会放过你的。但是,碰到那些很棘手的BUG,怎么办呢?例如,你是一个Android应用开发者,调用一个API接口的时候,总是抛出一个异常,而这个异常不跟到API内部实现去看看实在是不知道什么原因造成的。这时候,如果你手头上有这个手机的系统源代码,找这个API内部实现的地方,加一两行调试代码,再编译回手机上去跑,是不是就很容易定位问题了呢?&&&&&&& 所以说,会刷ROM,不只是可以获得女神崇拜,还可以维护世界和平,作为一个Android开发者,你还有什么理由不去学习刷ROM呢?既然你决定学习刷ROM了,那你就得先搞清楚两个问题:1. 什么是刷ROM;2. 怎么学习刷ROM。&&&&&&& 在回答第一个问题之前,我们先来看看Android设备从硬件到系统的结构,如图1所示:图1 Android系统架构&&&&&& 最底层的是各种硬件设备,往上一层是Bootloader。Bootloader是什么概念呢?我们都知道,PC主板上有一小段程序叫做BIOS,主板加电时它是第一个跑起来的程序,负责初始化硬件,以及将OS启动起来。在嵌入式世界里(手机也是属于嵌入式设备),也有一小段类似BIOS的程序,不过它不叫BIOS,而是叫Bootloader。使用最广泛的Bootloader是一个叫uboot的程序,它支持非常多的体系结构。经过编译后,uboot会生成一个uboot.bin镜像,将这个镜像烧到设备上的一个特定分区去,就可以作为Bootloader使用了。&&&&&&& Bootloader支持交互式启动,也就是我们可以让Bootloader初始化完成硬件之后,不是马上去启动OS,而是停留在当前状态,等待用户输入命令告诉它接下来该干什么。这种启动模块就称为Fastboot模式。对于Android设备来说,我们可以通过adb reboot bootloader命令来让它重新启动并且进入到Fastboot模式中去。&&&&&&& 在讨论Fastboot模式之前,我们先了解一下嵌入式设备的ROM结构(NAND flash之类的芯片)。通常,一个能够正常启动的嵌入式设备的ROM包含有以下四个分区:&&&&&&& 1. Bootloader分区,也就是存放uboot.bin的分区&&&&&&& 2. Bootloader用来保存环境变量的分区&&&&&&& 3. Kernel分区,也就是存放OS内核的分区&&&&&&& 4. Rootfs分区,也就是存入系统第一个进程init对应的程序的分区&&&&&&& 当设备处于Fastboot模式时,我们可以通过另外一个工具fastboot来让设备执行指定的命令。对搞机者来说,最常用的命令就是刷入各种镜像文件了,例如,往Kernel分区和Rootfs分区刷入指定的镜像。&&&&&&& 对于Android设备来说,当它处于Fastboot模式时,我们可以将一个包含有Kernel和Rootfs的Recovery.img镜像通过fastboot工具刷入到一个称为设备上一个称为Recovery的分区去。这个过程就是刷Recovery了,它也是属于刷ROM的一种。由于Recovery分区包含有Kernel和Rootfs,因此将Recovery.img刷入到设备后,我们就可以让设备正常地启动起来了。这种启动方式就称为Recovery模式。 对于Android设备来说,我们可以通过adb reboot recovery命令来让它进入到Recovery模式中去。& & & & 当设备处于Recovery模式时,我们可以做些什么呢?答案是取决于刷入的Recovery.img所包含的Rootfs所包含的程序。更确切地说,是取决于Rootfs镜像里面的init程序都做了些什么事情。不过顾名思义,Recovery就是用来恢复系统的意思,也包含有更新系统的意思。这里所说的系统,是用户正常使用的系统,里面包含有Android运行时框架,使得我们可以在上面安装和使用各种APP。&&&&&& 用户正常使用Android设备时的系统,主要是包含有两个分区:System分区和Boot分区。System分区包含有Android运行时框架、系统APP以及预装的第三方APP等,而Boot分区包含有Kernel和Rootfs。刷入到System分区和Boot分区的两个镜像称为system.img和boot.img,我们通常将它们打包和压缩为一个zip文件,例如update.zip,并且将它上传到Android设备上的sdcard上去。这样当我们进入到Recovery模式时,就可以在Recovery界面上用我们之前上传到sdcard的zip包来更新用户正常使用Android设备时所用的系统了。这个过程就是通常所说的刷ROM了。&&&&&& 不知道大家看明白了没有?广义上的刷ROM,实际上包含更新Recovery和更新用户正常使用的系统两个意思;而狭义上的刷ROM,只是更新用户正常使用的那个系统。更新Recovery需要进入到Fastboot模式中,而更新用户正常使用的那个系统需要进入到Recovery模式中。Android设备在启动的过程中,在默认情况下,一旦Bootloader启动完成,就会直接启动用户正常使用的那个系统,而不会进入到Recovery模式,或者停留在Bootloader中,也就是停留在Fastboot模式中。只有通过特定的命令,例如adb reboot recovery和adb reboot bootloader,或者特定的按键,例如在设备启动过程中同时按住音量减小键和电源开关键,才能让设备进入到Recovery模式或者Fastboot模式中。&&&&&& 因此,一个完整的刷ROM过程,包含以下两个步骤:&&&&&& 1. 让设备进入到Fastboot模式,刷入一个recovery.img镜像&&&&&& 2. 让设备进入到Recovery模式,刷入一个包含system.img镜像和boot.img镜像的zip包&&&&&& 不过需要注意的是,system.img镜像和boot.img镜像不一定是只有在Recovery模式才能刷入,在Fastboot模式下也是可以刷入的,就像在Fastboot模式中刷入recovery.img镜像一样,只不过在Recovery模式下刷入它们更友好一些。说到这里,就不得不说另外一个概念,就是所谓的Bootloader锁。在锁定Bootloader的情况下,我们是无法刷入非官方的recovery.img、system.img和boot.img镜像的。这是跟厂商实现的Bootloader相关的,它们可以通过一定的算法(例如签名)来验证要刷入的镜像是否是官方发布的。在这种情况下,必须要对Bootloader进行解锁,我们才可以刷入非官方的镜像。&&&&&& 好了,以上就回答了什么是刷ROM这个问题,接下来我们要回答的是如常学习刷ROM这个问题。&&&&&& 前面我们提到了刷ROM的两个步骤,实际上我们还少了一个重要的步骤,那就是先要制作recovery.img、system.img和boot.img。有人可能会说,网上不是很多现成的刷机包吗?直接拿过来用不就是行了吗?但是别忘了前面我们所说的刷ROM动机:随心所欲地定制自己的系统。去拿别人制好的刷机包就失去了随心所欲定制的能力。那就只能自己去编译AOSP源码生成刷机包了。&&&&&& 然而,从零开始从AOSP源码中编译出能在自己使用的手机上运行的系统,可不是一件容易的事情。不过,好在有很多现成的基于AOSP的第三方开源项目,可以编译出来在目前市场上大部分的手机上运行。其中,最著名的就是了,简称CM。国内大部分的第三方Android系统,都是基于CM来开发的,包括MIUI和锤子。&&&&&& 选择CM来讲解刷ROM的过程是本文的主题。不过单就刷ROM这个过程来说,CM官网上已经有很详细的过程,包括从CM源码编译出适用特定机型的刷机包,以及将编译出来的刷机包刷到手机里面去的过程。因此,本文不是单纯地讲解刷ROM过程,而是要结合原理来讲解刷ROM过程的关键步骤,来达到帮助大家更进一步地理解Android的目的。&&&&&&& 要真正做到理解CM ROM的刷机原理,除了要对Android系统本身有一定的认识之外,还熟练掌握Android的源码管理系统和编译系统。因此,在继续阅读下面的内容之前,希望可以先阅读前面和这两个系列的文章。接下来我们就开始讲解CM ROM的刷机过程和原理。&&&&&&& 我们首先是要准备好环境以及手机。这是本次操作所用的环境以及手机:&&&&&&& 1. Ubuntu 13.04&&&&&&& 2. CM-10.1&&&&&&& 3. OPPO Find 5&&&&&&& 也就是说,我们将在Ubuntu 13.04上为OPPO Find 5制作CM-10.1的Recovery和ROM。&&&&&&& 不过先别急着制作自己的ROM。为了保证接下来的步骤可以顺利执行,我们首先尝试刷一下CM官方对应版本的Recovery和ROM到我们的OPPO Find 5手机上。如果一切正常,就说明我们使用CM的源码来制作的Recovery和ROM也是可以运行在OPPO Find 5上的。&&&&&&& 适合OPPO Find 5的CM官方Recovery下载地址:。假设我们下载好之后,保存在本地的路径为$CM/recovery-clockwork-6.0.4.6-find5.img。&&&&&&& 适合OPPO Find 5的CM官方10.1.3版本ROM下载地址:。假设我们下载好之后,保存在本地的路径为$CM/cm-10.1.3.find5.zip。&&&&&&& 注意,由于我们计划用CM-10.1源码来制作自己的ROM,所以我们在下载CM官方ROM,也要下载对应10.1版本的。&&&&&&& 在刷Recovery和ROM的过程中,我们需要借助于Android SDK里面的fastboot和adb工具,因此,为了方便执行这些命令,我们先将这些工具的目录加入到PATH环境变量去。假设我们下载的Android SDK保存在目录$ASDK中,那么打开一个终端,执行以下命令即可:$ export PATH=$ASDK/platform-tools:$PATH&&&&&&& 先刷Recovery,步骤如下所示:&&&&&&& 1. 保持OPPO Find 5在正常开机状态,并且通USB连接到将有Ubuntu 13.04的电脑上。&&&&&&& 2. 还是在刚才打开的终端上,并且进入到保存recovery-clockwork-6.0.4.6-find5.img的目录$CM。$ cd $CM&&&&&&& 3. 执行以下命令让OPPO Find 5重启,并且进入Fastboot模式。$ adb reboot bootloader&&&&&&& 4. 可以看到OPPO Find 5停留在Fastboot界面上,执行以下命令确保fastboot工具能够连接到OPPO Find 5。$ fastboot devices&&&&&& 如果能够连接,那么上述命令将会输出一串标识OPPO Find 5的ID。&&&&&& 5. 刷入我们刚才下载的Recovery。$ fastboot flash recovery recovery-clockwork-6.0.4.6-find5.img&&&&&& 6. 提示刷入成功后,执行以下命令正常重启手机。$ fastboot reboot&&&&&& 如果一切正常,手机将进入到原来的系统中。&&&&&& 继续在上述打开的终端上,刷CM-10.1.3 ROM,步骤如下所示:&&&&&& 1. 将下载好的cm-10.1.3.find5.zip上传至OPPO Find 5的sdcard上$ adb push cm-10.1.3.find5.zip /sdcard/cm-10.1.3.find5.zip&&&&&& 2. 执行以下命令让OPPO Find 5重启,并且进入Recovery模式。$ adb reboot recovery&&&&&& 进入到Recovery模式后,我们将看到显示的Recovery版本号为6.0.4.6,这表明我们现在进入的就是刚才我们刷入的Recovery。&&&&&& 3. 在刷入新的ROM前,我们先备份一下当前的ROM,以防万一刷机失败,可以进行恢复。在Recovery界面中,通过音量增大/减小键,选中“backup and restore”选项,按下电源键,进入下一个界面,同样是通过音量增大/减小键,选中“backup”,按下电源键,就可以对当前系统进行备份了。&&&&&& 4. 备份完成之后,我们还要清除手机上的数据,恢复至出厂设置。回到Recovery界面中,通过音量增大/减小键,选中&wipe data/factory reset&,按下电源键,确认后即可进行清除数据,并且恢复至出厂设置。&&&&&& 5. 清除数据完成之后,再回到Recovery界面上,通过音量增大/减小键,选中“install zip”选项,按下电源键,进入下一个界面,同样是通过音量增大/减小键,选中“choose zip from sdcard”,按下电源键,找到前面我们上传至sdcard的cm-10.1.3.find5.zip,确认之后就可以进行刷机了。&&&&&& 6. 刷机完成后,再回到Recovery界面上,通过音量增大/减小键,选中“reboot system now”选项,按下电源键,正常启动系统。&&&&&& 如果一切正常,手机将进入到刚才刷入的CM-10.1.3系统中。&&&&&& 现在我们就可以确定OPPO Find 5可以正常运行CM-10.1.3的系统了。接下来激动人心的时刻就要开始了,我们将要自己下载和编译CM-10.1源码,并且将编译出来的Recovery和ROM刷入到OPPO Find 5去。同时,在接下来的步骤中,我们会将相关的原理讲清楚,以便我们可以更好地理解Android系统的结构,这也是本文的重点之一。以下假设我们将CM-10.1源码保存在目录$CMSOURCE中,并且已经按照Android官网文档的要求初始化好Android的源码编译环境,即在我们的Ubuntu机器上安装了要求的软件,详情请参考:。&&&&&&& 1. 进入到$CMSOURCE目录中。$ cd $CMSOURCE&&&&&&& 2. 将当前目录初始为CM-10.1分支源码的Git仓库。$ repo init -u git:///CyanogenMod/android.git -b cm-10.1&&&&&&& 3. 下载CM-10.1分支源码。$ repo sync&&&&&&& 以上两步都是关于Android源码仓库的知识,可以参考一文,这里不再详述。&&&&&&& 4. 进入到$CMSOURCE目录下的vendor/cm子目录中,并且执行里面的get-prebuilts脚本,用来获得一些预编译的APP。$ ./get-prebuilts&&&&&&& 打开$CMSOURCE/vendor/cm/get-prebuilts文件,它的内容如下所示:BASEDIR=`dirname $0`
mkdir -p $BASEDIR/proprietary
# Get Android Terminal Emulator (we use a prebuilt so it can update from the Market)
curl -L -o $BASEDIR/proprietary/Term.apk -O -L /Android-Terminal-Emulator/downloads/Term.apk
unzip -o -d $BASEDIR/proprietary $BASEDIR/proprietary/Term.apk lib/*&&&&&&& 我们可以发现,实际上这里只是去下载一个叫做Android Terminal Emulator的APP,地址是/Android-Terminal-Emulator/downloads/Term.apk。这个APP最终会包含在我们自己编译出来的ROM。它用来Android手机上模拟出一个终端来,然后我们就可以像在Linux主机上一样执行一些常用的Linux命令。是不是很酷呢?原来Android手机不单止可以运行我们常见的APP,还可以运运我们常用的Linux命令。关于这个Android Terminal Emulator的安装和介绍,参可以这里:。此外,这个Android Terminal Emulator还可以配合另外一个封装了busybox的kbox工具,用来在Android手机上获得更多的Linux常用命令,kbox的安装和介绍,可以参考这里:。&&&&&&& 5. 回到$CMSOURCE目录中,将build子目录下的envsetup.sh脚本加载到当前终端来。$ source build/envsetup.sh&&&&&&& 参考一文,envsetup.sh脚本加载到当前终端后,我们就可以获得一系列与Android编译系统相关的命令,例如lunch/m/mm/mmm,以及下一步要执行的breakfast命令。&&&&&&& 6. 为OPPO Find 5下载相关的源码。$ breakfast find5&&&&&&& 在这个系列的文章中,我们提到,在编译Android的官方源码之前,我们需要执行一个lunch命令来为我们的目标设备初始化编译环境。这个lunch命令是由Android官方源码的envsetup.sh脚本提供的。CM修改envsetup.sh脚本,额外提供了一个breakfast命令,用来从网上寻找指定的设备相关的源码,以便我们可以为该设备编译出能运行的ROM来。&&&&&&& 打开envsetup.sh文件,查看breakfast的实现:function breakfast()
CM_DEVICES_ONLY=&true&
unset LUNCH_MENU_CHOICES
add_lunch_combo full-eng
for f in `/bin/ls vendor/cm/vendorsetup.sh 2& /dev/null`
echo &including $f&
if [ $# -eq 0 ]; then
# No arguments, so let's have the full menu
echo &z$target& | grep -q &-&
if [ $? -eq 0 ]; then
# A buildtype was specified, assume a full device name
lunch $target
# This is probably just the CM model name
lunch cm_$target-userdebug
}& & & & 函数breakfast主要是做了以下两件事情。&&&&&&& 第一件事情是检查vendor/cm目录下是否存在一个vendorsetup.sh文件。如果存在的话,就将它加载到当前终端来。注意,这里是通过ls命令来检查文件endor/cm/vendorsetup.sh是否存在的。如果不存在的话,标准输出就为空,而错误信息会重定向至/dev/null。如果存在的话,字符串“endor/cm/vendorsetup.sh”就会输出到标准输出来,也就是变量f的值会等于“endor/cm/vendorsetup.sh”。&&&&&&& 接下来我们就看看文件endor/cm/vendorsetup.sh的内容:for combo in $(curl -s /CyanogenMod/hudson/master/cm-build-targets | sed -e 's/#.*$//' | grep cm-10.1 | awk {'print $1'})
add_lunch_combo $combo
done&&&&&&& 它所做的工作就是将的内容下载回来,并且去掉其中的空行,最后将含有&cm-10.1&的行的第1列取出来,并且通过add_lunch_combo命令将其加入到Android编译系统的lunch菜单去。&&&&&&& 从下载回来的是官方CM所支持的机型列表,格式为cm_&product&-&variant& &version&,以下列出的是部分内容:# CM build target list
# &lunchcombo& &branch& [period: &D&aily, &W&eekly or &M&onthly]
# Absence of a period indicates Daily (the default)
cm_a700-userdebug cm-11.0
cm_acclaim-userdebug cm-11.0
cm_amami-userdebug cm-11.0
cm_anzu-userdebug jellybean M
cm_apexqtmo-userdebug cm-11.0
cm_aries-userdebug cm-11.0
cm_captivatemtd-userdebug cm-11.0
......&&&&&&& 由此可见,执行脚本endor/cm/vendorsetup.sh之后,cm-10.1所支持的机型就会增加到lunch菜单中去。&&&&&&& 回到函数breakfast中,它所做的第二件事情是检查执行函数是否带有参数,即变量target的值是否等于空。如果变量target的值不等于空,并且它的值是&product&-&variant&的形式,那么就直接以它为参数,调用lunch函数。否则的话,就以cm_$target-userdebug为参数,调用lunch函数。&&&&&&& 在这一步中,我们调用breakfast函数时,传进来的参数为find5,不是&product&-&variant&的形式,因此,函数breakfast最后会以cm_find5-userdebug为参数,调用lunch函数。&&&&&&& 函数lunch的实现我们在前面一篇文章已经分析过了,不过当时分析的是AOSP官方版本的实现,CM对其进行了一些修改,增加了一些CM自有的逻辑,下面我们就看看这些修改:function lunch()
local product=$(echo -n $selection | sed -e &s/-.*$//&)
check_product $product
if [ $? -ne 0 ]
# if we can't find a product, try to grab it off the CM github
T=$(gettop)
pushd $T & /dev/null
build/tools/roomservice.py $product
popd & /dev/null
check_product $product
build/tools/roomservice.py $product true
}&&&&&& 这里的变量selection的值就等于我们传进来的参数&cm_find5-userdebug&,通过sed命令将&cm_find5&提取出来,并且赋值给变量product。接下来调用check_product函数来检查当前的CM源码中是否支持find5这个设备。&&&&&& 如果不支持的话,那么它的返回值就不等于0,即#?不等于0,那么接下来就会通过build/tools/roomservice.py到CM源码服务器去检查是否支持find5这个设备。如果CM源码服务器支持find5这个设备的话,那么build/tools/roomservice.py就会将与find5相关的源码下载回来。这时候我们就会发现本地CM源码目录中多了一个device/oppo/find5目录。里面存放的都是编译find5的ROM时所要用的文件。&&&&&& 另一方面,如果当前的CM源码中已经支持find5这个设备,那么函数lunch也会调用build/tools/roomservice.py去CM源码服务器检查当前CM源码目录中find5设备依赖的其它源码是否有更新,或者是否有新的依赖。如果有的话,就将这些依赖更新下载回来。&&&&&& 脚本build/tools/roomservice.py的详细内容这里就不分析了,下面主要是解释一下与Android的源码仓库管理工具Repo相关的逻辑。关于Android的源码仓库管理工具Repo的详细分析,可以参考一文。&&&&&& CM源码服务器放在github上,地址为,上面保存的是CM修改过的AOSP工程、CM支持的设备相关源码工程(下载回来放在device/&manufacturer&/&device&目录中),以及CM支持的设备对应的内核源码工程(下载回来放在kernel/&manufacturer&/&device&目录中)。&&&&&& 脚本build/tools/roomservice.py会根据传进来的第一个参数,到CM源码服务上检查是否存在相应的工程。在我们这个场景中,传给build/tools/roomservice.py的第一个参数为cm_find5。这时候前面的cm_会被去掉,然后到CM源码服务上检查是否存在一个android_device_&manufacturer&_find5的工程。如果存在的话,那么就会将它下载回来,保存在device/&manufacturer&/find5目录中。这里的&manufacturer&对应的就是oppo了。&&&&&& 下载回来的设备相关源码实际上是作为是一个Git仓库来管理的,因此,脚本build/tools/roomservice.py还需要将该Git仓库纳入到Repo仓库去管理,以便以后执行repo sync命令时,可以同时对这些设备相关的源码进行更新。&&&&&&& 从一文可以知道,Repo仓库保存在.repo目录中,而它所管理的Git仓库由.repo/manifest.xml文件描述。文件.repo/manifest.xml实际上只是一个符号链接,它链接至.repo/manifests/default.xml文件。目录.repo/manifests实际上也是一个Git仓库,用来描述当前的CM源码目录都是由哪些工程构成的,并且这些工程是来自于哪些Git远程仓库的。&&&&&& 如果按照标准的Repo仓库管理方法,从CM源码服务器上下载回来设备相关源码之后,应该往.repo/manifests/default.xml文件增加相应的描述,以后repo工具可以对这些设备相关的源码进行管理。但是,由于Repo仓库是由官方维护的,当我们在本地往.repo/manifests/default.xml增加了新的内容之后,下次执行repo sync命令时,.repo/manifests/default.xml的内容又会被恢复至修改前的样子,因此,修改.repo/manifests/default.xml文件是不适合的。CM采用另外一个办法,那就是在.repo目录下另外创建一个local_manifests目录,在里面可以随意增加任意命名的xml文件,只要这些xml文件的规范与.repo/manifests/default.xml文件的规范一致即可。执行repo sync命令时,它就会同时从.repo/manifests/default.xml和.repo/local_manifests目录下的xml文件中读取当前都有哪些源码工程需要更新。&&&&&& 实际上,在.repo/local_manifests目录下的xml文件,除了可以描述新增的工程之外,还可以描述要删除的工程。例如,如果我们不想将某一个系统功能或者系统APP编译到我们自己制作的ROM去,那么就可以在.repo/local_manifests目录下增加一个xml文件,里面描述我们需要删除对应的工程。这样,当我们从服务器下载回来相应的工程之后,它们就会在本地中被删除。这样就做到了很好的定制化编译,而且又不会与官方的源码结构产生冲突。关于CM的Local Manifests机制,可以参考官方文档:。&&&&&& 脚本build/tools/roomservice.py将下载回来的设备相关源码纳入到Repo仓库管理的办法就是在.repo/local_manifests目录下创建一个roomservice.xml文件。例如,当我们从CM源码服务器下载回来find5相关的设备源码之后,就可以看到在roomservice.xml文件中看到相应的一行内容:&?xml version=&1.0& encoding=&UTF-8&?&
&manifest&
&project name=&CyanogenMod/android_device_oppo_find5& path=&device/oppo/find5& remote=&github& /&
&/manifest&&&&&&& 这表明本地的device/oppo/find5目录是来自于远程仓库github的,并且相对路径为CyanogenMod/android_device_oppo_find5。&&&&&& 好了,现在我们终于将OPPO Find 5相关的设备源码下载回来了,但是在编译之前。需要从OPPO Find 5上提取一些设备相关的私有文件。&&&&&& 7. 保持OPPO Find 5开机状态,并且通过USB连接到Ubuntu 13.04上,进行到$CMSOURCE/device/oppo/find5目录中,执行以下命令提取设备私有文件。$ ./extract-files.sh&&&&&& 脚本extract-files.sh的内容如下所示:#!/bin/sh
VENDOR=oppo
DEVICE=find5
BASE=../../../vendor/$VENDOR/$DEVICE/proprietary
rm -rf $BASE/*
for FILE in `cat proprietary-blobs.txt | grep -v ^# | grep -v ^$ | sed -e 's#^/system/##g'`; do
DIR=`dirname $FILE`
if [ ! -d $BASE/$DIR ]; then
mkdir -p $BASE/$DIR
adb pull /system/$FILE $BASE/$FILE
./setup-makefiles.sh&&&&&& 首先是创建一个vendor/oppo/find5/proprietary目录,接着是读取文件proprietary-blobs.txt中的每一行,并且将每一行所描述的文件从设备上的/system目录中获取出来,保存在vendor/oppo/find5/proprietary对应的子目录下面,最后再执行另外一个脚本setup-makefiles.sh。&&&&&& 文件device/oppo/find5/proprietary-blobs.txt部分的内容如下所示:/bin/btnvtool
/bin/ds_fmc_appd
/bin/efsks
/bin/hci_qcomm_init
/bin/mm-qcamera-daemon
/bin/mpdecision
/bin/netmgrd
/bin/nv_tee
/bin/qmuxd
......&&&&&& 这里列出的文件路径都是相对于设备上的/system目录的,并且都是设备特定的、不公开源码的,因此,我们需要从设备上获取出来。&&&&&& 再来看脚本setup-makefiles.sh的内容:#!/bin/sh
VENDOR=oppo
DEVICE=find5
OUTDIR=vendor/$VENDOR/$DEVICE
MAKEFILE=../../../$OUTDIR/$DEVICE-vendor-blobs.mk
(cat && EOF) & $MAKEFILE
# Copyright (C) 2013 The CyanogenMod Project
# Licensed under the Apache License, Version 2.0 (the &License&);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an &AS IS& BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This file is generated by device/$VENDOR/$DEVICE/setup-makefiles.sh
PRODUCT_COPY_FILES += \\
LINEEND=& \\&
COUNT=`cat proprietary-blobs.txt | grep -v ^# | grep -v ^$ | wc -l | awk {'print $1'}`
for FILE in `cat proprietary-blobs.txt | grep -v ^# | grep -v ^$ | sed -e 's#^/system##g' -e 's#^/##g'`; do
COUNT=`expr $COUNT - 1`
if [ $COUNT = &0& ]; then
LINEEND=&&
$OUTDIR/proprietary/$FILE:system/$FILE$LINEEND& && $MAKEFILE
(cat && EOF) & ../../../$OUTDIR/$DEVICE-vendor.mk
# Copyright (C) 2013 The CyanogenMod Project
# Licensed under the Apache License, Version 2.0 (the &License&);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an &AS IS& BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This file is generated by device/$VENDOR/$DEVICE/setup-makefiles.sh
# Pick up overlay for features that depend on non-open-source files
DEVICE_PACKAGE_OVERLAYS := vendor/$VENDOR/$DEVICE/overlay
\$(call inherit-product, vendor/$VENDOR/$DEVICE/$DEVICE-vendor-blobs.mk)
(cat && EOF) & ../../../$OUTDIR/BoardConfigVendor.mk
# Copyright (C) 2013 The CyanogenMod Project
# Licensed under the Apache License, Version 2.0 (the &License&);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an &AS IS& BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This file is generated by device/$VENDOR/$DEVICE/setup-makefiles.sh
USE_CAMERA_STUB := false
EOF&&&&&& 这个脚本主要就是用来在vendor/oppo/find5目录下生成两个文件:find5-vendor-blobs.mk和BoardConfigVendor.mk文件。这两个文件都是接下来为OPPO Find 5编译ROM时要用到的。&&&&&& 生成的find5-vendor-blobs.mk的部分内容如下所示:PRODUCT_COPY_FILES += \
vendor/oppo/find5/proprietary/bin/btnvtool:system/bin/btnvtool \
vendor/oppo/find5/proprietary/bin/ds_fmc_appd:system/bin/ds_fmc_appd \
vendor/oppo/find5/proprietary/bin/efsks:system/bin/efsks \
vendor/oppo/find5/proprietary/bin/hci_qcomm_init:system/bin/hci_qcomm_init \
vendor/oppo/find5/proprietary/bin/ks:system/bin/ks \
......&&&&&& 实际上就是通过PRODUCT_COPY_FILES变量告诉编译系统,要将刚才从设备上获取回来的文件打包到编译出来的ROM的system分区里面去。&&&&&& 生成的文件BoardConfigVendor.mk只有1行,如下所示:USE_CAMERA_STUB := false&&&&&& 在编译摄像头相关的库文件时,就会到这里定义的USE_CAMERA_STUB变量。&&&&&& 到目前为止,我们就分别从CM源码服务器和目标设备上获取到了编译OPPO Find 5的ROM所需要的设备相关的文件了,接下来就可以开始编译CM源码了。&&&&&& 8. 回到$CMSOUCE目录中,为OPPO Find 5编译ROM。$ brunch find5&&&&&& 命令brunch也是由build/envsetup.sh脚本提供的,它的实现如下所示:function brunch()
breakfast $*
if [ $? -eq 0 ]; then
echo &No such item in brunch menu. Try 'breakfast'&
}&&&&&& 函数brunch做了两件事情:执行breakfast命令和执行mka bacon命令。&&&&&& 前面我们不是已经执行过breakfast命令了吗?这里为什么又要再执行一次呢?从前面的分析可以知道,函数breakfast在执行的过程中,会调用函数lunch,而函数lunch又会调用函数check_product来检查目标设备是否存在。因为在前一步中,我们已经将目标设备相关的源码下载回来了,因此这时候目标设备是肯定存在的。当目标设备存在的时候,函数lunch会通过build/tools/roomservice.py脚本检查目标设备相关的源码是否依赖有其它工程,并且这些工程是否已经下载回来了。如果有依赖的工程,并且这些工程还没有下载回来,那么就需要将它们下载回来。&&&&&& 当目标设备存在的时候,函数lunch执行build/tools/roomservice.py脚本的形式为:build/tools/roomservice.py $product true&&&&&& 传递给build/tools/roomservice.py第二件参数为true,表示要处理的是目标设备$product依赖的工程。&&&&&& 脚本build/tools/roomservice.py是如何知道目标设备有没有依赖的工程的呢?原来,在下载回来的设备源码中,有一个cm.dependencies文件,里面描述了自己所依赖的工程。例如,device/oppo/find5/cm.dependencies的内容如下所示:[
&repository&: &android_kernel_oppo_find5&,
&target_path&: &kernel/oppo/find5&,
&branch&: &cm-10.1&
]&&&&&& 上面描述的是OPPO Find 5所使用的内核源码,它来自于CM源码服务器上的android_kernel_oppo_find5仓库的cm-10.1分支,下载回来后保存在kernel/oppo/find5目录中。这意味着我们通过CM源码编译出来的ROM所使用的内核也是由我们自己编译出来的。&&&&&& 为了以后执行repo sync命令同步本地源码时,也可以将设备源码依赖的工程也同时同步回来,我们需要将这些依赖工程也纳入到Repo仓库中去,因此,当再次执行过breakfast使命之后。我们就可以在.repo/local_manifests/roomservice.xml文件中发现以下两行内容:&?xml version=&1.0& encoding=&UTF-8&?&
&manifest&
&project name=&CyanogenMod/android_device_oppo_find5& path=&device/oppo/find5& remote=&github& /&
&project name=&CyanogenMod/android_kernel_oppo_find5& path=&kernel/oppo/find5& remote=&github& revision=&cm-10.1& /&
&/manifest&&&&&& 回到函数brunch中,它接下来执行的命令mka也是由build/envsetup.sh脚本提供的,如下所示:function mka() {
case `uname -s` in
make -j `sysctl hw.ncpu|cut -d& & -f2` &$@&
schedtool -B -n 1 -e ionice -n 1 make -j$(cat /proc/cpuinfo | grep &^processor& | wc -l) &$@&
}&&&&&& 它实际上是通过一个叫做schedtool的工具来调用make工具对源码进行编译。我们知道,编码Android源码是一个漫长的过程,而现在的机器都是多核的,为了加快这个编译过程,需要将机器的所有核以都充分利用起来。工具schedtool所做的事情就是充分地利机器的多核特性来执行make命令,使得我们可以尽快结束编译过程。&&&&&& 关于Android源码的编译详细过程,可以参考的文章,这里只进行简要的说明。&&&&&& 从一文可以知道,Android的编译系统是由很多的mk文件组成的,每一个mk文件都是一个Makefile脚本片段。在编译开始之前,这些mk文件会组合在一起,形成一个很大的Makefile文件,然后再根据这个很大的Makefile文件的指令对源码进行编译。&&&&&& 由这些mk文件组成的Makefile文件内容可以抽象为四个层次,如图2所示:图2 Android编译系统层次&&&&&& 最下面一层描述的设备CPU的体系架构(Architecture),Android设备支持arm、x86和mips三种CPU体系架构。再往上一层描述的是设备所使用的芯片(Board),例如用的是高通的芯片,还是三星的芯片,等等,与这些芯片相关的源文件存放在hardware目录下。接下来再往上的一层是设备(Device),描述的是具体的硬件设备。最上面的一层是产品(Product),描述的是在硬件设备上运行的软件模块。&&&&&& 在这一步中,我们通过brunch命令编译CM源码时,指定的唯一参数是find5,那么Android编译系统是如何根据这个参数来找包含上述四个层次的mk文件为OPPO Find 5编译出能正常运行的ROM的呢?&&&&&& 在我们执行breakfast或者brunch命令的过程中,会调用另外一个函数check_product。根据一文,函数check_product会通过另外一个函数get_build_var加载build/core/config.mk文件。文件build/core/config.mk又会继续加载另外一个文件build/core/envsetup.mk。最后,文件build/core/envsetup.mk又会加载另外一个文件build/core/product_config.mk。&&&&&& 在build/core/product_config.mk文件的加载过程中,有以下的一段逻辑:ifneq ($(strip $(TARGET_BUILD_APPS)),)
# An unbundled app build needs only the core product makefiles.
all_product_configs := $(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)
ifneq ($(CM_BUILD),)
all_product_configs := $(shell ls device/*/$(CM_BUILD)/cm.mk)
# Read in all of the product definitions specified by the AndroidProducts.mk
# files in the tree.
all_product_configs := $(get-all-product-makefiles)
endif # CM_BUILD
endif&&&&&& 当我们编译的是整个Android源码时,变量TARGET_BUILD_APPS的值等于空。这时候就会判断是否设置了一个名称为CM_BUILD的环境变量。如果设置了的话,那么接下来就会加载device/*/$(CM_BUILD)目录下的cm.mk文件来获得目标产品配置文件。否则,首先会通过调用另外一个函数get-all-product-makefiles来获得/device/*/*目录下的所有名称为AndroidProducts.mk的文件,接着再在这些AndroidProducts.mk文件中定义的PRODUCT_MAKEFILES变量来获得目标产品配置文件。&&&&&& 环境变量CM_BUILD的值是在函数check_product中设置的,并且只有在CM源码中编译时才会设置。在AOSP源码编译时,是不会设置环境变量CM_BUILD的。CM版本的check_product函数实现如下所示:function check_product()
T=$(gettop)
if [ ! &$T& ]; then
echo &Couldn't locate the top of the tree.
Try setting TOP.& &&2
if (echo -n $1 | grep -q -e &^cm_&) ; then
CM_BUILD=$(echo -n $1 | sed -e 's/^cm_//g')
if [ `uname` == &Darwin& ]; then
export BUILD_NUMBER=$((date +%s%N ; echo $CM_BUILD; hostname) | openssl sha1 | cut -c1-10)
export BUILD_NUMBER=$((date +%s%N ; echo $CM_BUILD; hostname) | sha1sum | cut -c1-10)
export CM_BUILD
CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
TARGET_PRODUCT=$1 \
TARGET_BUILD_VARIANT= \
TARGET_BUILD_TYPE= \
TARGET_BUILD_APPS= \
get_build_var TARGET_DEVICE & /dev/null
# hide successful answers, but allow the errors to show
}&&&&&&& 从这里就可以看出,环境变量CM_BUILD的值实际上就是目标设备的名称。例如,前面我们执行breakfast命令时,通过函数lunch调用check_product函数时,传进来的参数为为cm_find5,函数check_product会将find5提取出来,并且赋值给环境变量CM_BUILD。这样在加载build/core/product_config.mk文件时,找到的产品配置文件就为device/*/find5/cm.mk文件。在device目录中,只有oppo子目录包含有find5这个目录,因此最终加载的实际上是device/oppo/find5/cm.mk文件。&&&&&&& 无论是通过环境变量CM_BUILD来直接获得的目标产品配置文件,还是通过AndroidProducts.mk文件间接获得的目标产品配置文件,获得的目标产品配置文件都会直接或者间接地通过变量PRODUCT_COPY_FILES和PRODUCT_PACKAGES来设备要包含的软件模块。&&&&&&& 以device/oppo/find5/cm.mk为例,它的部分内容如下所示:......
# Inherit device configuration
$(call inherit-product, device/oppo/find5/full_find5.mk)
## Device identifier. This must come after all inclusions
PRODUCT_DEVICE := find5
PRODUCT_NAME := cm_find5
PRODUCT_BRAND := Oppo
PRODUCT_MODEL := Find 5
PRODUCT_MANUFACTURER := Oppo
......&&&&&&& 除定了一些设备相关的变量之外,它还会加载另外一个文件device/oppo/find5/full_find5.mk,后者的部分内容如下所示:# Inherit from hardware-specific part of the product configuration
$(call inherit-product, device/oppo/find5/device.mk)
$(call inherit-product-if-exists, vendor/oppo/find5/find5-vendor.mk)&&&&&& 文件device/oppo/find5/full_find5.mk又会继续加载另外两个文件device/oppo/find5/device.mk和vendor/oppo/find5/find5-vendor.mk。&&&&&& 在文件device/oppo/find5/device.mk中,我们就可以看到PRODUCT_COPY_FILES和PRODUCT_PACKAGES的定义:PRODUCT_PACKAGES := \
lights.msm8960
PRODUCT_PACKAGES += \
charger_res_images \
# Vold and Storage
PRODUCT_COPY_FILES += \
device/oppo/find5/configs/vold.fstab:system/etc/vold.fstab
# Live Wallpapers
PRODUCT_PACKAGES += \
LiveWallpapers \
LiveWallpapersPicker \
VisualizationWallpapers \
......&&&&&& 而文件vendor/oppo/find5/find5-vendor.mk会加载另外一个文件vendor/oppo/find5/find5-vendor-blobs.mk,如下所示:......
$(call inherit-product, vendor/oppo/find5/find5-vendor-blobs.mk)
......&&&&&&& 回忆前面的第7步,文件文件vendor/oppo/find5/find5-vendor-blobs.mk是我们执行extract-files.sh脚本的时候生成的,里面通过变量PRODUCT_COPY_FILES告诉编译系统将从设备上获得的私有文件打包到要制作的ROM去。&&&&&&& 以上就是Product级别的配置信息的获取过程,接下来我们再看Device、Board和Architecture级别的配置信息的获取过程。&&&&&&& 函数check_product会通过另外一个函数get_build_var来加载build/core/config.mk文件的过程中,会在目标产品对应的设备目录中找到一个名称为BoardConfig.mk文件,如下所示:......
board_config_mk := \
$(strip $(wildcard \
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
device/*/$(TARGET_DEVICE)/BoardConfig.mk \
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
......&&&&&&& 上述Makefile脚本片段会在build/target/board、device/*、vendor/*目录中寻找一个名称为$(TARGET_DEVICE)的子目录,并且在找到的子目录里面加载一个名称为BoardConfig.mk文件,来获得Device、Board和Architecture级别的配置信息。&&&&&&& 变量TARGET_DEVICE指向的便是目标设备的名称。在我们这个场景中,它的值就等于find5,因此,最终获得的Device、Board和Architecture级别的配置信息就是来自于device/oppo/find5/BoardConfig.mk文件,它的部分内容如下所示:TARGET_CPU_ABI := armeabi-v7a
TARGET_CPU_ABI2 := armeabi
TARGET_ARCH := arm
# Bluetooth
BOARD_HAVE_BLUETOOTH := true
BOARD_HAVE_BLUETOOTH_QCOM := true
BLUETOOTH_HCI_USE_MCT := true
TARGET_BOARD_PLATFORM := msm8960
BOARD_HAS_QCOM_WLAN
BOARD_WLAN_DEVICE
TARGET_QCOM_DISPLAY_VARIANT := caf
USE_OPENGL_RENDERER := true
BOARD_HAVE_NEW_QC_GPS := true
COMMON_GLOBAL_CFLAGS += -DDISABLE_HW_ID_MATCH_CHECK -DQCOM_BSP_CAMERA_ABI_HACK -DNEW_ION_API
BOARD_USES_ALSA_AUDIO:= true
TARGET_QCOM_AUDIO_VARIANT := caf
TARGET_USES_QCOM_MM_AUDIO := true
TARGET_USES_QCOM_COMPRESSED_AUDIO := true
BOARD_AUDIO_CAF_LEGACY_INPUT_BUFFERSIZE := true
......&&&&&&& 从这里就可以看到各种Device、Board和Architecture级别的配置信息。例如,CPU体系架构由TARGET_ARCH、TARGET_CPU_ABI和TARGET_CPU_ABI2来描述。芯片类型由TARGET_BOARD_PLATFORM来描述,而设备信息的描述则包括Bluetooth、Wifi、Display、GPS、Camera和Audio等。&&&&&&& 在BoardConfig.mk文件中配置的编译信息是在什么时候用到的呢?以下我们就以TARGET_BOARD_PLATFORM为例,说明这些配置信息在编译的过程中是如何使用的。在Android源码中,hardware目录包含各种芯片相关的模块源码。在这些模块的编译脚本中,就会根据TARGET_BOARD_PLATFORM的值来为指定的芯片编译出正确的模块来。&&&&&&& 例如,假设我们使用的是高通芯片,在它的Camera HAL2模块源码目录hardware/qcom/camera/QCamera/HAL2/core中定义的Android.mk文件有如下的内容:......
LOCAL_CFLAGS += -DCAMERA_ION_HEAP_ID=ION_CP_MM_HEAP_ID # 8660=SMI, Rest=EBI
LOCAL_CFLAGS += -DCAMERA_ZSL_ION_HEAP_ID=ION_CP_MM_HEAP_ID
LOCAL_CFLAGS+= -DHW_ENCODE
LOCAL_CFLAGS+= -DUSE_NEON_CONVERSION
ifeq ($(TARGET_BOARD_PLATFORM),msm8960)
LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_MM_HEAP
LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
LOCAL_CFLAGS += -DCAMERA_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
LOCAL_CFLAGS += -DCAMERA_ZSL_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
else ifeq ($(TARGET_BOARD_PLATFORM),msm8660)
LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_CAMERA_HEAP
LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_CAMERA_HEAP # Don't Care
LOCAL_CFLAGS += -DCAMERA_ION_FALLBACK_HEAP_ID=ION_CAMERA_HEAP_ID # EBI
LOCAL_CFLAGS += -DCAMERA_ZSL_ION_FALLBACK_HEAP_ID=ION_CAMERA_HEAP_ID
LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_ADSP_HEAP
LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_ADSP_HEAP # Don't Care
LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=GRALLOC_USAGE_PRIVATE_UNCACHED #uncached
......&&&&&& 上述Makefile脚本片段会根据TARGET_BOARD_PLATFORM的值不同而设置不同的LOCAL_CFLAGS值,以便可以为目标设备编译出正确的HAL模块来。&&&&&& 这一步执行完成之后,也就是编译完成之后,我们就可以在out/target/product/find5目录中看到两个文件:recovery.img和cm-10.1-xxxxxxxx-UNOFFICIAL-find5.zip。其中,recovery.img是Recovery文件,而cm-10.1-xxxxxxxx-UNOFFICIAL-find5.zip是ROM文件。有了这两个文件之后,我们就可以参照前面的介绍,将它们刷入我们的OPPO Find 5手机上去了。当刷入完成,并且可以正常运行之后,现在我们的手机上面运行的Recovery和ROM都是我们自己亲手打造的了!&&&&&& 至此,我们就介绍完成CM的刷机过程和原理了,是不是觉得自己亲手去编译一个ROM是一件很容易的事呢?其实不然。我们上面编译的ROM之所以这么轻松,是因为CM已经为我们做了很多的工作,那就是已经在CM源码服务器上准备好了所有设备相关的源码,也就是我们下载回来之后存放在device目录下的源码。如果我们手头上有一部CM官方不支持的手机,那么CM源码服务器上是没有对应的设备源码存在的,这时候我们就需要自己去开发对应的设备源码了。这是一个艰苦的过程,需要不停的调试、调试、再调试,也许要花上几周,甚至一个月来完成这个工作。当然,这个过程也是有一些经验和技巧可以参考的,具体可以参考CM文档:。这里就不再详述。&&&&&& 最后,本文之所以选择CM这个第三方ROM和源码来讲解,是因为CM官方提供了很全面的资料供我们去学习如何基于AOSP源码来制作ROM,这样可以使我们少走很多弯路!另外,上面所述的ROM过程都是参考了CM官方文档的。更多的CM刷ROM教程,可以参考:。更多信息也可以关注老罗的新浪微博:。
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6069332次
积分:33346
积分:33346
排名:第59名
原创:139篇
评论:6770条
本博客所有文章均为原创,欢迎交流,欢迎转载;转载请勿篡改内容,并且注明出处,禁止用于商业目的,谢谢!
《Android系统源代码情景分析》
电子工业出版社
本书繁体版已经成功输出到台湾
新浪微博:
QQ交流群:
文章:139篇
阅读:6087030

我要回帖

更多关于 原生安卓4.4刷机包 的文章

 

随机推荐