暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

android 开源项目指南

yBmZlQzJ 2024-01-15
1200

前言

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

的源代码树在

Google

托管的

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

中配置你的真实姓名和

email

地址。要使用

Gerrit

代码审查工具,你可能会需要一个注册过

Google

账户的邮箱地址。请确保你能通过这个邮箱地址收到消

息。这将作为你贡献代码的署名出现。

成功初始化的时候会显示这样的消息状态-

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

按钮。你的评论内容将会通过

email

发送给这个更改的所有当事人,包括更改的拥有者,补丁更新者(如果

和拥有者不是同一个人),还有所有当前的检查者。

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

项目的所有更改要么发送

email

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

和与请求核心软件相关的功能,同时,它也是开源社区的一个技术工具。

这不是一个客户支持论坛。你可以在

Google

Nexus

帮助页面

得到

Nexus

设备的支持信息。其他设备的话,可以找设备厂商或者设备销售者。

寻找

Google

应用的帮助可以到

Google

的支持页面

。第三方应用的帮助可以找这个应用的开发者,比如,通过

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

修复之前让其他用户不再冒险。还有,请发送

email

security@android.com

描述详情。

这里将讲述

非安全

问题的

bug

搜索你的

bug

,看看是否已经有人报告了。记得要搜索全部

issue

,不仅仅是

open

状态下的,因为这个

issue

可能已经报告过了并且已经关闭了。可以通过星星的数量分类可以找

到最受欢迎的结果。

如果你发现你的问题很重要,请标记它。这样就可以让我们知道这个

bug

修复的重要性。

如果没有人报告这个

bug

,你就可以提交这个

bug

。你可以使用下面的其中一种模版:

设备中的

bug

-

如果你是使用你自己的设备的用户,请使用这种。

软件中的

bug

-

如果你是在开发一个

APP

的过程中遇到的,请使用这种。

功能请求

-

如果你想在将来的版本中看到这个功能,请使用这种。

请记住

issue

跟踪器不是一个用户帮助论坛。这是一个待定的技术任务列表,以及和这些任务相关的信息,还有这些任务的进展信息,包括哪些任务可能在短期内有进展。

这个

issue

跟踪器紧紧专注于

Android

开源项目。零售设备的问题需要通过这些设备的支持渠道来报告,尤其是和

Nexus

不同的设备。开发者的应用程序的问题并不是

AOSP

需要报告

的部分;这个也是

Google

应用的状况。

请注意我们不能保证特定的

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/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论