前言
Android
开源项目是针对各种各样具有不同外形的设备创建的开源软件栈。它的主要目的是为运营商、原始设备制造商(
OEMs
)和开发人员创造一个开放的软件平台。
本指南是
Android
开源项目官网
The Android Source Code
的中文翻译版本。
适用人群
本教程是给那些想深入了解
Android
系统源码或想参与
Android
开源项目的开发人员编写的。
学习前提
在学习本教程之前,你需要对
Android
系统、
Android
开源社区及编程相关的知识有一定了解。
你将学会
•
下载和编译
Android
源码
•
使用
Android
源码查看工具
•
如何参与
Android
项目
更新日期
更新内容
2015-07-09
Android
开源项目指南
1
概述
Android
源代码
Android
是针对各种各样具有不同外形的设备创建的开源软件栈。
Android
主要目的是通过为运营商、原始设备制造商(
OEMs
)和开发人员创造一个开放的软件平台,使他们的创新理
念成为现实并介绍一个成功的、真实的产品,从而提高了用户的移动体验。
一个行业竞争者可能限制或控制他人的革新,我们也希望确保这不会成为失败的核心原因。所以得出的结论是需要一个开源的、可定制和移植的、完整的、有质量的消费产品。
管理哲学
Android
起源于一个以谷歌为首的被称为
“
开放手机联盟
”
(
OHA
)的企业群体。如今,很多企业(包括
OHA
的两个原始成员和其他一些企业)都在
Android
中投入巨资。这些公司已
拨出重要的工程资源来改善
Android
和将
Android
设备带向市场。
那些投资于
Android
的公司之所以已经这样做,是因为他们认为
Android
有其可取之处且我们也相信一个开放的平台是必要的。
Android
有意并明确地成为一个开源的(而非一个免费
软件的)成果;一群共享了需求的企业已经集中资源在独立实现共享产品方面进行合作。首先,
Android
的理念是务实的。其次,
Android
的目的是实现每位合作者都可以调整和定制
的共享产品。
不受控制的定制必然会导致不兼容的实现。为了防止这种情况,
Android
开源项目还主张
Android
兼容性计划
,这个
Android
兼容性计划阐述了
“ Android
兼容性
”
是什么意思和为实现这
一状态需要哪些设备制造商。任何人都可以出于任何目的使用
Android
的源代码,我们欢迎一切合法用途。然而,为了参与我们正在围绕
Android
构建的应用程序的共享生态系统,设
备制造商必须参加这个
Android
兼容性计划。
Android
开源项目是由维护并进一步开发
Android
的谷歌来领导的。这是严格意义上的项目管理技术,尽管
Android
是由多个子项目组成。我们查看和管理
Android
作为一个单一的、整
体的软件产品,而不是可替换零件的
“
分配
”
、规范或搜集。我们的目标是设备制造商只负责将
Android
移植到设备上但他们不实施规范或分配管理。
代码主线、分支和版本
Android
开源项目(
AOSP
)主张原始设备制造商(
OEMs
)和其他设备实施者将一个完整的软件堆栈植入并运行在他们自己的硬件上。为了保持
Android
的质量,谷歌贡献出了专职的
工程师、产品经理、用户界面设计师、质量保证测试人员和所有其他把现代化设备带向市场的必要相关人员。
因此,我们保留了若干
“
代码主线
”
,从不稳定的试验性工作中清晰地区分出
Android
当前稳定的版本。我们将开源的管理和维护迭代进更大的产品开发周期中。
下面的图表描述了在概念层面上
AOSP
是如何管理代码和版本。我们将提及的这些作为
“
代码主线
”
而不是
“
支线
”
,仅仅是因为在任何特定的时刻,一个特定的
“
代码主线
”
里都有可能存
在不止一条支线。例如,当一个发布被中断,它会基于当时的需求去决定它能不能成为一条新的分支。
1.
在任何特定的时刻,都有一个
Android
平台的当前最新版本。这通常表现为树的一个分支形式。
2.
设备制造商和参与者使用当前最新版本进行工作,修复漏洞,推出新设备,试验新功能等等。
3.
与此同时,谷歌根据产品的需要和目标,内部实现
Android
平台和框架的下一个正式版本。我们通过在旗舰设备上与设备合作伙伴合作,开发出
Android
的下一个正式版本。这
些设备合作伙伴的性能规范被选中,用来推动
Android
朝着我们希望的方向前进。
4.
当
“N+1”
个版本已经准备就绪,它将被发布到公共源代码树,并成为新的最新版本。
条款及注意事项
•
一个
发布版本
对应于一个
Android
平台的正式版本,例如
1.5
,
2.1
等等。一般来说,一个平台的发布版本对应一个正式版本。这个正式版本在
AndroidManifest.xml
文件的
SdkVersion
域里面且它是在
frameworks/base/api
源代码树下定义的。
•
一个
上游
项目是一个开源项目,
Android
堆栈就是从这个开源项目上获取代码的。这些包括一些著名的项目,如
Linux
内核和
WebKit
。随着时间的推移,我们正在迁移的一些半
自主性的
Android
项目
(
例如
Android
运行环境
“ART”
,
Android SDK
工具,
Bionic
等等
)
作为
“
上游
”
项目进行开发。通常情况下会在公共树里面完全开发这些项目。对于一些上游
项目,开发是通过直接地构建上游项目本身完成的。可以参看
上游项目
获取更多资讯。在这两种情况下,快照将定期被拉入版本。
•
在任何时候,对于特定的
Android
平台,代码主线版本(实际上在
git
里面可能包含了不止一个实际的分支)被认为是唯一规范的源代码。原始设备制造商和其他设备制造商应该
只从发布版本分支获取源代码。
•
“
实验性
”
代码线路的建立用以获取社区的变化,这样他们可以在迭代上着眼于稳定性。
•
证明了稳定的变化将最终被拖入发布分支。注意,这只适用于漏洞修复的、应用程序改进的和其它不影响平台
API
的变化。
•
当有必要时,变化将被从上游项目(包括
Android “
上游
”
项目)拖入发布分支。
•
谷歌内部将开发
“N+1”
个版本(即框架和平台
API
的下一个主要版本)。可以参看
关于私有的代码主线
获取更多资讯。
•
当有必要时,从上游、发布版本与实验分支拉出的变化将会放到谷歌的私有分支。
•
当下一个正式版本的平台
API
已经稳定,并经过全面测试,谷歌将中断下一个平台正式版本的发布版本。(这特别是指一种新
SdkVersion
。)这也将对应被制成一个公共发布分
支的内部代码行和新的当前平台代码主线。
•
当一个新的平台版本被中止,一个相应的实验代码行会在同一时间被创建。
关于私有代码线
上述提及的源管理策略包括一个谷歌将继续保密的代码主线。这样做的原因是要把注意力集中在目前
Android
公共版本。
原始设备制造商和其他设备制造商自然希望制造出与
Android
最新版本相关的产品。同样,应用程序开发者如非必要不希望处理更多的平台版本。与此同时,谷歌保留对作为一个平台
和一个产品的
Android
战略方向的责任。我们的方法着重于在少量的旗舰设备上运行功能,确保与
Android
相关的知识产权受到保护。
结果是,谷歌经常拥有来自第三方的机密信息。我们必须避免泄露敏感的功能,直到我们确保拥有适当的保护措施。另外,一次存在太多平台版本也会对平台引起真实的风险。基于这
些原因,我们已经构建了开源项目
-
包括第三方的贡献
-
以专注于
Android
的目前公开的稳定版本。下一平台版本的深度开发不会公开进行,直到它已经准备好成为一个发布版本。
我们意识到许多贡献者不同意这种方法。我们尊重其他人可能有不同的观点,然而,我们觉得这种方法是最好的,我们也选择这个方法来实现。
代码名称,标签和版本号
概括来说,
Android
的开发发生在各发布集合中,它使用可口美食作为代码名称,并按字母顺序排列。
平台代码名称,版本,
API
等级和
NDK
发布
代码名称与下面的版本号匹配,下表也提供了相应的
API
级别和
NDK
版本方便查询:
代码名称
版本
API
等级
Lollipop
5.1
API level 22
Lollipop
5.0
API level 21
KitKat
4.4 - 4.4.4
API level 19
Jelly Bean
4.3.x
API level 18
Jelly Bean
4.2.x
API level 17
Jelly Bean
4.1.x
API level 16
Ice Cream Sandwich
4.0.3 - 4.0.4
API level 15, NDK 8
Ice Cream Sandwich
4.0.1 - 4.0.2
API level 14, NDK 7
Honeycomb
3.2.x
API level 13
Honeycomb
3.1
API level 12, NDK 6
Honeycomb
3.0
API level 11
Gingerbread
2.3.3 - 2.3.7
API level 10
Gingerbread
2.3 - 2.3.2
API level 9, NDK 5
Froyo
2.2.x
API level 8, NDK 4
Eclair
2.1
API level 7, NDK 3
Eclair
2.0.1
API level 6
Eclair
2.0
API level 5
Donut
1.6
API level 4, NDK 2
Cupcake
1.5
API level 3, NDK 1
(no code name)
1.1
API level 2
(no code name)
1.0
API level 1
从蛋糕开始,各独立版本由一个短的版本代码来区分,如
FRF85B
。
第一个字母代表的是版本集合的名称,例如
F
就是
Froyo
。
第二个字母就是让谷歌识别确切的代码分支是从哪里来。按照约定,
R
代表的是主发布分支。
下一个字母和两个数字是一个日期代码。字母是计算季度的,
A
代表
2009
年第一季度。因此,
F
代表
2010
年第二季度。两个数字代表在这个季度中的天数。
F85
代表的是
2010
年
6
月
24
日。
最后,最后的字母标识与同一日期代码各个版本,依次以
A
开头的;
A
实际上隐含的,通常省略。
日期代码不能保证版本的确切的日期,通常它将微小变化加入到现有的版本中,在现有版本中重复使用相同的日期代码。
源代码标签和版本
从甜甜圈开始,准确的标签列表和版本显示在下表中。用于
Nexus
设备的出厂镜像和二进制文件可以从以下网址下载:
https://developers.google.com/android/nexus/images
https://developers.google.com/android/nexus/drivers
内部版本
分支
外部版本
支持设备
LMY47Z
android-5.1.1_r4
Lollipop
Nexus 6 (For Sprint, USC ONLY)
LMY48B
android-5.1.1_r3
Lollipop
Nexus 5
LMY47X
android-5.1.1_r2
Lollipop
Nexus 9 (volantis)
LMY47V
android-5.1.1_r1
Lollipop
Nexus 7 (flo/grouper), Nexus 10, Nexus Player
LMY47O
android-5.1.0_r5
Lollipop
Nexus 4, Nexus 7 (flo/deb)
LMY47M
android-5.1.0_r4
Lollipop
Nexus 6 (For T-Mobile ONLY)
LMY47I
android-5.1.0_r3
Lollipop
Nexus 5, Nexus 6
LMY47E
android-5.1.0_r2
Lollipop
Nexus 6
LMY47D
android-5.1.0_r1
Lollipop
Nexus 5, Nexus 6, Nexus 7 (grouper/tilapia), Nexus 10, Nexus Player
LRX22L
android-5.0.2_r3
Lollipop
Nexus 9 (volantis/volantisg)
LRX22G
android-5.0.2_r1
Lollipop
Nexus 7 (flo/deb/grouper/tilapia), Nexus 10
LRX22C
android-5.0.1_r1
Lollipop
Nexus 4, Nexus 5, Nexus 6 (shamu), Nexus 7 (flo), Nexus 9 (volantis/volantisg), Nexus 10
LRX21V
android-5.0.0_r7.0.1
Lollipop
Nexus Player (fugu)
LRX21T
android-5.0.0_r6.0.1
Lollipop
Nexus 4
LRX21R
android-5.0.0_r5.1.0.1
Lollipop
Nexus 9 (volantis)
LRX21Q
android-5.0.0_r5.0.1
Lollipop
Nexus 9 (volantis)
LRX21P
android-5.0.0_r4.0.1
Lollipop
Nexus 7 (flo/grouper), Nexus 10
LRX21O
android-5.0.0_r3.0.1
Lollipop
Nexus 5 (hammerhead), Nexus 6 (shamu)
LRX21M
android-5.0.0_r2.0.1
Lollipop
Nexus Player (fugu)
LRX21L
android-5.0.0_r1.0.1
Lollipop
Nexus 9 (volantis)
KTU84Q
android-4.4.4_r2
KitKat
Nexus 5 (hammerhead) (For 2Degrees/NZ, Telstra/AUS and India ONLY)
KTU84P
android-4.4.4_r1
KitKat
Nexus 5, Nexus 7 (flo/deb/grouper/tilapia), Nexus 4, Nexus 10
KTU84M
android-4.4.3_r1.1
KitKat
Nexus 5 (hammerhead)
KTU84L
android-4.4.3_r1
KitKat
Nexus 7 (flo/deb/grouper/tilapia), Nexus 4, Nexus 10
KVT49L
android-4.4.2_r2
KitKat
Nexus 7 (deb Verizon)
KOT49H
android-4.4.2_r1
KitKat
Nexus 5, Nexus 7 (flo/deb/grouper/tilapia), Nexus 4, Nexus 10
KOT49E
android-4.4.1_r1
KitKat
Nexus 5, Nexus 7 (flo/deb/grouper/tilapia), Nexus 4, Nexus 10
KRT16S
android-4.4_r1.2
KitKat
Nexus 7 (flo/deb/grouper/tilapia), Nexus 4, Nexus 10
KRT16M
android-4.4_r1
KitKat
Nexus 5 (hammerhead)
JLS36I
android-4.3.1_r1
Jelly Bean
Nexus 7 (deb)
JLS36C
android-4.3_r3
Jelly Bean
Nexus 7 (deb)
JSS15R
android-4.3_r2.3
Jelly Bean
Nexus 7 (flo)
JSS15Q
android-4.3_r2.2
Jelly Bean
Nexus 7 (flo)
JSS15J
android-4.3_r2.1
Jelly Bean
Nexus 7 (flo/deb)
JSR78D
android-4.3_r2
Jelly Bean
Nexus 7 (deb)
JWR66Y
android-4.3_r1.1
Jelly Bean
Galaxy Nexus, Nexus 7 (grouper/tilapia), Nexus 4, Nexus 10
JWR66V
android-4.3_r1
Jelly Bean
Galaxy Nexus, Nexus 7 (grouper/tilapia), Nexus 4, Nexus 10
JWR66N
android-4.3_r0.9.1
Jelly Bean
Galaxy Nexus, Nexus 7 (grouper/tilapia/flo), Nexus 4, Nexus 10
JWR66L
android-4.3_r0.9
Jelly Bean
Nexus 7
JDQ39E
android-4.2.2_r1.2
Jelly Bean
Nexus 4
JDQ39B
android-4.2.2_r1.1
Jelly Bean
Nexus 7
JDQ39
android-4.2.2_r1
Jelly Bean
Galaxy Nexus, Nexus 7, Nexus 4, Nexus 10
JOP40G
android-4.2.1_r1.2
Jelly Bean
Nexus 4
JOP40F
android-4.2.1_r1.1
Jelly Bean
Nexus 10
JOP40D
android-4.2.1_r1
Jelly Bean
Galaxy Nexus, Nexus 7, Nexus 4, Nexus 10
JOP40C
android-4.2_r1
Jelly Bean
Galaxy Nexus, Nexus 7, Nexus 4, Nexus 10
JZO54M
android-4.1.2_r2.1
Jelly Bean
JZO54L
android-4.1.2_r2
Jelly Bean
JZO54K
android-4.1.2_r1
Jelly Bean
Nexus S, Galaxy Nexus, Nexus 7
JRO03S
android-4.1.1_r6.1
Jelly Bean
Nexus 7
JRO03R
android-4.1.1_r6
Jelly Bean
Nexus S 4G
JRO03O
android-4.1.1_r5
Jelly Bean
Galaxy Nexus
JRO03L
android-4.1.1_r4
Jelly Bean
Nexus S
JRO03H
android-4.1.1_r3
Jelly Bean
JRO03E
android-4.1.1_r2
Jelly Bean
Nexus S
JRO03D
android-4.1.1_r1.1
Jelly Bean
Nexus 7
JRO03C
android-4.1.1_r1
Jelly Bean
Galaxy Nexus
IMM76L
android-4.0.4_r2.1
Ice Cream Sandwich
IMM76K
android-4.0.4_r2
Ice Cream Sandwich
Galaxy Nexus
IMM76I
android-4.0.4_r1.2
Ice Cream Sandwich
Galaxy Nexus
IMM76D
android-4.0.4_r1.1
Ice Cream Sandwich
Nexus S, Nexus S 4G, Galaxy Nexus
IMM76
android-4.0.4_r1
Ice Cream Sandwich
IML77
android-4.0.3_r1.1
Ice Cream Sandwich
IML74K
android-4.0.3_r1
Ice Cream Sandwich
Nexus S
ICL53F
android-4.0.2_r1
Ice Cream Sandwich
Galaxy Nexus
ITL41F
android-4.0.1_r1.2
Ice Cream Sandwich
Galaxy Nexus
ITL41D
android-4.0.1_r1.1
Ice Cream Sandwich
Galaxy Nexus
ITL41D
android-4.0.1_r1
Ice Cream Sandwich
Galaxy Nexus
GWK74
android-2.3.7_r1
Gingerbread
Nexus S 4G
GRK39F
android-2.3.6_r1
Gingerbread
Nexus One, Nexus S
GRK39C
android-2.3.6_r0.9
Gingerbread
Nexus S
GRJ90
android-2.3.5_r1
Gingerbread
Nexus S 4G
GRJ22
android-2.3.4_r1
Gingerbread
Nexus One, Nexus S, Nexus S 4G
GRJ06D
android-2.3.4_r0.9
Gingerbread
Nexus S 4G
GRI54
android-2.3.3_r1.1
Gingerbread
Nexus S
GRI40
android-2.3.3_r1
Gingerbread
Nexus One, Nexus S
GRH78C
android-2.3.2_r1
Gingerbread
Nexus S
GRH78
android-2.3.1_r1
Gingerbread
Nexus S
GRH55
android-2.3_r1
Gingerbread
earliest Gingerbread version, Nexus S
FRK76C
android-2.2.3_r2
Froyo
FRK76
android-2.2.3_r1
Froyo
FRG83G
android-2.2.2_r1
Froyo
Nexus One
FRG83D
android-2.2.1_r2
Froyo
Nexus One
FRG83
android-2.2.1_r1
Froyo
Nexus One
FRG22D
android-2.2_r1.3
Froyo
FRG01B
android-2.2_r1.2
Froyo
FRF91
android-2.2_r1.1
Froyo
Nexus One
FRF85B
android-2.2_r1
Froyo
Nexus One
EPF21B
android-2.1_r2.1p2
Eclair
ESE81
android-2.1_r2.1s
Eclair
EPE54B
android-2.1_r2.1p
Eclair
Nexus One
ERE27
android-2.1_r2
Eclair
Nexus One
ERD79
android-2.1_r1
Eclair
Nexus One
ESD56
android-2.0.1_r1
Eclair
ESD20
android-2.0_r1
Eclair
DMD64
android-1.6_r1.5
Donut
DRD20
android-1.6_r1.4
DRD08
android-1.6_r1.3
DRC92
android-1.6_r1.2
分支
froyo, gingerbread, ics-mr0, ics-mr1, jb-dev, jb-mr1-dev, jb-mr1.1-dev, jb-mr2-dev, kitkat-dev
为代表的开发分支不完全匹配配置。这是由谷歌测试提供的结果。他们可能含有除了官方
标记发布之外的各种变化和那些没有彻底的测试的开发分支。
为了区别各版本,你可以得到每个项目有关的变化列表,通过发出以下命令,并向其传递两个分支标签相关的变化列表:
$ repo forall -pc 'git log --no-merges --oneline branch-1..branch-2'
例如:
$ repo forall -pc 'git log --no-merges --oneline android-4.4.2_r2..android-4.4.2_r1'
输出到文本文件中:
repo forall -pc 'git log --no-merges --oneline android-4.4.2_r2..android-4.4.2_r1' > /tmp/android-4.4.2_r2-android-4.4.2_r1-diff.txt
蜂窝版本的
GPL
模块
对于蜂窝,整个平台的源代码是不可用。然而,下列标签显示的是部分在
GPL
和
LGPL
许可下的蜂窝源代码:
内部版本
标签
备注
内部版本
标签
备注
HRI39
android-3.0_r1
最早的蜂窝版本
HRI66
android-3.0_r1.1
HWI69
android-3.0_r1.2
HRI83
android-3.0_r1.3
HMJ37
android-3.1_r1
HTJ85B
android-3.2_r1
HTK55D
android-3.2.1_r1
HTK75D
android-3.2.1_r2
HLK75C
android-3.2.2_r1
HLK75D
android-3.2.2_r2
HLK75F
android-3.2.4_r1
HLK75H
android-3.2.6_r1
最后的蜂窝版本
没有证明显示上面表格中包含准确源代码。然而,有证明显示允许建立这些组件。下面的命令是为
3.0_r1.1
工作的,并且其它版本可通过切换
GIT
中
checkout
参数进行使用。如果必
要的话,
-m
参数需要重置。
Git
的
checkout
命令会输出一个非
GPL
的项目的错误,如果不能在问题中找到标记。
$ repo init -b master -m base-for-3.0-gpl.xml
$ repo sync
$ repo forall -c git checkout android-3.0_r1.1
项目角色
Android
开源项目(
AOSP
)包括各种工作角色的个人。谷歌负责
Android
产品的管理以及核心框架和平台的工程处理。但是,项目需要考虑各种资源的贡献,不仅仅指谷歌。本文描述
了能够参与到相关方面的各种角色。
任何一个对探索和为
Android
做贡献有兴趣的人都可以使用
Android
开源项目的资源。任何人都可以加入到邮件列表中,提问问题,贡献补丁,报告错误,看看提交的补丁,和使用一
些工具。要开始使用
Android
的代码,参见
Contributing
。
贡献者
“
贡献者
”
指那些为
AOSP
源代码做出贡献的人,包括谷歌和其他公司的员工,也包括那些以个人名义为
Android
作贡献的个人开发者。那些在谷歌就业的员工和不是受雇于谷歌的合作
者之间是没有区别的。所有的工程师使用相同的工具(
git
,
repo
和
gerrit
),遵循相同的代码审查过程,并且在代码风格上要按照相同的要求等等。
开发者
“
开发者
”
指编写应用程序的工程师,那些是运行在
Android
设备上的应用程序。在开发者和合作者之间常常只有一些技能上的微小差别。但
AOSP
用
“
开发者
”
去区分使用平台的工程师
和那些为平台做贡献的合作者。开发者(也指用户)是平台的
“
消费者
”
,那是贡献者所创建的平台。因此,我们比较多的谈论开发者,虽然对于
AOSP
本身来说,在技术上这并不是一
个单独的角色。
验证者
“
验证者
”
负责测试变更的请求。当有人提交了大量的高质量代码到项目之后,项目领导会邀请他们做项目的验证者。
备注:在这时候,验证者就扮演了类似审核者的角色。
审核者
“
审核者
”
是项目中有经验的成员,他们展现了他们的设计技能,并且在技术上为项目做出了巨大的贡献。在代码审查过程中,审核者需考虑是否包括或排除一些修改点。项目领导(通
常指谷歌的员工)选择审核者,有时也会把一些验证者提升到审核者的位置,他们往往是在一些特定的项目中展现了他们的专业知识的人。
项目领导
Android
由许多子项目组成。你可以用个人身份在
Git
知识库看到这些子项目的
Git
文件。
“
项目领导
”
是资深的贡献者,他们监督着每个
Android
项目的工程。通常,这些项目领导是谷
歌的员工。每个独立项目的项目领导主要负责以下工作:
•
引导项目的各个技术方面,包括项目规划,开发,发布周期,版本控制,和质量保证(
QA
)。
•
确保项目质量,保证在预定时间发布
Android
平台测试。
•
为提交的补丁指派验证者和审核者。
•
公正无偏的审查修改点。在基于技术价值和
Android
策略的准线上接受或拒绝补丁。
•
及时审查修改点,并且在修改点不被接受时尽最大的能力去沟通。
•
选择性地维护项目的网站,主要维护项目的特定项目信息和文档。
•
扮演解决技术冲突的调解者。
•
作为项目的公众形象和项目相关问题的接口人。
品牌指南
Android
这个名字,
这个标志,
“
谷歌应用程序商店
”
这个品牌和其他商标都是谷歌公司的财产,因此,我们不能通过
Android
开源项目获取这些资源的任何部分。
如果你对使用这些品牌来预示它们和你的设备之间的关系感兴趣,你必须遵循本文的指南。请谨记,这些指南对应并且补充了
Android
应用程序开发品牌指南
和
谷歌品牌许可
。
Android
接下来是
Android
品牌和相关资源的制造商指南。
文本中的
Android
•
在首次创造性的出现时,
Android™
就象征着一个商标。
•
Android
始终应予以资本化,没有复数或所有格。
•
在硬件,包装和营销材料上使用
Android
仅限于
Android
兼容
的设备。
•
在你的产品名称或包装和设备的原始和主要标记中不能使用
Android
。
•
Android
只能作为一种术语,指的是你设备的操作系统(
OS
)。如果你不确定你的用法是否符合我们的指南,请遵循这个简单的测试:如果你能将
Android
替换成
“Android
平
台
”
且文本仍然通顺有意义,那么你就可以使用这个术语。
•
错误:
“Android XBrand Phone”
•
正确:
“XBrand phone on Android”
•
你可以在你的标志上用纯黑字体使用
with Android
。如果在你的标志上使用,
with Android
不能大于你的标志的
90%
。首要或最突出的使用实例是标志之后要有一个
™
符号。
•
Android
可以仅仅作一个描述符号般使用,只要其后有一个适当的通用术语即可。但它不能作为你设备的产品名称或品牌。
•
错误:
“Android XBrand Phone”
•
正确:
“Android mobile device”
在你的通讯交流中,任何关于
Android
名称的使用都必须包含这个属性:
Android
是谷歌公司的商标。
以下是一些可接受的例子:
Android
机器人
Android
机器人可以在市场营销中,在适当的因素下被自由地使用,复制和改良。参见
应用程序开发品牌指南
和
创作公共许可
来获取详细的信息。
Android Logo
除非由谷歌通过书面协议明确授权,否则
Android
标志和自定义字体不得被使用。这些图片也不能和
Android
机器人一起被使用。
谷歌应用程序商店
在包装,营销材料,或其本身使用
“
谷歌应用程序商店
”
名字和谷歌应用程序商店图标的硬件只允许用于
授权访问谷歌应用程序商店
的设备上。
参见
支持的设备
清单可知道授权使用谷歌应用程序商店的设备。
问题
要想获得更多的品牌使用信息,请通过提交
合作伙伴品牌咨询表
来联系我们的
Android
合作伙伴营销团队。
2
下载和构建
下载与构建
通常内部测试
Android
的构建是在最近一个版本的
Ubuntu LTS
(
14.04
)中,
但是大多数的发行版本都具有构建所需的工具。我们非常欢迎收到在其它版本上尝试的结果反馈,无论是
成功,还是失败。
在你下载并构建
Android
源码之前,请确定你的系统满足以下需求:
•
请选择
Linux
或
Mac OS
系统,
或者也可以在像
windows
等暂时不支持的系统中使用虚拟机去构建
Android
,如果你在虚拟机中运行
Linux
,你至少需要
16GB
的
RAM/swap
和
100GB
以上的存储空间来构建
Android tree
。具体磁盘大小需求请参阅下文。
•
对于
Gingerbread
(
2.3.x
)
及以上版本,包括
master
分支都需要一个
64
位的环境,你可以在
32
位系统上编译它之前的版本、
•
至少有
100GB
的磁盘空间用来检查,
150GB
用来单编译,还需要
200GB
以上的空间用来进行交叉编译。如果你采用
ccache
,你可能会需要更多的空间。
•
Python 2.6-2.7
,你可以从
python.org
上下载。
•
GNU Make 3.81-3.82
,你可以从
gnu.org
上下载。
•
JDK7
用来构建
Android Open Source Project
(
AOSP
)
的
master
分支;
JDK6
用来构建
Gingerbread
到
Kitkat
之间的版本,
JDK5
用来构建
Cupcake
到
Froyo
之间的版本,操作系统
安装说明参见
初始化编译环境
。
•
Git 1.7
或更新版本,你可以在
git-scm.com
中找到它。
初始化编译环境
这个章节阐述如何建立起你的本地工作环境来构建
Android
源文件。你需要使用
Linux
或
Mac OS
操作系统。目前暂不支持在
Windows
下编译。
想对整个代码审查和代码更新过程有个整体的了解,请参阅
Life of a Patch
。
选择一个分支
部分构建环境的需求取决于你打算编译的源码版本,查看
Build Numbers
里面包含一个完整的分支列表供你选择。你也许想选择下载最新的源码(
Master
)进行构建,在这种情况下你
可以在初始化仓库的时候简单的忽略分支规范。
当你选择了一个分支后,参考下面相应的说明来搭建你的编译环境。
搭建一个
Linux
平台的编译环境
这些说明适用于所有分支,包括
master
分支。
通常内部测试
Android
的构建是在最近一个版本的
Ubuntu LTS
(
14.04
)中,但是大多数发行版本都应该具备构建所需的工具,欢迎反馈您在其他版本上的尝试结果,无论成功还是失
败。
Gingerbread
(
2.3.x
)或以上版本,包括
master
分支,都需要一个
64
位的环境,它之前的版本可以在
32
位系统下进行编译。
提示:参阅
下载与构建
了解对硬件环境和软件环境的需求。然后参考下面对
Ubuntu
和
Mac OS
下构建的详细说明。
安装
JDK
Android Open Source Project
(
AOSP
)的
master
分支需要
Java 7
。在
Ubuntu
下可以使用
OpenJDK
。
Java 7
:适用于最新版本的
Android
$ sudo apt-get update
$ sudo apt-get install openjdk-7-jdk
也可以运行如下指令升级默认的
Java
版本:
sudo update-alternatives --config java
sudo update-alternatives --config javac
如果你遇到
Java
版本错误,参考
wrong-java-version
中描述的来设置它的路径。
开发较早版本的
Android
,下载安装相应的
Java JDK
:
Java 6
:适用
Gingerbread
到
KitKat
的版本
Java 5
:适用
Cupcake
到
Froyo
的版本
提示
:
在构建过程中的命令会确定使用的是
Sun JDK
而不是先前安装的
JDK
。
安装需要的包(
Ubuntu 14.04
)
你将需要一个
64
位版本的
Ubuntu
。推荐
Ubuntu 14.04
。
$ sudo apt-get install bison g++-multilib git gperf libxml2-utils make zlib1g-dev:i386 zip
安装需要的包(
Ubuntu 12.04
)
你也许会使用
Ubuntu 12.04
来构建较早版本的
Android
。
master
分支和最近的发行都不支持
12.04
版本。
$ sudo apt-get install git gnupg flex bison gperf build-essential \
zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \
libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \
libgl1-mesa-dev g++-multilib mingw32 tofrodos \
python-markdown libxml2-utils xsltproc zlib1g-dev:i386
$ sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so
安装需要的包(
Ubuntu 10.04 -- 11.10
)
在
Ubuntu 10.04-11.10
上构建已不在被支持,但仍可以用来构建较早的
AOSP
。
$ sudo apt-get install git gnupg flex bison gperf build-essential \
zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev \
libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
libxml2-utils xsltproc
在
Ubuntu 10.10
中:
$ sudo ln -s /usr/lib32/mesa/libGL.so.1 /usr/lib32/mesa/libGL.so
在
Ubuntu 11.10
中:
$ sudo apt-get install libx11-dev:i386
配置
USB
接口
在
GNU/Linux systems
系统下,(尤其是
Ubuntu
系统),通常用户在默认情况下不能直接读取
USB
设备。我们要对系统进行配置才能允许这种操作。
推荐的做法是创建一个文件
/etc/udev/rules.d/51-android.rules
(作为
root
用户),接着将下面对内容复制上去。
<username>
必须被替换成实际被授权通过
USB
访问手机的
用户名。
# adb protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e12", MODE="0600", OWNER="<username>"
# fastboot protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", ATTR{idProduct}=="0fff", MODE="0600", OWNER="<username>"
# adb protocol on crespo/crespo4g (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e22", MODE="0600", OWNER="<username>"
# fastboot protocol on crespo/crespo4g (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e20", MODE="0600", OWNER="<username>"
# adb protocol on stingray/wingray (Xoom)
SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", ATTR{idProduct}=="70a9", MODE="0600", OWNER="<username>"
# fastboot protocol on stingray/wingray (Xoom)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="708c", MODE="0600", OWNER="<username>"
# adb protocol on maguro/toro (Galaxy Nexus)
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="6860", MODE="0600", OWNER="<username>"
# fastboot protocol on maguro/toro (Galaxy Nexus)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e30", MODE="0600", OWNER="<username>"
# adb protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d101", MODE="0600", OWNER="<username>"
# adb protocol on panda (PandaBoard ES)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="d002", MODE="0600", OWNER="<username>"
# fastboot protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d022", MODE="0600", OWNER="<username>"
# usbboot protocol on panda (PandaBoard)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d00f", MODE="0600", OWNER="<username>"
# usbboot protocol on panda (PandaBoard ES)
SUBSYSTEM=="usb", ATTR{idVendor}=="0451", ATTR{idProduct}=="d010", MODE="0600", OWNER="<username>"
# adb protocol on grouper/tilapia (Nexus 7)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e42", MODE="0600", OWNER="<username>"
# fastboot protocol on grouper/tilapia (Nexus 7)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e40", MODE="0600", OWNER="<username>"
# adb protocol on manta (Nexus 10)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4ee2", MODE="0600", OWNER="<username>"
# fastboot protocol on manta (Nexus 10)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4ee0", MODE="0600", OWNER="<username>"
这些规则会在下次插入设备的时候生效。因此可能需要先拔出设备再插回去。
知道这些就可以在
Ubuntu Hardy Heron (8.04.x LTS)
和
Lucid Lynx (10.04.x LTS)
上工作。其他版本的
Ubuntu
或其他
GNU/Linux
的发行版本需要不同的设置。
使用一个单独的输出目录
默认情况下,每个构建出来的结果都存储在系统资源目录的子文件夹
out/
目录下。
在一些拥有多个存储设备的机器上。构建在存储源文件并输出到单独卷的时候会进行的较快。还有其他一些性能,比如可以将输出存储到一个经过速度优化的文件系统中并且不会造成
稳健性崩溃,因为所有文件都可以在文件损坏的情况下被重新生成。
要使用这种功能,配置输出
OUT_DIR_COMMON_BASE
变量指向到你存储输出数据的地方。
export OUT_DIR_COMMON_BASE=<path-to-your-out-directory>
每个源代码树的输出目录都将在文件夹创建后以源码树命名。
举个例子,如果你现在有一些源代码树,比如
/source/master1
和
/source/master2
并且
OUT_DIR_COMMON_BASE
设置为
/output
,输出目录就会是
/output/master1
和
/output/master2
。
有一个重要的情况就是不能将多个源代码树输出到同一个目录并且具有相同的名称,否则他们会在同时使用同一个输出目录的时候出现不可预知的结果,然后终止。
这些仅支持
Jelly Bean (4.1)
及以上版本,包括
master
分支。
在
Mac OS
平台搭建编译环境
在默认安装下,
Mac OS
运行在一个保留但不区分大小写的文件系统上。这种文件系统并不被
git
支持而且一些
git
指令
(比如
git status
)表现异常。出于此原因,我们推荐你在一个
区分大小写的文件系统上工作使用
AOSP
源代码树。
使用磁盘映像可以非常容易地达到目的,讨论如下。
一旦合适的文件系统准备好,在现代的
Mac OS
环境下构建
master
分支会变得非常容易。较早的一些分支,包括
ICS
,需要一些额外的工具和
SDK
。
创建一个区分大小写的磁盘映像
你可以用你的
Mac OS
环境下正在使用对磁盘映像创建一个区分大小写的文件系统。为了创建这个映像,启动磁盘工具并选择
"New Image"
。完成构建最少需要
25GB
;以后可能会需
要更多。使用分散的映像可以节省空间并且以后可以根据需要增大。请确定选择
“
区分大小写,日志
”
作为卷格式。
你也可以在
shell
里输入下面的命令来创建它。
# hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg
这会创建一个
.dmg
(或者
.dmg.sparsefile
)文件,一旦被安装,将成为具有
Android
开发所需格式的驱动器。
如果你以后需要更大的空间,你可以使用下面的指令来重新设置分散映像的大小。
# hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage
一个名为
android.dmg
的地盘映像被安装在你的主目录下,你可以在
~/.bash_profile
文件中添加一个辅助功能模块。
•
执行
mountAndroid
的时候安装这个镜像文件:
# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }
注意:如果你的系统创建了一个
.dmg.sparsefile
文件,请将
-/android.dmg
替换为
-/android.dmg.sparsefile
。
•
执行
umountAndroid
的时候卸载它:
# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }
一旦你安装了
android
卷,你可以在这里进行你所有的工作。也同样可以像一个外部驱动器一样直接弹出(卸载)它。
安装
JDK
Android
开源工程
(AOSP)
中
Android
的
master
和
5.0.x
分支需要
Java 7
。在
Mac OS
中,使用
jdk-7u71-macosx-x64.dmg
。
要开发
Android Gingerbread
到
KitKat
之间的版本,下载并安装
Java JDK
的
Java 6
版本。
Master
分支
要在
Mac OS
环境下构建最新版本的源代码,你需要一台具备
Intel/x86
的机器并且系统在
Mac OS X v10.8
(
Mountain Lion
)或以上,
Xcode
版本在
4.5.2
以上并包含命令行工具。
5.0.x
及其之前的分支
要在
Mac OS
环境下构建
5.0.x
及其之前的源码,你需要一台具备
Intel/x86
的机器并且系统在
Mac OS X v10.8
(
Mountain Lion
)或以上,
Xcode
版本在
4.5.2
以上并包含命令行工具。
4.4.x
及其之前的分支
要在
Mac OS
环境下构建
4.2.x
及其之前的源代码,你需要一台
Intel/x86
的机器并且系统为
Mac OS X v10.6 (Snow leopard)
或
Mac OS X v10.7 (Lion)
,具备
Xcode 4.2
(苹果开发者工
具)。尽管
Lion
系统并不事先具备
JDK
,但它会在你尝试构建源码的时候自动安装。
剩下的关于
Mac OS
的内容只针对那些希望构建较早分支的用户。
4.0.x
及其之前的分支
要在
Mac OS
环境下构建
android-4.0.x
及其之前的版本分支,你需要一台
Intel/x86
的机器并且运行
Mac OS X v10.5 (Leopard)
系统或
Mac OS X v10.6 (Snow Leopard)
系统,同时你将需
要
Mac OS X v10.5
的
SDK
。
安装需要的包
•
从
Apple
开发者平台
获取安装
Xcode
。我们推荐
3.1.4
或更新版本(比如
gcc 4.2
)。
4.x
的版本可能会造成困难。如果你还没有准备好注册成为
Apple
开发者,则需要创建一个
Apple ID
来进行下载。
•
从
macports.org
获取
MacPorts
的安装。
注意:确保在你的
/usr/bin
路径之前存在
/opt/local/bin
路径。如果没有,请将下面的内容添加到你的
~/.bash_profile
文件中:
export PATH=/opt/local/bin:$PATH
注意:如果在你的主目录下没有
.bash_profile
文件,那就创建一个。
•
从
MacPorts
上获取
make
,
git
和
GPG
包的安装:
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg
如果使用的是
Mac OS X v10.4
,还需要安装
bison
:
$ POSIXLY_CORRECT=1 sudo port install bison
从
make 3.82
中恢复
在
Android ICS
之前的版本,存在一个
bug
阻止了
android
的构建。你可以按照下面的步骤使用
MacPorts
安装
3.81
版本:
•
编辑
/opt/local/etc/macports/sources.conf
并添加下面一行内容
file:///Users/Shared/dports
添加完上面一行。之后创建这样一个目录:
$ mkdir /Users/Shared/dports
•
在新的
dports
目录中,运行
$ svn co --revision 50980 http://svn.macports.org/repository/macports/trunk/dports/devel/gmake/ devel/gmake/
•
为你的本地仓库创建一个端口:
$ portindex /Users/Shared/dports
•
最后,输入下面的指令安装旧版的
gmake
:
$ sudo port install gmake @3.81
设置文件描述限制符
在
Mac OS
上,默认的文件同时打开数量值太低,所以一个高并发的构建会超出这个限制。
为了增加这个上限,将下面的一行添加到你的
-/.bash_profile
文件中:
# set the number of open files to be 1024
ulimit -S -n 1024
优化构建环境(可选)
建立
ccache
你可以选择性的让构建使用
ccache
汇编工具。
Ccache
作为一个编译缓存器可以用来为重构建提速。如果你经常使用
make clean
,或者经常切换不同的工程进行构建的话,这将会非常
好用。
在你的
.bashrc
(或其它同类文件)中添加下面一行:
export USE_CCACHE=1
默认情况下
cache
会被存储在
~/.ccache
下。如果你的主目录在
NFS
活着其它非本地系统上,你也同样需要在你的
.bashrc
文件中指定目录。
export CCACHE_DIR=<path-to-your-cache-directory>
建议缓存大小设为
50
-
100 GB
之间。在你下载好源代码之后运行下面的指令:
prebuilts/misc/linux-x86/ccache/ccache -M 50G
在
Mac OS
中,你应该将
linux-x86
替换为
darwin-x86
:
prebuilts/misc/darwin-x86/ccache/ccache -M 50G
在构建
Ice Cream Sandwich (4.0.x)
或更早版本的时候,
ccache
会在一个不同的位置下:
prebuilt/linux-x86/ccache/ccache -M 50G
这些设置被存储在
CCACHE_DIR
并且一直生效。
你的编译环境已经准备好了,接下来
下载源代码
。
下载源码
Android
的源代码树在
托管的
Git
仓库中。本文主要阐述如何下载源码树中具体的
Android
代码。
安装
Repo
Repo
是一个方便在
Android
中使用
Git
的工具。想了解更多关于
Repo
的信息,请参阅
Developing
章节。
如何安装
Repo
:
1.
确保在你的主目录下有一个
bin/
目录并且它包含在你的路径中:
$ mkdir ~/bin
$ PATH=~/bin:$PATH
2.
下载
Repo
工具并确保它是可执行的:
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
1.17
版本,
repo
的
SHA-1
校验值是
ddd79b6d5a7807e911b524cb223bc3544b661c28
1.19
版本,
repo
的
SHA-1
校验值是
92cbad8c880f697b58ed83e348d06619f8098e6c
1.20
版本,
repo
的
SHA-1
校验值是
e197cb48ff4ddda4d11f23940d316e323b29671c
1.21
版本,
repo
的
SHA-1
校验值是
b8bd1804f432ecf1bab730949c82b93b0fc5fede
初始化一个
Repo
客户端
安装完
Repo
之后,建起一个客户端来访问
Android
的源码仓库:
1.
创建一个空目录来存放你的工作文件。如果你使用的是
MacOS
,则这个目录需要在一个区分大小写的文件系统上。可以以任何你喜欢的名称命名:
$ mkdir WORKING_DIRECTORY
$ cd WORKING_DIRECTORY
2.
运行
repo init
更新最新版本的
Repo
该版本已经修复了大量已知
Bug
。你必须为
manifest
指定一个
URL
,它指定了
Android
源码树里的各个仓库都会被存放在你工作的目录
下。
$ repo init -u https://android.googlesource.com/platform/manifest
要查看
"master"
以外的分支,用
-b
来指定。想查看分支列表,参阅
Source Code Tags and Builds
。
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1
3.
出现提示时,在
Repo
中配置你的真实姓名和
地址。要使用
Gerrit
代码审查工具,你可能会需要一个注册过
账户的邮箱地址。请确保你能通过这个邮箱地址收到消
息。这将作为你贡献代码的署名出现。
成功初始化的时候会显示这样的消息状态-
Repo
已经在你的工作目录下完成了初始化。你的客户端目录下应该会包含一个
.repo
目录用来存放像
manifest
一类的文件。
下载
Android
源代码树
要将
manifest
中默认指定的
Android
代码树拉取到你的工作目录下,请运行:
$ repo sync
你的工作目录下会有对应的工程名并存储了
Android
源码文件。这个初始化同步操作大概会需要一个小时或更多的时间才能完成。想了解更多关于
Repo sync
的信息和
Repo
的其它指
令,请参阅
Developing
章节。
使用认证
通常情况下,访问
Android
源码资源都是匿名的。为了防止服务器负荷过大,每个
IP
地址都关联一个
quota
。
当和他们共享同一个
IP
地址时(比如访问代码仓库时越过
NAT
防火墙),即使在正常模式下
quotas
也会被触发(例如许多用户在较短时段里从同一个
IP
地址下创建新客户端并发起
同步请求)。
在这种情况下,可以使用授权来访问,每个用户将会使用一个独立的与
IP
地址无关的
quota
。
第一步首先是使用
密码生成器
,然后按照页面上的说明进行操作。
第二步是通过使用
https://android.googlesource.com/a/platform/manifest
这个
manifest URL
来进行强制授权访问。注意
/a/
目录如何进行前缀强制触发认证。你可以使用下面的指令进行
强制认证来转化你的客户端:
$ repo init -u https://android.googlesource.com/a/platform/manifest
排除网络问题
当通过代理下载的时候(通常企业经常使用),需要去用
repo
明确地指定代理:
$ export HTTP_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port>
$ export HTTPS_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port>
更少见的是,
Linux
客户端遇到连接问题,下载到一半的时候中止(典型的就是在
“
正在接受数据
”
过程中)。据报道调整
TCP/IP
堆的设置并使用非平行的命令可以改善这个问题。你需
要
root
权限访问并修改
TCP
设定:
$ sudo sysctl -w net.ipv4.tcp_window_scaling=0
$ repo sync -j1
使用一个本地镜像
当使用多个客户端时,尤其是在带宽有限的情况下,最好在本地对整个服务器内容创建一个镜像,然后从这个镜像同步到客户端(这样就不需要网络访问权限)。当包含更大量内容的
时候,下载一个完整镜像和两个客户端分别同时进行下载是大致相同的。
这些说明假设镜像在
/usr/local/aosp/mirror
里被创建。第一步是创建一个镜像然后对自己进行同步。注意
--mirror
标识只可以在创建一个新客户端的时候被指定:
$ mkdir -p /usr/local/aosp/mirror
$ cd /usr/local/aosp/mirror
$ repo init -u https://android.googlesource.com/mirror/manifest --mirror
$ repo sync
一旦镜像被同步,新的客户端就可以从中创建,注意一定要指定一个绝对路径:
$ mkdir -p /usr/local/aosp/master
$ cd /usr/local/aosp/master
$ repo init -u /usr/local/aosp/mirror/platform/manifest.git
$ repo sync
最后,客户端要对服务器进行同步,镜像需要对客户端进行同步,然后客户端同步镜像:
$ cd /usr/local/aosp/mirror
$ repo sync
$ cd /usr/local/aosp/master
$ repo sync
可以将镜像存储在一个局域网服务器上,然后通过
NFS
,
SSH
或者
Git
访问它。同样也可以将它存储在可移动设备上,然后在用户或者机器直接传递它。
验证
Git
标记
加载下面的公钥到你的
GunPG
密钥库。这个密钥用来进行标签注释并签署发布。
$ gpg --import
复制粘贴下面的密钥,然后键入
EOF
(或者
Ctrl-D
)来结束输入病保存这个密钥。
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.2.2 (GNU/Linux)
mQGiBEnnWD4RBACt9/h4v9xnnGDou13y3dvOx6/t43LPPIxeJ8eX9WB+8LLuROSV
lFhpHawsVAcFlmi7f7jdSRF+OvtZL9ShPKdLfwBJMNkU66/TZmPewS4m782ndtw7
8tR1cXb197Ob8kOfQB3A9yk2XZ4ei4ZC3i6wVdqHLRxABdncwu5hOF9KXwCgkxMD
u4PVgChaAJzTYJ1EG+UYBIUEAJmfearb0qRAN7dEoff0FeXsEaUA6U90sEoVks0Z
wNj96SA8BL+a1OoEUUfpMhiHyLuQSftxisJxTh+2QclzDviDyaTrkANjdYY7p2cq
/HMdOY7LJlHaqtXmZxXjjtw5Uc2QG8UY8aziU3IE9nTjSwCXeJnuyvoizl9/I1S5
jU5SA/9WwIps4SC84ielIXiGWEqq6i6/sk4I9q1YemZF2XVVKnmI1F4iCMtNKsR4
MGSa1gA8s4iQbsKNWPgp7M3a51JCVCu6l/8zTpA+uUGapw4tWCp4o0dpIvDPBEa9
b/aF/ygcR8mh5hgUfpF9IpXdknOsbKCvM9lSSfRciETykZc4wrRCVGhlIEFuZHJv
aWQgT3BlbiBTb3VyY2UgUHJvamVjdCA8aW5pdGlhbC1jb250cmlidXRpb25AYW5k
cm9pZC5jb20+iGAEExECACAFAknnWD4CGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIX
gAAKCRDorT+BmrEOeNr+AJ42Xy6tEW7r3KzrJxnRX8mij9z8tgCdFfQYiHpYngkI
2t09Ed+9Bm4gmEO5Ag0ESedYRBAIAKVW1JcMBWvV/0Bo9WiByJ9WJ5swMN36/vAl
QN4mWRhfzDOk/Rosdb0csAO/l8Kz0gKQPOfObtyYjvI8JMC3rmi+LIvSUT9806Up
hisyEmmHv6U8gUb/xHLIanXGxwhYzjgeuAXVCsv+EvoPIHbY4L/KvP5x+oCJIDbk
C2b1TvVk9PryzmE4BPIQL/NtgR1oLWm/uWR9zRUFtBnE411aMAN3qnAHBBMZzKMX
LWBGWE0znfRrnczI5p49i2YZJAjyX1P2WzmScK49CV82dzLo71MnrF6fj+Udtb5+
OgTg7Cow+8PRaTkJEW5Y2JIZpnRUq0CYxAmHYX79EMKHDSThf/8AAwUIAJPWsB/M
pK+KMs/s3r6nJrnYLTfdZhtmQXimpoDMJg1zxmL8UfNUKiQZ6esoAWtDgpqt7Y7s
KZ8laHRARonte394hidZzM5nb6hQvpPjt2OlPRsyqVxw4c/KsjADtAuKW9/d8phb
N8bTyOJo856qg4oOEzKG9eeF7oaZTYBy33BTL0408sEBxiMior6b8LrZrAhkqDjA
vUXRwm/fFKgpsOysxC6xi553CxBUCH2omNV6Ka1LNMwzSp9ILz8jEGqmUtkBszwo
G1S8fXgE0Lq3cdDM/GJ4QXP/p6LiwNF99faDMTV3+2SAOGvytOX6KjKVzKOSsfJQ
hN0DlsIw8hqJc0WISQQYEQIACQUCSedYRAIbDAAKCRDorT+BmrEOeCUOAJ9qmR0l
EXzeoxcdoafxqf6gZlJZlACgkWF7wi2YLW3Oa+jv2QSTlrx4KLM=
=Wi5D
-----END PGP PUBLIC KEY BLOCK-----
输入完密钥,你可以使用下面的指令校验任何标记
$ git tag -v TAG_NAME
如果你还没有
搭建
ccache
,现在是完成他的最好时机。
构建系统
下面的信息对于构建
Android
资源树的指导适用于各个分支,包括
master
分支。
选择一个分支
有些构建工程的环境所需要的请求,是需要搞清楚你计划要编译这些代码所使用的版本的。请查看
Codenames,Tags,and Build Numbers
里面完整的分支列表以供你来选择。你也可以选
择下载,构建最新版本源代码(被称之为
master
),这样你需要做的仅仅是在初始化仓库时,删除之前的分支即可。
当已经选择一个分支后,就跟着下面的指导去创建你的构建环境。
基础的构建命令系列如下所示:
初始化
用
envsetup.sh
脚本来初始化环境。值得注意的是,用
.
(一个单独的点)来替换
source
节省一些符号,简写也更方便的在说明文档中使用。
$ source build/envsetup.sh
或者是
$ . build/envsetup.sh
选择一个目标
选择一个目标用
lunch
来建立。明确的配置信息可以通过一个参数来实现。比如像下面的命令:
$ lunch aosp_arm-eng
这个命令是构建一个模拟器,并且可以使用
debug
模式。
如果使用没有参数的
lunch
将会及时的提醒你从菜单中选择一个目标参数。
所有构建目标可以从
BUILD-BUILDTYPE
,
BUILD
是一个代码名称,依赖于特定参数的混合体。这里是一部分的列表:
Build name
Device
Notes
aosp_arm
ARM emulator
AOSP,fully configured with all languages,apps,inputs methods
aosp_maguro
maguro
AOSP, running on Galaxy Nexus GSM/HSPA+ ("maguro")
aosp_panda
panda
AOSP, running on PandaBoard ("panda")
下列显示的是其中一个的
BUILDTYPE
:
Buildtype
Use
user
limited access; suited for production
userdebug
like "user" but with root access and debuggability; preferred for debugging
eng
development configuration with additional debugging tools
要想查看更多有关构建以及运行在真机的信息,请看
Building for Devices
构建代码
用
make
可以完成任何事情。
GUN
可以用一个
-jn
参数,传递一个平行的任务,一般来说使用一个介于
1
和
2
之间的参数
N
,乘以在电脑上用于构建硬件线程的数量。比如,在一个
dual-E5520
(
2
个
cpu
,每个
4
核
,每核
2
个线程)上,最快的构建是使用命令
make -j16
和
make -j32
。
$ make -j4
运行它!
你既可以运行你
build
在模拟器上,也可以在真机上。请注意你已经用
lunch
选中了你需要构建的目标,而且他不大可能运行在与构建目标不相符的地方。
在设备上运行
为了在设备上运行,你需要使用
fastboot
,
这个命令需要你在成功构建之后,添加到你的
PATH
中。将设备置于
fastboot
模式,你既可以手工的在根目录下添加
key
,也可以用下面的脚
本命令:
$ adb reboot bootloader
一旦设备在
fastboot
模式下,运行
$ fastboot flashall -w
-w
选项用于清除在设备上
/data
分区;这个选项很适合第一次刷入真机,但在某些情况下并非必要。
要想查看更多有关构建以及运行在真机的信息,请看
Building for Devices
。
Android
模拟设备
模拟器将会自动被构建进程添加在你的路径中。要启动模拟器,请输入:
$ emulator
使用
ccache
ccache
是一种编译缓存,为的是让
C
和
C++
更快的构建的。在资源树的根目录下,按照下面的说明去做:
$ export USE_CCACHE=1
$ export CCACHE_DIR=/<path_of_your_choice>/.ccache
$ prebuilts/misc/linux-x86/ccache/ccache -M 50G
建议的缓存大小是
50-100 G
。
在
Linux
上,你可以通过以下的操作查看
ccache
:
$ watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s
在
Mac OS
上,你应该用
darwin-x86
来替换掉
linux-x86
。
当使用
Ice Cream Sandwich (4.0.x)
或者是这之前的版本时,你应该用
prebuilt
来替换掉
prebuilts/misc
。
分析解决常见构建错误
错误的
Java
版本
如果你尝试用与
Android
不对应的
Java
版本,
make
命令将会终止,并提示下面的信息:
************************************************************
You are attempting to build with the incorrect version
of java.
Your version is: WRONG_VERSION.
The correct version is: RIGHT_VERSION.
Please follow the machine setup instructions at
https://source.android.com/source/download.html
************************************************************
出现这一现象可能的原因是:
•
安装在
初始化构建环境
中所说的
JDK
失败。
•
另一个之前版本的
JDK
出现在你的路径中。将正确的
JDK
放在你的
PATH
的开头处,或者从环境变量中删除导致问题的
JDK
。
Python
版本
3
Repo
的基于特殊功能的
Python 2.x
,但是不幸的是和
Python 3
相冲突。为了使用
Repo
,请安装
Python 2.x
:
$ apt-get install python
忽略文件系统的情况
如果你正在
Mac OS
上构建一个
HFS
文件系统,你可能会偶然遇见下面的错误:
************************************************************
You are building on a case-insensitive filesystem.
Please move your source tree to a case-sensitive filesystem.
************************************************************
请根据
初始化构建环境
中的说明创建一个敏感的磁盘镜像。
没有
USB
权限
在大多数
Linux
系统上,没有特权的用户不能通过默认的
USB
端口。如果你看见一个权限拒绝错误,请根据
初始化构建环境
来配置你的
USB
入口。
如果
adb
已经运行,并且通过刚才的规则也不能连接到设备,这时可以通过
adb kill-server
命令杀死。这将会导致
adb
使用新的配置重启。
根据设备构建
这一篇补充说明主页上有关
构建和运行
中运行在特殊设备上的信息。
通过当前已经发放的版本,可以在
Nexus 4
,
Nexus 7
以及一些
Galaxy Nexus
的变异版本的手机上构建。每一个设备的具体实用性水平,取决于硬件所属的二进制文件。
给
Nexus 4
和
Nexus 7
,所有的配置都可以使用,并且所有的硬件都可以工作。由于硬件的不同,不要在
Nexus 7
上使用
4.1.1
,它已经被
4.1.2
以及后续的版本所取代。
所有的
Nexus 10 “manta”
配置可以使用
4.2.2
。在这些设备上,图像,音频,
Wi-Fi
,蓝牙,照相机,
NFC
,
GPS
和定向的感应器都可以运行。
Galaxy Nexus
变异版本可以使用的是
GSM/HSPA+ “maguro”
配置
(
只有在它已经被
“yakju”
或者
“takju”
操作系统所替代
)
,以及
VZW CDMA/LTE "toro"
配置。在这些设备上,图形和视
频可以生效,和
Wi-Fi
,蓝牙一样,它们都通过各自的细胞网络连接。
NFC
和方向感应器也可以工作。
Galaxy Nexus
在
jb-mr1-dev-plus-aosp
分支上实验性的通过
Sprint CDMA/LTE
配置信息
“toroplus”
。在此配置中,细胞网络并不能正常工作,其他的功能像他们在
“toro”
中一样的工作。
使用
Android 4.1.2
,
Motorola Xoom
可以用在产于美国的
Wi-Fi
配置
“wingray“
。图形,音频,
Wi-Fi
和蓝牙以及方向感应都可以正常工作。
所有
Nexus S
和
Nexus S 4G
的配置都可以用于
Android 4.1.2
上。在这些设备上,所有的硬件都可以正常的工作。
此外,
PandaBoard
a.k.a ”panda“
可以被用在
jb-mr1-dev-plus-aosp
分支上,但是仅仅是理论上可行。具体如何通过
Android
开源工程来使用
PandaBoard
,在资源树中的
device/ti/panda/README
中查看。
创建
fastboot
和
adb
如果你还没有安装好这些工具,
fastboot
和
adb
可以通过一般的
build
系统来构建。按照网页中有关
Build and Running
的信息,替换掉主要的
make
命令,改为一下的命令:
$ make fastboot adb
启动进入
fastboot
模式
通过冷启动,下面核心的组合可以被用来进入
fastboot
模式,这是一个在
bootloader
中的一种模式,可以被用来启动设备:
Devices
Keys
shamu
Press and hold Volume Down, then press and hold Power
fugu
Press and hold Power
volantis
Press and hold Volume Down, then press and hold Power
hammerhead
Press and hold both Volume Up and Volume Down, then press and hold Power
flo
Press and hold Volume Down, then press and hold Power
deb
Press and hold Volume Down, then press and hold Power
manta
Press and hold both Volume Up and Volume Down, then press and hold Power
mako
Press and hold Volume Down, then press and hold Power
grouper
Press and hold Volume Down, then press and hold Power
tilapia
Press and hold Volume Down, then press and hold Power
phantasm
Power the device, cover it with one hand after the LEDs light up and until they turn red
maguro
Press and hold both Volume Up and Volume Down, then press and hold Power
toro
Press and hold both Volume Up and Volume Down, then press and hold Power
toroplus
Press and hold both Volume Up and Volume Down, then press and hold Power
panda
Press and hold Input, then press Power
wingray
Press and hold Volume Down, then press and hold Power
crespo
Press and hold Volume Up, then press and hold Power
crespo4g
Press and hold Volume Up, then press and hold Power
同样的,命令
adb reboot bootloader
可以被用于直接重启
Android
进入
bootloader
模式,并且不需要核心组合。
解锁
bootloader
只有
bootloader
允许才能刷入客户端。
默认情况下
bootloader
是上锁的。在设备处于
fastboot
模式下,
bootloader
可以这么解锁:
$ fastboot oem unlock
程序必须确认在屏幕上,并且出于隐私原因将会删除用户数据。这只需要执行一次即可。
所有数据都被删除,也就是说不仅仅是应用程序的私有数据,还包括那些可以通过
USB
轻易获取的公共数据,其中包含照片和电影,都会被删除。请在解锁
bootloader
之前,确认重
要的数据是否都做了备份。
在
Nexus 10
上,解锁
bootloader
之后内置的存储被置于未格式化的状态,所以必须通过下面的命令格式化:
$ fastboot format cache
$ fastboot format userdata
bootloader
可以通过下面的命令进行加锁
$ fastboot oem lock
注意,这会清除用户在
Xoom
上的数据(包括
USB
共享数据)
获取特定的二进制数据
Android
开源工程不能单单从纯粹的源码中使用,而且还必须通过硬件厂商的连接库才能运行,特别是那些具有硬件图像加速功能的手机。
官方提供给支持的设备的二进制文件被标以
AOSP
标签免费版本,是可以从
Google's Nexus driver page
中下载的。这些用不开源的代码,增加了额外的硬件能力。安装构建
AOSP
当前
分支,请使用
Binaries Preview for Nexus Devices
。
当给一个设备创建
master
分支时,大多数被标记发放或者多数不久之前的二进制数据应该是可以被使用的。
取出特定的二进制数据
每一个特定的二进制数据,都会通过一个自取脚本,从压缩的文档中获取。解压缩每一个文件,从资源树的根目录中,运行包括自取脚本,确认你同意封闭许可协议,之后二进制文件
以及他们的匹配文件将会在资源树的
vendor/
层中安装。
添加特定二进制数据时的清理
为了确保取出后的二进制数据正确的添加进账号,之前已经存在对外输出的构建必须像这样删除:
$ make clobber
选取和构建匹配设备的配置
匹配和构建
Android
开源工程的步骤被写在了
Building
上。
通过登录菜单,给大多数设备推荐的
builds
,当运行无参数
lunch
命令时是可以运行的。适配
Nexus
的工厂图片和二进制数据可以在这里下载:
https://developers.google.com/android/nexus/images
https://developers.google.com/android/nexus/drivers
Device
Code name
Build configuration
Nexus 6
shamu
aosp_shamu-userdebug
Nexus Player
fugu
aosp_fugu-userdebug
Nexus 9
volantis (flounder)
aosp_flounder-userdebug
Nexus 5 (GSM/LTE)
hammerhead
aosp_hammerhead-userdebug
Nexus 7 (Wi-Fi)
razor (flo)
aosp_flo-userdebug
Nexus 7 (Mobile)
razorg (deb)
aosp_deb-userdebug
Nexus 10
mantaray (manta)
full_manta-userdebug
Nexus 4
occam (mako)
full_mako-userdebug
Nexus 7 (Wi-Fi)
nakasi (grouper)
full_grouper-userdebug
Nexus 7 (Mobile)
nakasig (tilapia)
full_tilapia-userdebug
Galaxy Nexus (GSM/HSPA+)
yakju (maguro)
full_maguro-userdebug
Galaxy Nexus (Verizon)
mysid (toro)
aosp_toro-userdebug
Galaxy Nexus (Experimental)
mysidspr (toroplus)
aosp_toroplus-userdebug
PandaBoard (Archived)
panda
aosp_panda-userdebug
Motorola Xoom (U.S. Wi-Fi)
wingray
full_wingray-userdebug
Nexus S
soju (crespo)
full_crespo-userdebug
Nexus S 4G
sojus (crespo4g)
full_crespo4g-userdebug
不要在
Nexus 7
上使用
4.1.1
,此机型只能使用
4.1.2
或更高版本。
设备刷入系统
如果有必要请将设备设置成
fastboot
模式(详情请看上文)。
一个完整的
Android
系统可以用一条命令来给设备刷入一个系统:在经过核对被写入的系统已经成功的和已经安装过的
bootloader
,广播之间可以相互协作后,会将启动,修复,系统
三个部分写在一块,最后重启系统。这样的操作也会清楚用户数据,就跟之前在
fastboot oem unlock
中提到的差不多。
$ fastboot -w flashall
需要注意的是,在
Motorola Xoom
上,文件系统创建出的
via fastboot
并不会良好的工作,并且强烈推荐用下面的命令重建它:
$ adb reboot recovery
一旦进入回复,打开菜单(按下电源和音量
+
),清除缓存部分,之后清除数据。
恢复设备出厂值
Nexus 5,Nexus 10,Nexus 4,Nexus Q,Nexus 7,Galaxy Nexus (GSM/HSPA+ "yakju"
和
"takju",
和
CDMA/LTE "mysid"
以及
"mysidspr")
,
Nexus S
和
Nexus S 4G
的出厂图片,都可以在
Google's
factory image
页面下载。
Motorola Xoom
的工厂图片则直接通过
Motorola
发布。
构建内核
如果你只对内核感兴趣,你可以利用这篇文章来帮助你下载并且构建出合适的内核。
下面的信息我们假定你还没有下载所有的
AOSP
。如果你已经下载了所有的
AOSP
,你可以跳过
git clone
的部分到下载实际的内核源码。
在下面的例子中,我们将使用
Pandaboard
内核。
明确要创建的内核
这张表列出了内核源码的名字,位置以及二进制数据:
Devices
Binary location
Source location
Build configuration
shamu
device/moto/shamu-kernel
kernel/msm
shamu_defconfig
fugu
device/asus/fugu-kernel
kernel/x86_64
fugu_defconfig
volantis
device/htc/flounder-kernel
kernel/tegra
flounder_defconfig
hammerhead
device/lge/hammerhead-kernel
kernel/msm
hammerhead_defconfig
flo
device/asus/flo-kernel/kernel
kernel/msm
flo_defconfig
deb
device/asus/flo-kernel/kernel
kernel/msm
flo_defconfig
manta
device/samsung/manta/kernel
kernel/exynos
manta_defconfig
mako
device/lge/mako-kernel/kernel
kernel/msm
mako_defconfig
grouper
device/asus/grouper/kernel
kernel/tegra
tegra3_android_defconfig
tilapia
device/asus/grouper/kernel
kernel/tegra
tegra3_android_defconfig
maguro
device/samsung/tuna/kernel
kernel/omap
tuna_defconfig
toro
device/samsung/tuna/kernel
kernel/omap
tuna_defconfig
panda
device/ti/panda/kernel
kernel/omap
panda_defconfig
stingray
device/moto/wingray/kernel
kernel/tegra
stingray_defconfig
wingray
device/moto/wingray/kernel
kernel/tegra
stingray_defconfig
crespo
device/samsung/crespo/kernel
kernel/samsung
herring_defconfig
crespo4g
device/samsung/crespo/kernel
kernel/samsung
herring_defconfig
你可能会想查看设备工程中核心组件里面你所感兴趣的
git
日志。
设备工程在当前格式的设备
/<vendor>/<name>
目录下。
$ git clone https://android.googlesource.com/device/ti/panda
$ cd panda
$ git log --max-count=1 kernel
这里的内核组件提交信息中包含了一部分有问题的内核源码的
git log
信息。第一进入的是最近一次的,也就是用于构建内核的信息。你在下面的步骤中会需要用到它。
辨别内核版本
为了查明在实际的系统映像中所使用的内核版本,在内核文件中执行下面的代码:
$ dd if=kernel bs=1 skip=$(LC_ALL=C grep -a -b -o $'\x1f\x8b\x08\x00\x00\x00\x00\x00' kernel | cut -d ':' -f 1) | zgrep -a 'Linux version'
在
Nexus 5 (hammerhead)
,你可以用这个命令:
$ dd if=zImage-dtb bs=1 skip=$(LC_ALL=C od -Ad -x -w2 zImage-dtb | grep 8b1f | cut -d ' ' -f1 | head -1) | zgrep -a 'Linux version'
下载资源
下载哪一个取决于你所想要的:
$ git clone https://android.googlesource.com/kernel/common.git
$ git clone https://android.googlesource.com/kernel/x86_64.git
$ git clone https://android.googlesource.com/kernel/exynos.git
$ git clone https://android.googlesource.com/kernel/goldfish.git
$ git clone https://android.googlesource.com/kernel/msm.git
$ git clone https://android.googlesource.com/kernel/omap.git
$ git clone https://android.googlesource.com/kernel/samsung.git
$ git clone https://android.googlesource.com/kernel/tegra.git
•
goldfish
工程中包含为模拟器平台使用的内核源码。
•
msm
工程有可供
ADP1
,
ADP2
,
Nexus One
,
Nexus 4
,
Nexus 5
,
Nexus 6
,也可以被当做一个起始点给
Qualcomm MSM
芯片组使用。
•
omap
工程被用于
PandaBoard
和
Galaxy Nexus
,也可以被当做一个起始点给
TIOMAP
芯片组使用。
•
samsung
工程是为了
Xoom
,
Nexus 7
,
Nexus 9
,也可以被当做一个起始点给
Samsung Hummingbird
芯片组使用。
•
tegra
工程是给
Xoom
,
Nexus 7
,
Nexus 9
,也可以被当做一个起始点给
NVIDIA Tegra
芯片组使用。
•
exynos
工程包含供
Nexus 10
的核心源码,也可以被当做一个起始点给
Samsung Exynos
芯片组使用。
•
x86_64
工程包含有
Nexus Players
的核心源码,也可以被当做一个起始点给
Intel x86_64
芯片组。
下载预构建
gcc
确保预生成的工具链在你的环境变量中
$ export PATH=$(pwd)/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin:$PATH
或者
$ export PATH=$(pwd)/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.6/bin:$PATH
在一个
Linux host
中,如果你没有
Android
源码树,你可以从下面的地址中下载预编译工具链:
$ git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6
构建
作为一个例子,我们将会使用下面的命令来构建
panda
内核:
$ export ARCH=arm
$ export SUBARCH=arm
$ export CROSS_COMPILE=arm-eabi-
$ cd omap
$ git checkout <commit_from_first_step>
$ make panda_defconfig
$ make
构建
tuan
内核,你需要将之前的命令中所有
'panda'
改为
'tuna'
。
核心组件将会输出:
arch/arm/boot/zlmage
。它可以被拷贝进入
Android
源码树中,以便于构建适合的
boot
镜像。
或者你可以使用
make bootimage
命令,包含
TARGET_PREBUILD_KERNEL
变量,或者其他任何
make
命令行用来构建
boot
镜像。
$ export TARGET_PREBUILT_KERNEL=$your_kernel_path/arch/arm/boot/zImage
那个变量支持所有用过
device/common/populare-new-device.sh
命令启动的设备。
Android
平台
64
位构建指导
概述
从构建系统的观点看,最显著的更改是用同一个
build
就可以生成出可以支持在
2
个目标
CPU
架构上(
64
位和
32
位)的构建文件。这就是被人们所知的
多库构建
。
为了构建本地静态库和共享库,构建系统启动规则去给两个架构的
CPU
生成二进制文件。产品配置(
PRODUCT_PACKAGE
),和图形依赖,然后寻找到使用的是哪一个二进制文
件,最后安装进系统镜像中。
构建系统默认情况下只构建
64
位版本给可执行文件和应用程序,但是你可以重写这个设置,通过一个全局的
BoardConfig.mk
参数或者一个局部的参数。
注意:
如果一个应用要开放一个
API
给其他可能是
32
位或是
64
位的应用时,这个应用必须在
manifest
文件中有
android:multiarch
属性,并且将其值设为
true
,这样可以避免潜在的
错误。
产品配置
在
BoardConfig.mk
文件中,我们添加下面的参数来配置第二个
CPU
架构和接口:
TARGET_2ND_ARCH
TARGET_2ND_ARCH_VARIANT
TARGET_2ND_CPU_VARIANT
TARGET_2ND_CPU_ABI
TARGET_2ND_CPU_ABI2
你可以在
build/target/board/generic_arm64/BoardConfig.mk
中查看事例。
如果你想默认构建给
32
位的可执行文件和应用,设置下面的参数:
TARGET_PREFER_32_BIT := true
然而,你也可以在
Android.mk
文件中通过重写
module-specific
参数来进行设置。
在一个多库构建中,只要他们被构造系统定义了,命名在
PRODUCT_PACKAGES
中的模块就可以同时覆盖了
32
位和
64
位这两种二进制文件。在依赖库的获取中,只有被另外一个
32
位
的可执行文件或库所请求时才会安装
32
位库。在
64
位库中也是一样的情况。
但是,命名在
make
命令行中的模块仅仅只覆盖
64
位的版本。举个例子,在执行完
lunch aosp_arm64-eng,make libc
后,只构建了
64
位的库。要构建
32
位的库,你需要运行
make libc_32
。
在
Android.mk
中描述模块
你可以使用
LOCAL_MULTILIB
变量中配置你要构建的
32
位或者
64
位以及重写全局的变量
TARGET_PREFER_32_BIT
。
按照下列中的一个设置你的
LOCAL_MULTILIB
:
•
“both”
:同时构建
32
位和
64
位
•
“32”
:只构建
32
位
•
“64”
:只构建
64
位
•
“first”
:只给第一个架构构建(
在
32
位中优先
32
位,在
64
位中优先
64
位)
•
“”
:默认参数;构建系统构建哪个架构取决于模块类以及其他
LOCAL_
参数,比如
LOCAL_MODULE_TARGET_ARCH
,
LOCAL_32_BIT_ONLY
等等。
在多库构建中,像
ifeq $(TARGET_ARCH)
这种附件条件将不再起作用。
如果你想给一些特殊的架构上构建你的模块,下面的参数可能会帮助你
:
•
LOCAL_MODULE_TARGET_ARCH
:这个可以设置成一个架构的列表,有些像
arm x86 arm64
.
只有被构建的架构在列表中才会被构建系统添加进入当前模块。
•
LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH
:这是
LOCAL_MODULE_TARGET_ARCH
的对立选项。只有被构建的架构不在列表中才会被构建系统添加进入当前模
块。
这里有上面两个变量的缩小版:
•
LOCAL_MODULE_TARGET_ARCH_WARN
•
LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN
如果当前模块跳出了应该有的架构限制,那么构建系统将会提出警告。
启动
arch-specific
构建标识,使用
arch-specific LOCAL_
变量。一个
arch-specific LOACL_
变量一般情况是
LOCAL_
跟上一个架构的后缀,比如
:
•
LOCAL_SRC_FILES_arm, LOCAL_SRC_FILES_x86
,
•
LOCAL_CFLAGS_arm, LOCAL_CFLAGS_arm64
,
•
LOCAL_LDFLAGS_arm, LOCAL_LDFLAGS_arm64
,
需要注意的是:所有的
LOCAL_
变量支持
arch-specific
变体。查看最新的相关列表,请看
build/core/clear_vars.mk
。
安装路径
在前面,你应该使用
LOCAL_MODULE_PATH
来替代默认的那个用于安装一个库到一个路径。比如
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
在多库构建中,使用
LOCAL_MODULE_RELATIVE_PATH
来替代:
LOCAL_MODULE_RELATIVE_PATH := hw
这样就可以让
64
位和
32
位都可以安装在正确的路径下了。
如果你想构建一个同时在
32
位和
64
位下都可以运行的可执行文件,你会都需要使用下面中的一个变量来区分你的安装路径:
•
LOCAL_MODULE_STEM_32, LOCA\L_MODULE_STEM_64
具体说明安装文件的名字
•
LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64
具体说明安装路径
生成源码
在多库构建中,如果你在
$(local-intermediates-dir)
(或者含有参数的
$(intermediates-dir-for)
)生成源文件,那么它将不会正常工作。这是因为
32
位和
64
位会同时请求中间产生的源文
件,但是
$(local-intermediates-dir)
只指向其中这两个中的其中一个路径。
值得高兴的是,构建系统现在为生成源文件提供可共享,对多库友好的中间文件路径。你可以使用
$(local-generated-sources-dir)
或者
$(generated-sources-dir-for)
来获取一个文件路径。
他们的用法跟
$(local-intermediates-dir)
和
$(intermediates-dir-for)
类似。
如果源文件已经在新的中间文件路径中生成,并且被
LOCAL_GENERATED_SOURCES
所接管,那么它将在多库构建中生成
32
位和
64
位文件。
预构建
在多库中,你不能用
TARGET_ARCH
(或者连同
TARGET_2ND_ARCH
一块使用)来告诉构建系统要预构建二进制文件的目标是什么。用之前提到的
LOCAL_
变量
LOCAL_MODULE_TARGET_ARCH
或者是
LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH
来替换。
用这些变量,构建系统即使是在一个
64
位的多库构建中也能选择匹配
32
位的预构建二进制文件。
如果你想使用选择的架构来给预构建的二进制文件计算出源文件路径,你可以使用
$(get-prebuilt-src-arch)
。
Dex
预选择
在
64
位设备上,默认情况下我们同时给系统镜像生成
32
位和
64
位的
odex
文件以及一些
Java
库。默认我们只给
64
位架构生成
odex
文件给
APK
文件。如果某个应用可能会同时在
32
位和
64
位上登录,请使用
LOCAL_MULTILIB := both
来确保
32
位和
64
位的
odex
文件都被生成。这个标识同样也会告诉构建系统,如果有应用需要,就包括
32
位和
64
位的
JNI
库。
已知的问题
即使是在我们最好的照看下,也会偶尔出现小的问题。这篇文章会持续追踪在使用
Android
源码的过程中出现的问题。
构建问题
在
toro
构建中丢失
CellBroadcastReceiver
症状
在
AOSP
给
toro
的构建中(
Jelly Bean 4.2.1
之后的版本),
CellBroadcastReceiver
并不会包括在系统中。
原因:
在
vendor/samsung/toro/device-partial.mk
中的
PRODUCT_PACKAGES
有一个排版错误:有一个
H
替代了
K
。
修复:
使用
4.2.2
的最后一个版本包,或者手工的修改排版。
丢失
CTS
原生
XML
生成器
症状
:
在有些
IceCreamSandwich
或之后的版本构造中,在构造中会先打印下面的警告:
/bin/bash: line 0: cd: cts/tools/cts-native-xml-generator/src/res: No such file or directory
原因:
有些
makefile
依赖的路径并不存在。
修复:
无。这是一个无害的警告。
Black Gingerbread
模拟器
症状
:
这个模拟器直接由
gingerbread
分支构造而且没有启动,一直卡死在绿屏状态下。
原因:
gringerbread
分支使用的是
R7
版本的模拟器,该模拟器并没有所有必要的特征来运行最近版本的
gingerbread
。
修复:
使用
R12
版本的模拟器,以及一个新的匹配工具的核心。不需要清理
build
。
$ repo forall platform/external/qemu -c git checkout aosp/tools_r12
$ make
$ emulator -kernel prebuilt/android-arm/kernel/kernel-qemu-armv7
构建在
MacOS 10.7 Lion
上的模拟器不工作
症状:
构建在
MacOS 10.7 Lion
或者
XCode 4.x
上的模拟器(任何版本)不工作。
原因:
一些在开发环境的更改导致了模拟器不能从工作环境中编译。
修复:
使用一个
SDK
中的二进制文件,该文件可以构建在用
XCode 6
的
MacOS 10.6
上,并且可以在
MacOS 10.7
上工作。
WITH_DEXPREOPT=true
以及模拟器构建。
症状:
在模拟器的构建中,当部分行为的构建以及同步(使系统没有依赖)时,结果构建没有生效。
原因:
默认情况下,现在所有模拟器构建都会进行
Dex
优化,这就会导致每次框架改变都会请求跟随所有的依赖,用来重新优化应用。
修复:
用
export WITH_DEXPREOPT=false
使本地的
Dex
优化失效,用
make installclean
删除已经存在的优化版本,然后运行一个完整的构造,重新生成没有优化的版本。在进行完上述
操作之后,部分的构造将会开始工作。
构造过程中出现
Permission Denied
症状:
所有的构建失败都伴随着
Permission Denied
,可能伴随着反病毒警告。
原因:
有些反病毒程序会将一些
Android
源码树中的文件错误的识别成包含病毒。
修复:
经过确认没有病毒存在后,让反病毒程序在
Android
源码树中失效。这样做对减少构建次数有好处。
构建错误与使用错误的编译器
特征:
构建错误有许多的特征。其中一个特征是:
cc1: error: unrecognized command line option "-m32”
原因:
在
PATH
中
Android
构建系统使用的是默认的编译器,假设在
host
中有合适的编译器生成的二进制文件。其他情况(比如使用
Android NDK
或者构建内核)将会导致默认的编译器不
是主编译器。
修复:
使用
“clean”
脚本,确保没有别的操作会更改默认的编译器。
由于无默认工具设置导致的构造错误
特征:
构造失败有很多特征,可能是由于文件丢失或者文件格式错误。其中一个的特征是
member [...] in archive is not an object
。
原因:
Android
构建系统往往使用很多
host
工具并依赖于他们默认的行为。有些设置更改了工具的行为并使他们的行为干扰到了系统构建。已知会导致问题的变量是
CDPATH
和
GREP_OPTIONS
。
修复:
在尽可能少的自定义环境中构建
Android
。
在
MacOS 10.7
上构建
4.0.x
以及之前版本的错误
特征:
在
MacOS 10.7
上构建
IceCreamSandwich 4.0.x
(和更老的版本)失败,并提示下面的错误信息:
Undefined symbols for architecture i386: "_SDL_Init”
原因:
在
MacOS 10.7
上不能适配
4.0.x
修复:
降级电脑系统到
MacOS 10.6
或者是在
MacOS 10.7
上构造当前版本。
$ repo init -b master
$ repo sync
在
MacOS
上用
XCode 4.3
的构建错误
特征:
当使用
XCode 4.3
时所有的构造都失败
原因:
XCode 4.3
的默认编译器从
gcc
改成了
llvm
,而
llvm
拒绝过去可以在
gcc
上通过的代码。
修复:
使用
XCode 4.2
。
在
Ubuntu 11.10
上构造
4.0.x
或更早版本的错误
特征:
在
Ubuntu 11.10
或之后的版本中构建
IceCreamSandwich 4.0.x
(或者其之前的版本)会出现类似
<command-line>:0:0: warning: "_FORTIFY_SOURCE" redefined [enabled by
default]
的错误。
原因:
Ubuntu 11.10
使用
gcc
标记是默认的,而
Android
也会定义一个默认的标记,这样导致了冲突。
修复:
可以选择降级到
Ubuntu 10.04
或者使用当前分支,这样就可以在
Ubuntu 11.10
或者之后的版本中使用。
$ repo init -b master
$ repo sync
源文件同步问题
复杂同步源代码(代理问题)
特征:
在
http
错误的时候
repo
或者是
repo sync
失败,通常是
403
或者是
500
。
原因
有很多引起错误的原因,其中最常见的是关联到了
http
代理,这是传输大数据的时候比较困难。
修复:
暂时还没有通用解决方法,使用
python 2.7
以及明确的使用
repo sync -jl
来改善一些用户的使用情况。
复杂同步源代码(
VituralBox
以太网问题)
特征:
当在一些
VituralBox
安装中运行
repo sync
,进程伴随着可能的特征挂起或者失败。其中一种特征是:
DownloadError: HTTP 500 (Internal Server Error: Server got itself
in trouble)
。
原因:
默认的
VirualBox
的网络行为是使用
NAT
(
Network Addrss Translation
)连接客户系统来连接网络。繁重的网络行为将会引发
NAT
中的某些代码。
修复:
配置
VirtualBox
让其使用桥连接来代替
NAT
。
复杂同步源代码(
NDS
问题)
特征:
当运行
repo sync
时,由于无法识别
hostname
伴随着一些错误导致进程失败。其中一个错误是:
<urlopen error [Errno -2] Name or service not known>
。
原因:
有些
DNS
系统在应对大数量的请求时需要同步源码树而导致运行缓慢(在最坏的假设情况下可能有好几百请求)
修复:
手工移除相关的
hostname
,并在本地硬编码那些结果。
你可以用
nslookup
命令来移除,这可以给你一系列的数字
IP
地址(通常是在输出中的
“Address”
部分)。
$ nslookup googlesource.com
$ nslookup android.googlesource.com
之后你可以在本地硬编码他们到
/etc/hosts
,再在这个文件中以下面的格式添加两行:
aaa.bbb.ccc.ddd googlesource.com
eee.fff.ggg.hhh android.googlesource.com
需要注意的是这只在服务的地址没有改变的情况下,所以如果他们更改了地址而你又无法连接,这时候你就要重新的获取
hostname
,相应的你还要更改
etc/hosts
。
复杂同步源代码(
TCP
问题)
特征:
在同步时
repo sync
挂起,通常都是在已经同步了
99%
的情况下。
原因:
在
TCP/IP
堆的设置会使一些网络环境变的很糟糕,比如
repo sync
会既不编译,也不失败。
修复:
在
Linux
上执行
sysctl -w net.ipv4.tcp_window_scaling=0
。在
MacOS
上,使
rfc 1323
扩展失效。
运行问题
照相机和
GSP
在
Galaxy Nexus
上失效
特征:
照相机和
GSP
在
Galaxy Nexus
上失效。举个例子,照相机应用一启动就崩溃。
原因:
在
Android
开源项目中不提供这些硬件外设需要专有库。
修复:
无。
3
开发
开发
应用
Android
代码时,你需要同时使用
Git
和
Repo
,在大多数情况下,你可以使用
Git
而不是
Repo
,或是混合使用
Git
和
Repo
形成的复杂命令。然而,把
Repo
使用于基本跨网络
(
across-network
)的操作时,将会使你的工作更加简单。
Git
是一个开源的版本控制系统,设计来处理分布在多个存储库的大项目。在
Android
背景中,我们可以使用
Git
进行本地操作,如本地分支,提交,差异,和编辑。其中我们在建立
Android
项目所面临的其中一个挑战就是如何最好地支持外界社区
——
从爱好社区到大型
OMEs
构建大众消费设备。我们希望组件能够被替换,我们还想要有趣的组件去发展他们在
Android
以外的生活。我们首先选择一个分布式的版本控制系统,然后进一步将其缩小到
Git
。
Repo
是我们建立在
Git
顶部的一个存储库管理工具。
Repo
在必要时可以统一许多个
Git
仓库,上传到我们的
版本控制系统
,并且自动化
Android
部分开发工作流程。
Repo
并不意味着
取代
Git
,只是帮助更容易地在
Android
环境中使用
Git
。
Repo
命令是一个可执行的
Python
脚本,你可以把它放在你的任何路径上。在使用
Android
源文件工作时,你将把
Repo
使用于
跨网络操作。例如,使用一个单一的
Repo
命令,你就可以从多个存储库下载文件到你的本地目录下。
Gerrit
是一个基于
Web
的代码审查系统,使用的是
Git
。
Gerrit
鼓励所有授权用户更多的集中使用
Git
来提交变化,如果他们发布代码审查,
Gerrit
将可以进行自动合并。此外,
Gerrit
通过浏览器显示每一步变化使审查变得更加容易,并且支持内联注释。
基本工作流程
与存储库交互的基本模式如下:
1.
使用
repo start
开始一个新的主题分支。
2.
编辑文件。
3.
使用
git add
暂存更改。
4.
使用
git commit
提交更改。
5.
使用
repo upload
上传更改到审查服务器。
图片
3.1
images
任务参考
下面的任务列表总结了如何进行普通的
Repo
和
Git
任务操作。关于使用
Repo
下载资源的信息,请参阅
下载资源
。
同步你的客户端
同步所有可用项目的文件:
$ repo sync
同步已选择项目的文件:
$ repo sync PROJECT0 PROJECT1 PROJECT2 ...
创建主题分支
当你开始进行一个改变时,在你的本地工作环境上新建一个主题分支,例如当你开始解决
bug
或开发新功能的时候。主题分支不是原始文件的复制;它是一个特定的提交的指向。这使
得创建的本地分支能在它们之间进行轻微操作的切换。通过使用分支,你可以把当前的工作与其他工作分离。有关使用主题分支的一篇有趣的文章,请参阅
分离特性分支
。
使用
Repo
开始一个主题分支,导航到该项目进行修改和发布:
$ repo start BRANCH_NAME .
请注意,这个期间是在当前工作目录下。验证是否已创建新的分支:
$ repo status .
使用主题分支
要指定分支到一个特定的项目:
$ repo start BRANCH_NAME PROJECT_NAME
查看
android.googlesource.com
所有项目的列表。此外,如果你已经导航到特定项目的目录,那么你可以简单地传递一个时期代表当前项目。
要切换到您在本地工作环境中创造的另一个分支:
$ git checkout BRANCH_NAME
查看现有分支的列表:
$ git branch
或
$ repo branches
当前分支的名字将被标星号表示优先。
注意:一个
bug
可能会导致
repo sync
重置本地的分支。如果你运行
repo sync
之后,
git branch
显示
*
(没有分支),那就再次运行
git checkout
。
暂存文件
默认情况下,
Git
通知但没有跟踪你在一个项目中所做的更改。为了让
Git
保存你的更改,你必须将它们标记在一个
commit
中。这也称之为
“staging
(暂存)
”
。
你可以在运行下面命令来暂存更改
git add
它接受作为参数的项目目录中的任何文件或目录。尽管
git add
并不如名字表示的这样简单地将文件添加到
Git
仓库,但是它也是可以用来暂存文件的修改和删除的。
查看客户端状态
列出文件的状态:
$ repo status
查看未提交的编辑:
$ repo diff
repo diff
命令能够显示你所做的每一个本地编辑,除了已经进入提交的,如果你正准备现在提交。如果你现在提交,那么你将进入提交并且可以看到每一个编辑状态,你需要一个
Git
命令,即
git diff
。运行它之前,首先确定你是在当前项目的目录下:
$ cd ~/WORKING_DIRECTORY/PROJECT
$ git diff ——cached
提交更改
在
Git
中,一个
commit
是版本控制的一个基本单位,是组成目录结构的一个快照(
snapshot
),也是组成整个项目的文件内容。在
Git
中创建一个
commit
很简单,只需要输入如下代
码:
git commit
你将在你最喜欢的编辑器中收到一条
commit
消息的提示;请为你提交到
AOSP
的更改都提供一条有效信息。如果你不添加记录信息,你的
commit
将会被中止。
上传更改到
Gerrit
上传之前,更新到最新版本:
repo sync
然后运行
repo upload
这将会把你已经提交的更改列表出来,并且提示你选择分支上传到审查服务器。如果只有一个分支,那么你会看到一个简单的
y/n
提示。
恢复同步冲突
如果一个
repo sync
显示同步冲突:
•
查看拆分的文件(
status code = U
)。
•
必要时编辑冲突区域。
•
在相关的项目目录中更改,为上述文件运行
git add
和
git commit
,然后
“rebase”
这个更改。例如:
$ git add .
$ git commit
$ git rebase --continue
•
当
rebase
完成时再一次开始完整的同步:
$ repo sync PROJECT0 PROJECT1 ... PROJECTN
清理你的客户端文件
更改被合并到
Gerrit
之后更新你的本地工作目录:
$ repo sync
安全的移除已过时的主题分支:
$ repo prune
删除客户端
因为所有暂存文件都存储在你的客户端,你只需要从你的文件系统直接删除目录:
$ rm -rf WORKING_DIRECTORY
删除客户端将会
永久地删除
你还没有上传审查的更改。
Git
和
Repo
备忘录
图片
3.2
images
Repo
命令手册
Repo
的使用形式如下:
repo <COMMAND> <OPTIONS>
可选元素显示在方括号
[]
里面。例如,许多命令接受的项目列表作为参数。您可以指定项目列表作为名称列表或本地源目录的路径列表:
repo sync [<PROJECT0> <PROJECT1> <PROJECTN>]
repo sync [</PATH/TO/PROJECT0> ... </PATH/TO/PROJECTN>]
帮助
一旦
Repo
被安装,你可以找到总结所有命令的最新的文档,运行:
repo help
在
Repo
目录中运行如下这个,你可以获得任何命令的信息:
repo help <COMMAND>
初始化
$ repo init -u <URL> [<OPTIONS>]
在当前目录下安装
Repo
。这会产生一个
.repo/
目录,目录包括装
Repo
源代码和标准
Android
清单文件的
Git
仓库。
.repo/
目录还包括
manifest.xml
,是一个在
.repo/manifests/
目录选择清单的符号链接。
选项:
•
-u
:指定一个恢复清单仓库的地址(
URL
)。常见的清单可以在
https://android.googlesource.com/platform/manifest
找到。
•
-m
:在仓库里选择一个清单文件。如果没有清单名称,那么默认是
default.xml
。
•
-b
:指定一个修正,例如,一个特殊的清单分支(
manifest-branch
)。
注意:所有剩余的
Repo
命令,在当前工作目录下必须是
.repo/
的父目录或是一个父目录的子目录。
同步
repo sync [<PROJECT_LIST>]
下载新的更改,更新在你本地环境中的工作文件。如果你不带参数运行
repo sync
,它将同步所有项目的文件。
当你运行
repo sync
,将会发生:
•
如果项目从来没有被同步过,那么
repo sync
相当于
git clone
。在远程仓库的所有分支都被复制到本地项目目录。
•
如果项目曾经已经被同步过,那么
repo sync
相当于:
git remote update
git rebase origin/<BRANCH>
<BRANCH>
是本地项目目录中的当前检查的分支。如果本地分支不跟踪远程仓库的分支,那么没有同步发生的项目。
-
如果
git rebase
操作导致合并冲突,你将需要使用正规的
Git
命令
(例如,
git rebase ——continue
)去解决这个冲突。
一个成功的
repo sync
之后,指定项目中的代码将和最新的代码留在远程仓库中。
选项:
•
-d
:切换指定项目回到清单修正。如果该项目目前是一个主题分支那就有帮助,但清单修正是暂时需要。
•
-s
:同步到一个已知的构建
manifest-server
在当前清单指定的元素。
•
-f
:继续同步其他项目,即使有项目同步失败。
上传
repo upload [<PROJECT_LIST>]
在指定的项目中,
Repo
把本地分支的更新比作远程分支在最后一次
Repo
同步。
Repo
会提示你选择一个或更多尚未上传审查的分支。
你选择一个或更多分支时,选到的分支上所有的
commits
会通过
HTTPS
连接传送到
Gerrit
。你将需要配置一个
HTTPS
密码去启用上传授权。查看
密码生成器
生成新的用户名
/
密码配
对去使用
HTTPS
。
当
Gerrit
在它的服务器接收到对象数据时,它会把每个
commit
转变成更改,所以审阅者可以单独的评论每条
commit
。将几条
“checkpoint” commits
一起合并到一条单个的
commit
上,
然后在你运行
repo upload
之前使用
git rebase -i
。
如果你不带参数运行
repo upload
,它将搜索所有项目上传的更改。
在更改(
changes
)上传之后进行编辑,你应该使用一个类似
git rebase -i
或
git commit --amend
的工具去更新你的本地的
commits
。你所有编辑完成之后:
•
确保更新的分支是当前已审查的分支。
•
在系列里的每个
commit
的括号内输入
Gerrit
改变
ID
:
```
第
3
章
Replacing from branch foo
[ 3021 ] 35f2596c Refactor part of GetUploadableBranches to lookup one specific... [ 2829 ] ec18b4ba Update proto client to support patch set replacments
第
3
章
Insert change numbers in the brackets to add a new patch set.
第
3
章
To create a new change record, leave the brackets empty.
```
上传完成后,更改将会有一个额外的补丁集(
Patch Set
)。
差异
repo diff [<PROJECT_LIST>]
在
commit
和工作目录之间使用
git diff
显示明显差异的更改。
下载
repo download <TARGET> <CHANGE>
从审查系统下载指定的更改,然后使它在你的项目的本地工作目录中可用。
例如,下载
change 23823
到你的平台
/
框架
/
基本目录:
$ repo download platform/build 23823
一个
repo sync
应该可以有效地移除任何通过
repo download
恢复的
commit
。或者,你可以检查远程分支;例如,
git checkout m/master
。
注意
:
当更改在
Gerrit
网络上可见时和
repo download
被所有用户找到时,期间,有一个轻微的镜像滞后,因为复制延迟存在于全世界所有的服务器。
forall
repo forall [<PROJECT_LIST>] -c <COMMAND>
在每个项目中被给予的
shell
命令。如下的附加环境变量是通过
repo forall
才变得有效的:
•
REPO_PROJECT
设置项目唯一的名称。
•
REPO_PATH
是相对于客户端
root
的路径。
•
REPO_REMOTE
是清单中远程系统的名称。
•
REPO_LREV
是清单中修订本的名字,翻译成一个本地跟踪分支。如果你需要通过清单修正去本地执行
git
命令的时候可以使用。
•
REPO_RREV
是清单中修订本的名字,正如在清单中所写的那样。
选项:
•
-c
:执行命令和参数。命令是通过
/bin/sh
评估的并且后面的任何参数就如
shell
位置的参数通过。
•
-p
:在指定命令的输出前显示项目标题。这是通过绑定管道到命令的
stdin
,
stdout
,和
sterr
流,并且用管道输送所有输出量到一个连续的流,显示在一个单一的页面调度会话
中。
•
-v
:显示命令写到
sterr
的信息。
删减
repo prune [<PROJECT_LIST>]
删减(删除)已经合并的标题。
开始
repo start <BRANCH_NAME> [<PROJECT_LIST>]
一个新分支的发展,从清单中指定的修正开始的。
<BRANCH_NAME>
参数应该提供一个更改的简短说明给你正在尝试建立的项目。如果你不知道,那就考虑使用默认名称。
<PROJECT_LIST>
指定将要参与这个主题分支的项目。
注意:
"."
是当前工作目录下的项目的一个方便的简写。
状态
repo status [<PROJECT_LIST>]
比较工作目录和暂存区(索引),和这个分支(
HEAD
)在每个项目指定的最近一次提交。为每个不同于这三个状态的文件展示一个摘要行。
运行
repo status
,查看当前分支的状态。状态信息将会在项目中列表出来。项目中的每个文件,两个字母的代码是经常被使用的:
在第一列中,大写字母表明了暂存区和最后一次提交状态的差异。
字母
含义
描述
-
无变化
在
HEAD
和在索引中是一样的
A
增加
不在
HEAD,
在索引
M
修改
在
HEAD,
在索引表示修改
D
删除
在
HEAD,
不在索引
R
重命名
不在
HEAD,
在索引中改变路径
C
复制
不在
HEAD,
在索引中复制另一份
T
改变模式
在
HEAD
和在索引中是一样的内容
,
改变模式
U
拆分
HEAD
和索引之间有冲突
;
要求解决
在第二列中,一个小写字母表明了工作目录和索引的差异。
字母
含义
描述
-
新建
/
未知
不在索引
,
在工作目录
字母
含义
描述
m
修改
在索引
,
在工作目录
,
修改
d
删除
在索引
,
不在工作目录
使用
Eclipse
本文将帮助您为
Android
平台开发建立
Eclipse IDE
。
注意:如果您正在寻找如何使用
Eclipse
开发
Android
上运行的应用程序的资料,那么这不是您要找的页面。你也许会发现
the Eclipse page on developer.android.com
页面更加有用。
基本设置
首先,重要的是要确保常规
Android
开发系统的设置。
cd /path/to/android/root
make
重要提示
:你将仍然使用
make
建立你的文件,实际运行(在模拟器上或者设备上)。你将使用
Eclipse
来编辑文件并且验证它们的编译,但是当你想要运行某些东西时你需要确保你
的文件保存在
Eclipse
里,并且在命令行(
shell
)里运行
make
。
Eclipse
的建立只是为了检查错误。
Eclipse
需要一个目录列表去搜索
Java
文件。这个被称为
“Java Build Path
(
Java
构建路径)
”
,还能够设置到
.classpath
文件。我们有一个示例版本让你开始。
cd /path/to/android/root
cp development/ide/eclipse/.classpath .
chmod u+w .classpath
如果必要的话,现在可以编辑复制
.classpath
。
增加
Eclipse
的内存设置
Android
项目(所占空间)非常的大以致有时
Eclipse
的
Java VM
在运行编译时内存不足。而编辑
eclipse.ini
文件就可以避免这个问题。在
Apple OSX
上,
eclipse.ini
文件是位于
/Applications/eclipse/Eclipse.app/Contents/MacOS/eclipse.ini
内存相关的默认设置(如
Eclipse 3.4
)
-Xms40m
-Xmx256m
-XX:MaxPermSize=256m
为
Android
开发的建议设置是:
-Xms128m
-Xmx512m
-XX:MaxPermSize=256m
这些设置是将
Eclipse
的
Java
堆的最小值设为
128 MB
,最大值设为
512 MB
,并且默认永久代的最大值为
256 MB
。
现在启动
Eclipse
:
eclipse
创建一个项目
现在为
Android
开发创建一个项目:
1.
如果
Eclipse
要求你选择一个工作区的位置,选择默认。
2.
如果你有一个
“
欢迎
”
屏幕,关闭它显示到
Java
视图。
3.
文件(
File
)
>
新建(
New
)
> Java
项目(
Java Project
)
4.
选择一个项目名称,
“android”
或者任何你喜欢的名称。
5.
取消使用默认位置,输入路径到
Android
根目录,然后点击
Finish
。
6.
等待建立项目的时候。(你会看到一个微妙的进度表在右下角)
一旦项目工作区创建,
Eclipse
也应当开始构建。从理论上讲,它的建立应该是没有错误的,你应该准备好开始启动。如果有必要,取消选择再重新选择项目自动构建(
Project Build
Automatically
)以强制重建。
注意:
Eclipse
有时会添加一个
import android.R
声明在你文件的顶部以使用资源,特别是当你要求
Eclipse
分类或以其他方式管理导入包(
imports
)。这将导致你的构造被破坏。
要留心找到那些错误的导入声明并删除掉它们。
当你同步时
每次你同步
Repo
,或者以其他方式改变
Eclipse
外部的文件(特别是
.classpath
)时,你需要更新
Eclipse
视图的以下东西:
1.
窗口(
Windows
)
>
显示视图(
Show View
)
>
导航(
Navigator
)
2.
在导航(
Navigator
)中,右键单击项目名称
3.
点击右键菜单中的刷新(
Refresh
)。
添加
Apps
到构建路径中
默认的
.classpath
包括核心系统的来源和一组
APP
的例子,但也许并不包括你想要的特定的
APP
。添加一个
APP
,你必须添加
APP
的源目录。需要在
Eclipse
里面完成这些:
1.
项目(
Project
)
>
属性(
Properties
)
2.
选择左边菜单上的
“Java Build Path
(
Java
构建路径)
”
上。
3.
选择
“Source”
选项卡。
4.
点击
“Add Folder…
(添加文件夹
…
)
”
5.
添加你的
APP
的
src
目录下。
6.
点击
OK
。
当你完后,你应该可以看到
“source folder”
路径在列表中如下显示:
android/packages/apps/YOURAPP/src
根据你所包含的
APP
,你可能也需要包含
android/dalvik/libcore
下的
othersrc/main/java
目录。如果你发现你不能在默认设置下构建的时候你就用这个方法。
Eclipse
格式化
你可以导入文件到
development/ide/eclipse
里面使得
Eclipse
跟随
Android
的样式规则。
1.
选择窗口(
Windows
)
>
参数选择(
Preferences
)
> Java >
代码风格(
Code Style
)。
2.
使用格式化(
Formatter
)
>
导入
android-formatting.xml
。
3.
整理导入包
(Imports) >
导入
android.importorder
。
使用
Eclipse
调试模拟器
你也可以使用
Eclipse
通过单步调试代码去调试模拟器。首先,开始运行模拟器:
cd /path/to/android/root
. build/envsetup.sh
lunch 1
make
emulator
如果模拟器正在运行,你可以看见一张手机的图片。
在另一个命令行,启动
DDMS
(
Dalvik
虚拟机调试管理器):
cd /path/to/android/root
ddms
你应该看到一个
splufty
调试控制台。
现在,在
Eclipse
中,您可以连接到模拟器:
1.
运行(
Run
)
>
打开调试对话框
…
(
Open Debug Dialog…
)
2.
右键单击
“Remote Java Application
(选择远程调试)
”
,选择
“New
(新建)
”
。
3.
选择一个你喜欢的名字,例如
“android-debug”
或任何东西。
4.
将
“Project”
设置为你的项目名称。
5.
主机(
Host
)依旧设置为
“localhost”
,但端口(
Port
)更改为
8700
。
6.
点击
“Debug
(调试)
”
按钮,这样就应该准备就绪了。
需要注意的是端口
8700
连接到任何的进程都是在目前
DDMS
控制台选择的,所以你需要确保
DDMS
已经选择你想要调试的进程。
你可能需要打开调试(
Debug
)视图(在
“Java”
视图图标的右上角,点击的
“Open Perspective
(打开视图)
”
的小图标然后选择
“Debug
(调试)
”
)。一旦你做了这些,你应该可以看到
一个线程的列表;如果你选择一个(线程)并且中断它(通过点击
“pause
(暂停)
”
图标),那么它应该显示堆栈跟踪,源文件和执行路线。断点和诸如此类的东西都应该在工作。
扩展材料
Mac
系统的苹果键替换
Ctrl
键
快捷键
功能
Ctrl-Shift-o
导入所有需要的包
Ctrl-Shift-t
按名称加载类
Ctrl-Shift-r
按名称加载非资源类
Ctrl-1
快速修复
Ctrl-e
最近查看的文件
Ctrl-space
自动完成
Shift-Alt-r
重构:重命名
Shift-Alt-v
重构:移动
Eclipse
不能正常运行时,该怎么做?
首先确认:
•
你准确地按照这个网页的说明去执行。
•
你的问题(
Problems
)视图没有显示任何错误。
•
你的应用程序遵从包
/
目录的构造。
如果你仍然有问题,请联系其中一个
Android
社区电子邮箱列表或
IRC
通道
。
Git
资源
有关
Git
的更多信息,请查看这些优秀的站外资源:
•
书本
Git Community Book
(Scott Chacon
著
)
•
Git
维基百科
•
Git
手册页面
•
GitCasts
(Git
教程视频
)
4
参与
参与
感谢你对
Android
的喜爱。这里有几个方法能够让你介入并帮助我们改善
Android
。你可以在
Overview
页面看到
Android
项目的背景和我们的目标。
报告错误
帮助我们改善
Android
一个最简单而且很有效的方法就是提出
Bug
。你可以查看
Reporting Bugs
页面获取更多信息。
请注意我们并不能保证特定的
bug
会在特定的版本中解决。当你提交
bug
之后你可以在
Life of a Bug
查看
bug
状况。
开发
APP
我们创造
Android
让所有开发者能够在开放平台分发应用給用户。改善
Android
最好的一个方式就是创造一个用户喜爱的酷炫
APP
。
想知道怎么开始,可以查看
developer.android.com
。这个网页将提供指导信息和工具,再使用
SDK
,就可以编写兼容各种
Android
设备的应用。
奉献代码
源码才是王道。我们很喜爱查看你提交的更改,所以请将源码拷贝下来,选择一个
bug
或者功能特性,然后开始编写。注意,你提交的补丁越小越定向,将越有益于我们查看。
如果你想准备开始,可以通过左边的链接查看
Life of a Patch
,还有
git
,
repo
或其他工具。你也可以查看我们的
Gerrit server
上贡献者的所有活动。如果你需要帮助,可以加入我们的
讨论组
。
补丁的生命周期
Android
开源项目(
AOSP
)使用一个基于
WEB
编码的查看工具,叫做
Gerrit
。下方的流程图说明一个补丁被创建之后的详细发展状态。虽然它看似很复杂,但它主要的步骤都会在一
个
WEB
应用中呈现。
想要知道开始使用
gerrit
和
git
的详细说明,请查看
Submitting Patches
页面。
提交补丁
这个页面将描述提交补丁到
AOSP
的全过程,包括校验和
Gerrit
追踪更改。
前提条件
•
在按照说明学习本页面内容之前,你需要
初始化构建环境
,
下载源码
,
创建密码
和按照密码生成页面的说明学习。
•
可以在
developing
章节查看
Repo
和
Git
的详细信息。
•
可以在
Project roles
章节查看你可以在开源社区扮演的各种角色信息。
•
如果你打算在
Android
平台贡献代码,应该先阅读
AOSP
的权限声明信息
。
•
注意更改一些使用
Android
的上游项目,你应该给这个项目创建一个目录,像
Upstream Projects
中所说的目录。
贡献者
与服务器进行身份验证
在你上传内容到
Gerrit
的时候,你需要
创建一个与服务器认证的密码
。按照
password generator
页面的说明。你只要在第一次的使用的时候这样做。查看
Using Authentication
补充说
明。
从一个
Repo
分支开始
在你有意向更改的地方,可以在相关联的
git
库中新建一个分支:
$ repo start NAME .
你可以在同一个库同一时间新建几个独立的分支。这个分支的名字是在你本地的工作空间,不包含在
gerrit
或者最终的源码分支树中。
更改
一但你更改了源码里面的文件(请验证它们),在本地库中
commit
这个改变:
$ git add -A
$ git commit -s
在
commit
的消息中,写上你更改信息的详细描述。这个描述信息将会
push
到公共的
AOSP
库,所以请按照我们的指导来写更改列表的描述信息:
•
开始是一行摘要(最多
60
字),接着空一行。这样的格式在
git
和
gerrit
中用于各种显示。
``` short description on first line
more detailed description of your patch, which is likely to take up multiple lines. ```
•
这个描述信息应该着重说明解决了什么问题,怎么解决的。第二部分尽管是值得满意的,但是实现新功能的时候还是比较随意的。
•
写入一些简短的假定或者背景信息,这些内容可能对明年致力于这个功能的奉献者很重要。
在执行
repo init
后得到的独特的
change ID
,名称和邮箱将会自动添加到你的
commit
信息中。
上传到
gerrit
一旦
commit
你的更改到个人历史,就可以上传到
gerrit
。
$ repo upload
如果你在同一个库中选择了多个分支,你将会得到提示,让你选择一个分支上传。
上传成功之后,
repo
将会给你提供一个
Gerrit
新页面的
URL
。预览这个链接并在评审服务器上查看你的补丁,添加评论,或者给你的补丁请求特定的评审员。
上传一个代替的补丁
假如一个评审员已经看了你的补丁,并且要求你做一些小的更改。你可以通过
git
修改
commit
信息,这样将会在
gerrit
中生成一个新的补丁,但是使用的是原先那个
change ID
。
注意,如果你在上传补丁之前添加了其他
commits
,你将需要手动移动你的
git HEAD
。
$ git add -A
$ git commit --amend
当你上传了修改的补丁,它将在
gerrit
和本地
git
历史中代替之前的。
解决同步冲突
如果提交到源码中的其他补丁和你的有冲突,你将需要在源码库新
HEAD
的顶部
rebase
(重新定义分支版本库状态)你的补丁。一个简单的方法就是运行:
$ repo sync
这个命令将会从服务器先
fetches
最新的源码,然后会试图自动
rebase HEAD
到新的远程
HEAD
上面。
如果自动
rebase
没有成功,你必须手动执行
rebase
。
$ repo rebase
使用
git mergetool
可能帮助你处理
rebase
冲突。一旦你成功地合并冲突文件,
$ git rebase --continue
手动或者自动
rebase
完成之后,运行
repo upload
来提交你
rebase
补丁。
提交被批准之后
提交的内容在通过检查和验证过程之后,
Gerrit
会自动的
merges
这个更改到公共的库中。其他用户可以运行
repo sync
来
pull
这个更新到自己的本地。
检查员和审核者
检查一个更改
如果你被分配成这个更改内容的批准者,你需要决定接下来的内容:
•
这个更改是不是符合项目一开始的目的?
•
这个更改是不是在现存的构造中有效?
•
这个更改引入的设计缺陷是否会在将来出现问题?
•
这个更改是否遵循这个项目中已建立的最佳实践?
•
这个更改是执行描述方法的好方式?
•
这个更改是否引入任何安全或不稳定的风险?
如果你准许了这个改变,请在
Gerrit
中用
LGTM
(
Look Good to ME
)标记它。
审核更改
如果你被分配成这个更改内容的审核者,你需要做接下来的内容:
•
使用其中一种下载命令将这个更改
Patch
到自己的本地客户端。
•
构建和测试这个更改。
•
在
Gerrit
中,使用发布评论的方式来标记这个
commit
,用
“Verified”
或者
“Fails”
,并且添加一个消息来解释哪些问题是经过鉴定的。
从
Gerrit
下载更改的内容
已经审核和合并之后的提交将会在下一次
repo sync
的时候被下载。如果你希望下载一个特定的没有经过检验的更改,执行:
$ repo download TARGET CHANGE
这个
TARGET
就是你下载的更改将要放到本地目录的位置,
CHANGE
就是在
Gerrit
中的更改列表的数字。想要知道更多信息,请查看
Repo reference
。
怎么样才能成为一个审核者或者检验者?
简单来说,需要对一个或者多个
Android
项目贡献高质量代码。想要了解更多关于
Android
开源社区的不同角色和都有谁参与的信息,可以查看
Project Roles
。
Diffs
和评论
在
Gerrit
中点击一个更改的
Id number
或者
Subject
可以打开这个更改的详细信息。想知道现有的代码和更新的代码之间的差异,可以点击文件名下的
Side-by-side diffs
。
添加评论
在开源社区的任何一个人都可以使用
Gerrit
来给提交的源码添加内联的评论。一个好的评论将会关联行或者部分在
Gerrit
中的附加代码。这或许是关于如何改进一行代码,简短的或者
建设性的意见,或者,这个也许是为什么作者这样写代码就有意义的解释。
想要添加内联评论,双击代码中相关联的行,并且在下一个打开的窗口写上你的评论。你点击保存之后,只有你可以看到你的评论。
想要发布你的评论,让其他
Gerrit
使用者看到评论,点击
Publish Comments
按钮。你的评论内容将会通过
发送给这个更改的所有当事人,包括更改的拥有者,补丁更新者(如果
和拥有者不是同一个人),还有所有当前的检查者。
Upstream
项目
Android
使用很多其他开源项目,比如,
Linux
内核和
WebKit
,像在
Codelines
,
Branches
,
Releases
中描述的那样。在
external/
下的大多数项目,更改应该被
upstream
,然后
Android
维护者通知新的
upstream
版本将包括这些更改。让我们跟踪一个新的
upstream
版本,可能对上传补丁有好处。但是如果这些项目被广泛使用,像下面提到的大多数项目一样,
将很难做出改变,对于这样的项目,我们倾向于每次发布版本都升级。
一个有趣的特殊情况是仿生(
bionic
)。很多代码都是来源于
BSD
,所以除非改变的是新的仿生代码,我们宁愿看到一个
upstream
修复,然后从
适当的
BSD
上
pull
一个完整的新的文
件(很可悲的是我们同时有很多不同的
BSD
,但是我们希望在未来解决这个问题,并且进入一个我们更密切跟踪
upstream
的位置)。
ICU4C
在
external/icu4c
目录下,
ICU4C
项目的所有改变,都应该在
icu-project.org/
里被
upstream
。查看
Submitting ICU Bugs and Feature Requests
获取更多信息。
LLVM/Clang/Compiler-rt
LLVM-related
项目(
external/clang, external/compiler-rt, external/llvm
)的所有更改都应该在
llvm.org/
upstream
。
mksh
external/mksh
目录下,
MirBSD Korn Shell
项目的所有更改要么发送
到
mirbsd.org
(不需要订阅提交)域名下的
miros-mksh
,要么是
Launchpad
来进行
upstream
。
OpenSSL
external/openssl
目录下的
OpenSSL
项目的所有更改都应该在
openssl.org
中
upstream
。
V8
external/v8
目录下
V8
项目的所有更改都应该提交到
code.google.com/p/v8
中
upstream
。进入
Contributing to V8
查看详情。
WebKit
external/webkit
目录下
WebKit
项目的所有更改都应该在
webkit.org
中
upstream
。这个过程首先是提出一个
Webkit bug
。这个
bug
应该是使用
Android
平台和系统,并且这个
bug
仅仅是
针对于
Android
的。当添加了修复提议并有测试,
Bugs
将更容易引起检查员的注意。查看
Contributing Code to WebKit
获取更多信息。
zlib
external/zlib
目录下
zlib
项目的所有更改狗应该在
zlib.net
中
upstream
。
Bug
的生命周期
Android
开源项目维护了一个公共的
issue
跟踪管理,在这里你可以报告
bugs
并给核心
Android
软件请求功能(可以到
Reporting Bugs
页面查看
issure
跟踪器的详细信息)。提交
Bugs
是一件很棒的事情(谢谢!),但是当你提交完之后会发生什么呢?这个页面就是描述
Bug
的生命周期。
请注意
:
Android
开源项目(
AOSP
)
issue
跟踪器仅仅是针对
bugs
和与请求核心软件相关的功能,同时,它也是开源社区的一个技术工具。
这不是一个客户支持论坛。你可以在
的
Nexus
帮助页面
得到
Nexus
设备的支持信息。其他设备的话,可以找设备厂商或者设备销售者。
寻找
应用的帮助可以到
的支持页面
。第三方应用的帮助可以找这个应用的开发者,比如,通过
Google Play
提供的联系方式。
下面是
bug
的生命周期,简短的概括:
1.
bug
被提出后,就会在
New
状态。
2.
AOSP
的维护者定期检查并且将
bug
分类。
Bugs
将被分为四个
“buckets”
中的其中一个:
New
,
Open
,
No-Action
,和
Resolved
。
3.
每一个
bucket
都会包括一些状态用来提供
issue
生命期的更多信息。
4.
Resoloves
状态下的
Bug
最终会发布在未来版本的
Android
软件中。
Bucket
详情
这里是每个
bucket
的一些额外的信息,它意味着什么,以及它是怎么处理的。
New
状态
New
状态的
issue
包括了没有采取行动的
bug
的报告。这两个状态是:
•
New
:
这个
bug
报告还没有被分类(就是还没有被
AOSP
维护者检查)。
•
NeedsInfo
:
提交的
bug
要有足够的信息来采取行动(给维护者)。在分类之前,提交
bug
的用户需要提供额外的细节信息。如果过了很长时间,新的信息还没有提供,这个
bug
可能默认会关闭,变成
No-Action
状态。
Open
状态
这个状态的
bugs
包括需要采取行动的,但仍未解决,在等待修改的源码。
•
未分配:
这个
bug
报告已经被认为是一个有充分详情的正当的
issue
报告,但是它还没有被分配给
AOSP
奉献者解决。
•
已分配:
像未分配状态一样,但是这个
bug
实际上已经被分配给一个特定的奉献者来修改。
通常情况下,一个给定的
bug
开始是未分配状态的,直到有人打算解决它,此时它就会变成分配状态。然而,请注意这并不是绝对的,一个
bug
从未分配状态到解决状态也不奇怪。
一般而言,如果这个
bug
是
Open
状态的其中一种,
AOSP
团队已经认为它是一个合理的
issue
,并且这个
bug
将会接受到高质量的奉献修复。但是,不能保证及时修复到任何特定的发
布版本中。
No-Action
状态
这个状态下的
bugs
因为这样或那样的原因决定不在采取任何行动。
•
Spam
:
一些好心的人提供的不错的建议,但是很遗憾,这个不是我们需要的。
•
Duplicate
:
issue
跟踪器中已经有一个相同的问题了。任何目前的操作都会更新在那个报告中。
•
Unreproducible
:
一个
AOSP
奉献者试图重现所描述的行为,但是没有重现出来。这个有时意味着
bug
虽然合理但是不常见或者很难重现,有时意味着这个
bug
已经在之后的版本
中修复了。
•
Obsolete
:
和
Unreproducible
状态相似,但是合理确定的是这个
bug
在提交的那个版本中存在,但已经在之后的版本中解决了。
•
WorkingAsIntended
:
AOSP
维护者已经确定描述的行为不是
bug
,但是是一个期望的行为。这种状态通常也被称为
WAI
。
•
Declined
:
这个像
WorkingAsIntended
一样,除了
WorkingAsIntended
通常是功能请求,不是
bugs
。这个意味着
AOSP
维护者决定这个请求不在
Android
中实现。
•
NotEnoughInformation
:
这个报告没有足够的信息让维护者采取行动。
•
UserError
:
这个报告结果是用户使用
Android
的时候自己造成了错误。例如,输入错误的密码导致无法正常连接服务器。
•
WrongForum
:
AOSP
无法处理个错误,通常来说是因为这个
bug
是定制的设备或者外部的应用程序导致的。
•
Question
:
有人误以为
issue
跟踪是一个帮助论坛。
Resolved
状态
这个状态的
bug
包括已经采取行动的,并且现在被认为是解决了的。
•
Released
:
这个
bug
已经修复了并且发布在正式的版本中。在设置这个状态的同时,我们也会尽力发布一个适当的说明表示这个
bug
是在哪个版本中解决的。
•
FutureRelease
:
这个
bug
在源码中已经解决(或者功能已经实现),但是还没有发布在正式的版本中。
其他特性
上面提到的状态和生命周期是我们通常跟踪软件的方式。然而,
Android
包含了很多软件,相应的得到大量的
bugs
。因此,一些
bugs
并没有经过正常流程中的所有的状态。我们会尽
力让系统保持更新,但是我们倾向于周期性的进行
bug
清理,同时检查数据库并更新。
提交
Bugs
感谢你对
Android
的喜爱。帮助我们改善
Android
的最好方式就是告诉我们你发现关于它的任何问题。
报告问题
注意:安全漏洞的问题,请查看
Reporting Security Issues
。如果你发现一个安全漏洞,
请不要使用下面的形式
。使用一个普通的形式,让大家都可以看到你的报告,这样能够在
bug
修复之前让其他用户不再冒险。还有,请发送
到
security@android.com
描述详情。
这里将讲述
非安全
问题的
bug
:
•
搜索你的
bug
,看看是否已经有人报告了。记得要搜索全部
issue
,不仅仅是
open
状态下的,因为这个
issue
可能已经报告过了并且已经关闭了。可以通过星星的数量分类可以找
到最受欢迎的结果。
•
如果你发现你的问题很重要,请标记它。这样就可以让我们知道这个
bug
修复的重要性。
•
如果没有人报告这个
bug
,你就可以提交这个
bug
。你可以使用下面的其中一种模版:
•
设备中的
bug
-
如果你是使用你自己的设备的用户,请使用这种。
•
软件中的
bug
-
如果你是在开发一个
APP
的过程中遇到的,请使用这种。
•
功能请求
-
如果你想在将来的版本中看到这个功能,请使用这种。
请记住
issue
跟踪器不是一个用户帮助论坛。这是一个待定的技术任务列表,以及和这些任务相关的信息,还有这些任务的进展信息,包括哪些任务可能在短期内有进展。
这个
issue
跟踪器紧紧专注于
Android
开源项目。零售设备的问题需要通过这些设备的支持渠道来报告,尤其是和
Nexus
不同的设备。开发者的应用程序的问题并不是
AOSP
需要报告
的部分;这个也是
应用的状况。
请注意我们不能保证特定的
bug
将会在特定的版本中解决。查看
Life of a Bug
可以知道提交
bug
之后的情况。
一般而言,请尽可能的提交多一点的的
bug
信息,仅仅用一行内容告诉我们这里有问题是没用的,这样维护者很可能不采取任何行动就把它关闭了。你提交的详情越多,你的问题可能
更好的解决。下面介绍一些好的
bug
提交报告和劣质的报告。
劣质的报告
标题:当运行
Eclipse
的时候,错误消息提示
Internal Error
,并且需要打开
.log
查看详情。重现步骤:
Object o = null
的时候发生,变成
Object o
的时候不发生。预期的结果:我没有
获取到错误信息
-- Object o = null
不产生作用。观察结果:查看上文。
这个一个劣质的报告因为没有提供任何上下文相关的信息。这个是
ART
运行时的问题?
framework
的问题?
或者其他问题?这个也没有提供任何关于重现错误的代码或者线索。换句
话说,这个
bug
报告没有提供足够的信息让维护者来采取行动,所以它将被忽略。
优质的报告
标题:执行到
Object o = null
的时候,引起
Eclipse
的
Internal Error bug
,使用的
Eclipse
版本
3.3.1.1
,
m37a android
,代码如下:
package com.saville.android;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class TestObjectNull extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
Object o = null;
o = "hi";
Log.v(TAG, "o=" + o);
}
static final String TAG = "TestObjectNull";
}
Eclipse
表明是
Internal Error
,并且在
.log
中可以查看更多信息,然后询问是否退出工作台。在
setContentView(R.layout.main)
这里设置一个断点,然后单步执行
Object o = null
就会发生
错误。如果我把它变成
Object o
就没什么问题。
.log
文件的最后一行是:
!ENTRY org.eclipse.core.jobs 4 2 2008-01-01 13:04:15.825
!MESSAGE An internal error occurred during: "has children update".
!STACK 0
java.lang.InternalError: Invalid signature: "<null>"
at
org.eclipse.jdi.internal.TypeImpl.signatureToTag(TypeImpl.java:307)
at
org.eclipse.jdi.internal.LocalVariableImpl.tag(LocalVariableImpl.java:185)
at
org.eclipse.jdi.internal.StackFrameImpl.getValues(StackFrameImpl.java:128)
at
org.eclipse.jdi.internal.StackFrameImpl.getValue(StackFrameImpl.java:73)
at
org.eclipse.jdt.internal.debug.core.model.JDILocalVariable.retrieveValue(JDILocalVariable.java:57)
at
org.eclipse.jdt.internal.debug.core.model.JDIVariable.getCurrentValue(JDIVariable.java:66)
at
org.eclipse.jdt.internal.debug.core.model.JDIVariable.getValue(JDIVariable.java:88)
at
org.eclipse.debug.internal.ui.model.elements.VariableContentProvider.hasChildren(VariableContentProvider.java:62)
at
org.eclipse.jdt.internal.debug.ui.variables.JavaVariableContentProvider.hasChildren(JavaVariableContentProvider.java:73)
at
org.eclipse.debug.internal.ui.model.elements.ElementContentProvider.updateHasChildren(ElementContentProvider.java:223)
at
org.eclipse.debug.internal.ui.model.elements.ElementContentProvider$3.run(ElementContentProvider.java:200)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
关于代码风格的指导
以下的规则并不是普通的指导方针或者我们的推荐,而是严格的规范。不遵循这些风格而构建出来的
Android
软件将不会被接受。
目前,并不是所有的代码都符合规范,但是以后的代码应该向规范靠拢。
Java
语法规则
我们遵循标准的
Java
编码规范,此外我们加入了一些新的规范
不能忽视异常
有时候,开发者会倾向于编写完全忽视了异常的代码,就像下面这样:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatExceptio e) { }
}
开发者绝不能像这样。当你觉得你的代码不会出现这个错误,或者处理这个错误并不重要的时候,像上面的代码那样忽略了异常处理就相当于在你的代码中给以后接手的开发者埋下了
地雷,他们总有一天会在这里遇到问题。你必须将代码中所有的异常用一种规范化的方式处理好,具体的处理方式取决于情况的不同。
不管什么时候,如果代码中存在空的捕获语句,开发者应当感到毛骨悚然。不论如何,在捕获语句中,必然存在应当执行的操作,至少你应该多考虑一下。在
Java
中,这种恐慌感是
无法逃避的。
-
James Gosling
可接受的处理方式(可以参照个人的喜好选择)有:
•
由方法的调用者抛出异常
void setServerPort(String value) throws NumberFormatException {
serverPort = Integer.parseInt(value);
}
•
抛出一个适合你当前抽象层次的新异常
void setServerPort(String value) throws ConfigurationException {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
throws new ConfigurationException("Port " + value + " is not valid.");
}
•
通过在
catch
代码块中使用一个合适的值替代异常值来处理异常
/**
设置端口号
,
当
value
是一个无效数字时
,
使用
80
替代
*/
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
serverPort = 80; //
服务器的默认端口
}
}
•
捕获异常并抛出一个新的
运行时异常
。这种方式存在风险:只有当你确认出现这种错误的时,令程序崩溃是最合适的处理方式,才能采用该方式。
/**
设置端口号
,
如果
value
是一个无效值
,
程序中断。
*/
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
throws new RuntimeException("port " + value + " is invalid, ", e);
}
}
请注意,原来的异常传递给了
RuntimeException
的构造器。如果你的代码必须在
Java 1.3
以下版本编译,你需要省略掉异常发生的原因。
•
最后一招:如果你认为忽略屌异常处理是最合适的,并且对此相当有信心,那么你可以忽略异常。但是你必须在注释中说明为什么:
/**
如果
value
是无效的数字
,
将会使用原来的端口号。
*/
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
//
文档中会注明该方法将忽略掉用户输入的无效值
// serverPort
将不会发生改变
}
}
不要捕获一般性异常(
Generic Exception
)
有些时候,为了偷懒,开发者将会像下面这样捕获异常并作出处理:
try {
someComplicatedIOFunction(); //
可能抛出
IOException
someComplicatedParsingFunction(); //
可能抛出
ParsingException
someComplicatedSecurityFunction(); //
可能抛出
SecurityException
// phew, made it all the way
} catch (Exception e) { //
我希望捕获所有的异常
handleError(); //
一个普通的
handler
}
你不能这样做。几乎所有情况下都不适合捕获一般性异常,因为其中包括还包括了错误异常,这是相当危险的。这意味着你并不期待的异常(包括运行时异常,就像
ClassCastException
)最后却在应用级别的错误处理中被捕获。它掩盖了处理失败的代码,这意味着如果有人在您正在调用的代码中添加了一个新类型的异常,编译器无法告诉你需要以
不同的方式处理该错误。并且在几乎全部情况下,你都不应该以同种方式处理不同种类的异常。
这一规则有极少数例外:在某些测试代码和顶级代码中,你希望捕捉所有类型的异常(以防止他们在界面中显示或者继续进行批处理作业)。在这种情况下,你需要捕获一般性异常并
合适地处理错误。这么做之前你需要谨慎考虑,然后在注释中解释为什么在这里这么做是安全的。
替代捕获一般性异常的选项:
•
在同一个
try
语句之后设置多个分离的
catch
块来处理不同的异常。这个方法可能不太方便,但是要比捕获所有异常要好不少。需要注意的是,
catch
块中应尽量避免代码重复过
多。
•
通过多个
try
语句重构代码以使错误处理的粒度更细小,把
IO
从
parsing
分离出来,在不同的情况中单独处理错误。
•
重新抛出异常。很多情况下,你不需要在当前层次下捕获异常,此时只需在方法中抛出异常即可。
记住:异常是你的朋友!当编译器告诉你还有异常没有被捕获的时候,不要皱眉。此时应该微笑:编译器令你能够更加轻松地在自己的代码中捕获运行时异常,是值得高兴的事。
不要使用终结器(
Finalizers
)
终结器是一种可以在对象被垃圾回收器回收时,执行一大块代码的方法。
优点:方便清理,特别是针对外部资源的时候。
缺点:并不能保证终结器什么时候会被调用,甚至有时候它根本不会被调用。
判定:我们不应使用终结器。在大多数情况下,你可以在终结器中执行你需要的操作,并且能实现良好的异常处理。如果你一定需要它,定义一个
close()
方法(或者是
like
)并注明什
么时候它应该被调用。我们可以把
InputStream
当做一个例子来说明一下。在这种情况下,它并不是一定要在终结器中输出日志信息,但是,如果并不希望输出太多日志信息的话,在
终结器中输出小段日志信息是很合适的方法。
完全限定引用
当你希望使用
foo
包中的
Bar
类的时候,你又两种方法实现:
1.
import foo.*;
2.
import foo.Bar;
第一种方式优点:可能会减少
import
语句的数量。
第二种方式优点:把要使用的类描述出来了,使得代码在维护时更具可读性。
判定:引用
Android
代码的时候使用第二种形式。
Java
标准库(
java.util.*
,
java.io.*
等)和单元测试代码(
junit.framework.*
)是例外。
Java
资源库规范
使用
Android
中的
Java
库和工具会带来许多便利。有些情况下,这种便利性在一些重要方面发生了改变,因为旧的代码可能使用的是已经弃用的模式或者资源库。使用这样的代码时,
直接使用已有的模式是没问题的。但是当创建新的组件的时候,不要使用弃用的资源库。
Java
样式规范
使用
Javadoc
标准注释
每个文件都会在其顶部放置版权声明。然后是包的声明和引用语句,用空行把不同作用的语句块分离开来。接下来是类或者接口的声明。在
Javadoc
标准注释中,要描述类或者接口的
作用。
/*
* Copyright (C) 2013 The Android Open Source 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.
*/
package com.android.internal.foo;
import android.os.Blah;
import android.view.Yada;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Does X and Y and provides an abstraction for Z.
*/
public class Foo {
...
}
对于每个类和有价值的公共方法,你都应该为之书写一个
Javadoc
注释,该注释至少包含一句关于类或方法作用的描述。并且这个描述应该以第三人称描述性谓词开头。
示例:
/** Returns the correctly rounded positive square root of a double value. */
static double sqrt(double a) {
...
}
或者:
/**
* Constructs a new String by converting the specified array of
* bytes using the platform's default character encoding.
*/
public String(byte[] bytes)
你并不需要为没价值的
get
或者
set
方法书写
Javadoc
,比如,对于
setFoo()
方法,你在
Javadoc
中只能说设置了
Foo
的值。如果该方法所做的事情更加复杂(比如强制约束或者有一个
重要的副作用),那你应该写一个
Javadoc
。假设之前的例子中,
Foo
这个属性的意思并不明确,那就该添加一个
Javadoc
。
你所写的每一个方法,不论是公有的还是其他的,都将受益于
Javadoc
。而公共函数是
API
的一部分,所以需要
Javadoc
。
Android
目前并不强制开发者使用特定的
Javadoc
书写风格,但是你应该遵循
How to Write Doc Comments for the Javadoc Tool
中的规范。
编写短小的方法(
Short Method
)
在可行的范围内,方法应该尽量向小型化和集中化靠拢。但是,也要认识到,有些情况下较长的方法更加合适,所以对于方法的长度并不做硬性要求。如果某个方法的代码超出了
40
行,那么应该考虑一下是否能将它分解为小方法并且不影响到程序的结构。
在标准的地方定义字段
字段应该在文件顶部定义,或者在即将使用它们的方法前定义。
限制变量的范围
局部变量的存在范围应该尽可能地低。这样做将会增加代码的可读性和可维护性,并且还能降低出错的可能性。在嵌套的代码块中,每个变量应该在能够包含所有使用该变量的语句的
最小的代码块中声明。
局部变量应该在第一次被使用时声明。几乎每个局部变量的声明都应该包括合理的初始化,如果你没有没办法在此处获得足够的信息去初始化这个变量,那么你应该将声明推迟到你获
得足够信息的地方。
这个规则的一个例外就是
try-catch
语句。如果一个变量初始化的时候,其初始值是一个抛出已检查异常的方法的返回值,它就必须在
try
语句内初始化。如果这个变量必须在
try
块之
外被使用,那么它就要在
try
块之外声明,尽管在那里它并没有被合理地初始化:
//
实例化类
cl
,
表示某种集合
Set s = null;
try {
s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
throw new IllegalArgumentException(cl + " not instantiable");
}
//
运用这个集合
s.addAll(Arrays.asList(args));
但即使是这种情况也能通过把
try-catch
语句封装在一个方法中来避免:
Set createSet(Class cl) {
//
实例化的类
cl
,
表示某种集合
try {
return (Set) cl.newInstance();
} catch(IllegalAccessException e) {
throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
throw new IllegalArgumentException(cl + " not instantiable");
}
}
...
//
运用这个集合
Set s = createSet(cl);
s.addAll(Arrays.asList(args));
对于循环变量,除非有令人信服的理由,否则应该在
for
语句中声明:
for (int i = 0; i < n; i++) {
doSomething(i);
}
其他类型的循环变量:
for (Iterator i = c.iterator(); i.hasNext(); ) {
doSomethingElse(i.next());
}
有序的引用语句
引用语句的顺序如下:
1.
Android
的引用
2.
第三方的引用
3.
java
和
javax
的引用
为了更好地符合
IDE
的设置,这些引用语句应该是这样的:
•
每个分组按字母排序,其中大写字母放在小写字母前。(比如,
Z
在
a
前面)
•
每个主要的组之间应该用空行隔开(
android, com, junit, net, org, java, javax
)
最初在顺序的风格上并没有要求。也就是说
IDE
总是在改变这些顺序,或者说使用
IDE
的开发人员不得不禁用自动引用的特性然后手动维护这些引用语句,这是相当不好的。当问及
Java
风格的时候,开发者们喜欢的风格是五花八门的。这和我们对于
“
尽量有序并且一致
”
的需求完全不同,所以我们选择了一种风格,更新了风格指南,并且让
IDE
来遵循它。我们
希望,随着用户不断使用
IDE
来编码,最终所有的引用语句都能符合这种风格。
这种风格是这样的:
•
人们希望并且往往放在顶部的引用语句(
android
)
•
人们希望并且往往放在底部的引用语句(
java
)
•
人们要使用这种风格很简单
•
IDE
能够遵循这种风格
静态引用的使用和位置一直都存在争议。有的人喜欢把静态引用分散在已有的引用语句中,有些人则希望把它们放在其他所有引用语句的上方或者下方。此外,我们目前也没有得出一
种能够让所有
IDE
都遵循统一顺序的方法。
由于多数人认为这件事并不重要,所以你需要自行判断,并尽可能保持一致。
使用空格来缩进
我们使用
4
个空格来缩进,而不是使用
tab
键。对此感到困惑的话,请和你周围的代码保持一致。
语句换行的时候我们使用
8
个空格来缩进,包括方法的调用和赋值语句。例如,这样是正确的:
Instrument i =
someLongExpression(that, wouldNotFit, on, one, line);
下面这样则是不正确的:
Instrument i =
someLongExpression(that, wouldNotFit, on, one, line);
遵循字段命名惯例
•
非公有且非静态的字段以
m
开头
•
静态字段以
s
开头
•
其他字段以小写字母开头
•
公有的静态字段全部大写并用下划线连接
例子如下:
public class MyClass {
public static final int SOME_CONSTANT = 42;
public int publicField;
private static MyClass sSingleton;
int mPackagePrivate;
private int mPrivate;
protected int mProtected;
}
使用标准的花括号风格
花括号不单独占一行,应该放在和前面代码同一行的位置。就像下面这样:
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
我们需要在一个条件语句中使用括号。只有整个条件语句中只有一行代码,你才可以把他放在一行而不使用括号。就如下面这样是合法的:
if (condition) {
body();
}
而这样也是可行的:
if (condition) body();
不过,那这样也是可以的:
if (condition)
body(); //
不推荐这样的风格
控制行的长度
你代码的每一行的长度应该限制在
100
个字符以内。
为此我们做了很多讨论,最终决定,一行的长度应该限制在
100
个字符以内。
例外
1
:如果一个注释语句含有一个超过
100
个字符的简单命令或者是一个
URL
,那么为了方便剪切和粘贴,你可以不在意行的长度。
例外
2
:引用语句可以不管这个限制,因为人们很少在意他们。这样也能简化工具的编写。
使用标准
Java
标注(
Annotations
)
标注应该先于同一语言元素中的其他修饰符。简单的标注(如
@Override
)可以和其他语言元素在同一行中列出。如果有多个标注,或者参数化的标注,他们应该各自单独占一行并按
字母顺序排列。
Java
预定义的三种标注在
Android
中的标准用法如下:
•
@Deprecated.
当被标注的元素不鼓励使用的时候你必须使用
@Deprecated
标注,你还需要使用
Javadoc
添加
@deprecated
标记并且该标记应该用可选的名字实现。此外,请记住,
@Deprecated
方法依旧是可以执行的。
(对于以前的代码,如果有一个
Javadoc
的
@deprecated
标记,请为代码加入
@Deprecated
标注。
•
@Override.
当一个方法重写了其父类中的声明或者实现的时候,必须用
@Override
来注明。比如,如果你有一个方法有
Javadoc
的标记
@inheritdocs
,并且是从一个类(不是接
口)中派生而来的,你就必须再为方法添加
@Override
说明该方法重写了父类中的相关方法。
•
SuppressWarnings
:
@SuppressWarnings
标注应该只在无法消除警告的情况下使用。如果一个警告通过了
“
无法消除
”
的测试,那么
@SuppressWarnings
标注会被使用,以确保所有
的警告都反映了代码中的实际问题。
当必须使用
@SuppressWarnings
标注的时候,必须在其之前写一个
TODO
注释来说明
“
无法消除
”
的情况。这通常会标记出一个使用了一个比较尴尬的接口的违规类。例子如下:
// TODO: The third-party class com.third.useful.Utility.rotate() needs generics
@SuppressWarnings("generic-cast")
List<String> blix = Utility.rotate(blax);
当需要
@SuppressWarnings
标注的时候,应该重构代码以隔离标注中使用的软件元素。
熟悉首字母缩略词
在为变量、方法以及类命名的时候,最好使用首字母缩略词。这些名称将会更具可读性:
Good
Bad
XmlHttpRequest
XMLHTTPRequest
getCustomerId
getCustomerID
class Html
class Html
String url
String URL
Good
Bad
long id
long ID
不论
JDK
还是
Android
的代码库都使用了首字母缩略词,因而他们是相当一致的,因此,想使自己的代码与他们一致是几乎不可能的。请咬紧牙关,尽量熟悉首字母缩略词。
使用
TODO
注释
为代码使用
TODO
注释是暂时,短期的解决方案,或者说是够用的但是并不完美。
TODO
注释必须用大写的
TODO
开头,后面跟一个冒号:
// TODO: Remove this code after the UrlTable2 has been checked in.
或者:
// TODO: Change this to use a flag instead of a constant.
如果你的
TODO
语句是
“
在未来的某一时期做什么
”
的格式,请确保你包含了一个求具体的日期(
2005
年
11
月份)或者一个特定的事件(在所有产品开发者了解
v7
协议后删除此代
码)。
谨慎使用
Log
当日志记录是必须的时候,它对性能有显著的负面影响并且如果它不保持一定程度的简洁性的话,就会迅速失去其有效性。测试系统提供五种不同级别的日志记录:
•
Error
:这个等级的日志信息应该只在出现致命错误的时候使用,比如,有些事件会导致用户可见的结果并且如果不显示地删除数据,卸载应用,清理数据分区或者重新刷掉整个
手机(可能更糟)的时候就无法修正该结果,这个级别的信息会一直记录下来。在向统计数据的服务器提交报告的时候,说明
ERROR
级别的日志中的情况通常是一种好的选
择。
•
Warning
:这个等级的日志信息应该在事情比较严重或者出现预期之外的结果时使用,比如,有些事件会导致用户可见的结果,但是通过一些显示的动作,就像是等待或重启应用
程序的应用甚至于下载新版的应用程序或者重新启动设备,可以在不丢失数据的情况下恢复。这个级别的信息会一直记录下来。在向统计信息的服务器报告的时候,说明
WARNING
级别的日志信息也是会考虑的。
•
INFORMATIVE
:这一级别的日志应当记录的是大多数人会感兴趣的信息。比如,当发现某种情况会造成广泛的影响时,尽管它不一定是错误,也应该记录。这种情况只应该由
一个被认为在该域中是最具权威性(避免由非权威的组件做重复记录)的模块记录。始终记录该级别的日志信息。
•
DEBUG
:这一级别的日志信息应该用于进一步说明在设备上发生了什么和调查及调试异常行为相关的事件。你应该只有在需要收集关于组件的足够信息的时候进行记录。如果你
的调试日志是主要的日志信息,那你可能需要使用
verbose
日志记录。这一级别的日志应当记录,即时是在发行版中也应当用
if(LOCAL_LOG)
或者
if (LOCAL_LOGD)
代码块中
来包含该日志。而在
LOCAL_LOG[D]
中则定义你的类或者子组件,故而要禁用所有这类记录是有可能的。在
if(LOCAL_LOG)
块中不应当含有执行的逻辑,所有为日志而构建的
字符串也应该放在
if(LOCAL_LOG)
块中。如果日志调用会导致字符串的构建发生在
if(LOCAL_LOG)
块之外,那么不应该把日志调用分散到函数调用中。还有些代码仍然使用
if(localLOGV)
,这也是可接受的,尽管这个名称并不规范。
•
VERBOSE
:这个级别的日志用于记录其他所有的信息,只会在调试版本中记录,并且应当包含在
if(LOCAL_LOGV)
块中。故而它可以在默认情况下编译,任何因此构建的字符
串在应当在
if(LOCAL_LOGV)
块中出现,并且在发行版中将会被剥离出来。
注意:
•
在给定的模块中,除了
VERBOSE
级别以外,一个错误应该尽可能只报告一次
:在模块内的函数调用链,只有最内层的函数应当返回错误信息,并且同一模块内的调用者只应添
加一些有助于分离问题的日志信息。
•
在一连串模块中,除了
VERBOSE
级别以外,当底层模块检测到的无效数据来自较高模块,并且只有在日志提供了调用者无法使用的信息的时候,低级别模块将记录这种情况到
DEBUG
日志。具体来说,没有必要在抛出异常的,或者被记录的信息被包含在错误信息中的时候,记录当时的情况(异常中应该会包括所有相关的信息)。这在框架和应用的
交互间尤为重要,并且由第三方应用程序造成的情况能够由框架合理处理的时候,不应该触发高于
DEBUG
级别的记录。唯一能触发
INFORMATIVE
或者更高级别记录的情况应
该是当模块或者应用在其本身的自别检测到错误,或者错误来自较低级别的时候。
•
当有些日志记录可能会发生多次的时候,实施一些限制速率的机制来防止重复输出很多与副本相同(或者很相似)的日志信息是一个好方法。
•
失去网络连接被一致认为且期望是不应该无理由记录的。在
app
内失去网络连接会出现的后果应当在
DEBUG
或者
VERBOSE
级别记录(根据后果是否足够严重并且超出预期的
情况足够被记录在发行版中)。
•
在一个文件系统中,一个可以使用或者代表第三方的完整文件系统不应该输出高于
INFORMAL
的日志。
•
来自不信任源的无效数据(包括任何共享设备上的文件,或者通过网络连接取得的数据)被检测出无效的时候,我们认为且应当不触发任何高于
DEBUG
级别的日志记录。(甚
至应该尽可能地限制日志记录)
•
在心中记住,当对
String
对象使用
+
连接符的时候,会隐式地创建一个默认大小(
16
个字符)的
StringBuilder
对象,而且可能会有其他的临时
String
对象。比如,显示创建
StringBuilder
的花销并不使用默认的
‘+’
操作符要大(而且事实上更加高效)。也请记住,即时没有读日志信息,调用
Log.v()
的代码,包括字符串的构建,是会被编译并且运行在
发行版本中的。
•
任何用于给其他人看并且在发行版中也可用的日志,应当尽可能地简洁,并且应当是合理易懂的。这包括到
DEBUG
为止的全部日志。
•
如果可能的话,有意义的的日志应该保持在单行内。单行的长度在
80
到
100
个字符内是完全可以被接受的,但是长度在
130
到
160
各字符也是可以接受的(包括标签的长度),
只是应当尽量避免。
•
报告成功的日志绝对不能使用高于
VERBOSE
级别的日志。
•
临时记录用于诊断一个很难重现的问题,而且应该保持在
DEBUG
或者
VERBOSE
级别,并且应当封闭在
if
块之中以允许其在编译期间能够被禁用。
•
对于在日志中泄露的安全信息要小心。私有信息应该尽量避免。受保护的内容是必须避免的。在编写框架代码的时候这是非常重要的,因为它并不会预先知道什么是私有信息或
者受保护的信息。
•
不要使用
System.out.println()
(或者
printf()
原生代码)。
System.out
和
System.err
可以重定向到
/dev/null
,所以你的打印语句不会有可见的影响。然而,所有银
这些调用而构建的字符串仍然会被输出。
•
关于日志的最好的规则就是,你的日志不会把其他日志推到缓冲区中,正如其他日志不会这样对你的日志一样。
保持一致
我们的部分想法:保持一致。如果你在编辑代码,请花一点时间去观察一下周围人的代码以确定你的风格。如果他们在
if
语句的周围使用空格,你也应该这样。如果他们的注释是包
含在用星号构成的方块里,你也要把注释放在星号构成的方块里。
需要风格指南的关键是有一个共同的代码词汇表,于是人们可以专注于你所说的内容,而不是你说话的方式。我们提出了整体的风格规范,所以人们知道这个专业词汇表。但是局部的
风格也是很重要的,如果你在文件中加入的代码看起来和周围代码明显不同,那么读者读到这里的时候,这些代码会使他们的节奏被打断,这应当尽量避免。
Javatests
风格规范
遵循测试方法的命名便捷性
当为测试方法命名的时候,你可以使用下划线从特定的测试情况中分离出要测试的东西。这种风格可以更好地看出是在什么情况下进行测试。
例如:
testMethod_specificCase1 testMethod_specificCase2
void testIsDistinguishable_protanopia() {
ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}
更多信息请访问
http://wiki.jikexueyuan.com/project/android-source/




