先介绍下我的电脑基础环境:
1.硬件:MacBook Pro
2.系统版本:OS X EI Capitan 10.11.6
以下是官方给出的各个android版本建议对应的系统版本:
Android 6.0 (Marshmallow) - AOSP master: Ubuntu 14.04 (Trusty)
Android 2.3.x (Gingerbread) - Android 5.x (Lollipop): Ubuntu 12.04 (Precise)
Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Ubuntu 10.04 (Lucid)
Android 6.0 (Marshmallow) - AOSP master: Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
Android 5.x (Lollipop): Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat): Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple’s Developer Tools)
Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich): Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK
The master branch of Android in AOSP: Ubuntu - OpenJDK 8, Mac OS - jdk 8u45 or newer
Android 5.x (Lollipop) - Android 6.0 (Marshmallow): Ubuntu - OpenJDK 7, Mac OS - jdk-7u71-macosx-x64.dmg
Android 2.3.x (Gingerbread) - Android 4.4.x (KitKat): Ubuntu - Java JDK 6, Mac OS - Java JDK 6
Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Ubuntu - Java JDK 5
(以下内容记录的是在Mac上的搭建过程,其余系统请移步android官方文档)
直接在终端运行以下命令,即可建立一块大小为40g的分区,如果要创建其他的大小的分区,将命令中的40改为对应的数字即可。个人实测建议,这个分区尽量大一些,以我自己为例,我下载的是android-6.0 nexus5分支的源码,完成同步并编译之后大概占用了70G1
# hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg
上述命令将会生成一个以.dmg或.dmg.sparseimage为后缀的文件
如果已经创建好了这个分区,想再去更改它的大小,可以通过以下命令实现1
# hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage
2.将创建好的这个镜像挂载到系统中
在文件~/.bash_profile中配置以下内容。(如果该文件不存在,可通过touch命令先生成,然后再将内容添加)1
2
3
4
5# 挂载镜像文件
function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }
# 卸载镜像文件
function unmountAndroid() { hdiutil detach /Volumes/android; }
(如果镜像文件是以.dmg.sparseimage为后缀,则将命令中的~/android.dmg 替换为 ~/android.dmg.sparseimage)
3.下载并安装jdk
上oracle官网,对照前面所提的不同的android版本所需jdk下载安装即可
4.在appstore中安装Xcode
5.安装MacPorts
确保path环境变量中/opt/local/bin在/usr/bin之前,否则添加以下内容到~/.bash_profile1
export PATH=/opt/local/bin:$PATH
6.通过MacPorts安装make, git, 和 GPG等1
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg
7、在~/.bash_profile中配置文件限制1
2# set the number of open files to be 1024
ulimit -S -n 1024
8、配置缓存
在源码的根目录下,打开终端输入以下命令,即可配置编译运行缓存,建议大小为50~100G1
2
3$ export USE_CCACHE=1
$ export CCACHE_DIR=/<path_of_your_choice>/.ccache
$ prebuilts/misc/darwin-x86/ccache/ccache -M 50G
在.bashrc中加入内容:export USE_CCACHE=1
1.在home根目录下建立一个bin文件夹并添加到环境变量中:
$ mkdir ~/bin
$ PATH=~/bin:$PATH
2.下载repo工具
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
3.在上面创建的区分大小写的镜像中建立一个编译根目录(名字随意取):WORKING_DIRECTORY
$ mkdir WORKING_DIRECTORY
$ cd WORKING_DIRECTORY
4.配置git用户名和账号邮箱信息
$ git config –global user.name “Your Name”
$ git config –global user.email “you@example.com”
5.init源码分支1
$ repo init -u https://android.googlesource.com/platform/manifest
如果提示无法连接到 gerrit.googlesource.com,可以将源换成清华的,编辑 ~/bin/repo,把 REPO_URL 一行替换成下面的:
REPO_URL = ‘https://gerrit-google.tuna.tsinghua.edu.cn/git-repo‘
更加详细操作可点击该链接进行查看
如果想clone具体的分支,可加上-b参数,我想编译的是nexus 5,android 6.0,点击这个[链接]可查看具体的分支名,可以看到我想要的具体分支名为:android-6.0.1_r60
所以命令为:
$ repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r60
6.开始同步
在源码根目录下打开终端执行:repo sync,即可开始代码同步过程,经历的将是漫长的等待,毕竟即使个G的代码。。。
1.make clobber:清理out目录,如果每次都想重新编译的话,可执行该命令清除上次编译生成的OUT目录
2.source build/envsetup.sh:初始化编译环境
3.lunch
4.输入对应target的数字(因为我要编译的是userdebug版本 19. aosp_hammerhead-userdebug所以直接输入19即可)
5.make -j4:开始编译,至于是4个线程同时编译还是8个或者16个自行根据自己电脑的配置来决定
如果编译一切顺利,就可以实行最后一步了,就是我们常说的刷机
cd $OUT:切换到out目录
手机重启进入bootloader模式
fastboot flashall -w:执行该命令开始刷机
1.Xcode版本问题:Can not find SDK 10.6 at /Developer/SDKs/MacOSX10.6.sdk
这个问题是由于我们系统的版本比较高,所以sdk版本也比较高了,此时需要更改sdk配置
cd /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
ls //查看sdk版本(我的版本为 MacOSX10.11.sdk)
然后编辑build/core/combo/mac_version.mk中的mac_sdk_versions_supported所在的行添加10.11
先介绍下我的电脑基础环境:
1.硬件:MacBook Pro
2.系统版本:OS X EI Capitan 10.11.6
以下是官方给出的各个android版本建议对应的系统版本:
Android 6.0 (Marshmallow) - AOSP master: Ubuntu 14.04 (Trusty)
Android 2.3.x (Gingerbread) - Android 5.x (Lollipop): Ubuntu 12.04 (Precise)
Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Ubuntu 10.04 (Lucid)
Android 6.0 (Marshmallow) - AOSP master: Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
Android 5.x (Lollipop): Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat): Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple’s Developer Tools)
Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich): Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK
]]>
登陆之后,你会看到下图的界面。界面右边是你所参与的项目
首先你会看到橙色的提示,要你提供你的SSH-KEY, 请按照提示来添加你的公钥。
① 如果之前有生成过私钥和公钥,可直接在你的~/.ssh 目录看到id_rsa、id_rsa.pub这两个文件,将id_rsa.pub文件内容添加即可
② 如果未生成过的话,可通过终端输入以下命令生成1
ssh-keygen -t rsa
③ 如果后续想更改或者增减新的SSH-KEY,可在Profile Settings界面里(非Project设置界面),选择SSH Keys进行操作
界面上显示你可以通过http和ssh两种方式来获取代码,我们建议使用SSH.这样可以减少你反复输入密码。
点击可直接copy到当前git地址:git@kf2GitHUB:20248760/VersionManager.git
由于我们本机无法自动解析@kf2GitHUB地址,有两种处理方法:
1 | git clone git@172.28.2.93:20248760/VersionManager.git |
1 | host kf2GitHUB |
配置成功后,可使用以下命令即可直接clone代码了:1
git clone git@kf2GitHUB:20248760/VersionManager.git
如果出现以下提示:
输入:ssh-add 即可解决
回到Projects视图窗口,如下图,点击右侧New Project即可创建一个新的项目
如下图中红色框中所示,第一项填入你的项目名称,然后选择可访问级别,选择Internal——对登录用户才能进行clone操作,点击Create Project即可完成创建操作
创建成功之后会看到如下界面
如中间红色框所示:
1 | git config --global user.name "罗才干" |
1 | git clone git@kf2GitHUB:20248760/AwesomeTest.git |
1 | cd existing_folder |
如果之前该项目下已经存在一个git仓库,推荐使用第三种方式,可以在新仓库中保留所有原仓库中所有提交历史!
在Project视图,点击Members,可进行项目成员管理,如需添加新成员,如图所示完成三步操作即可:选择成员——分配权限(如需参与提交代码,权限等级不得低于Developer)——Add users to project
关于权限,master拥有最高管理权限,分配时应慎重,一般来说Developer权限足够了,除非该成员需要进行代码审核
每个团队研发有自己的开发分支:比如framework组有dev_framework_android分支。
每个软件工程师在自己团队的分支上开发和提交,可以push代码到开发分支,但是不允许merge代码到主干分支。这个merge的操作由merge request机制来完成,团队定期审核团队内提交的代码。并由专人接受审核申请,完成合并到主干的工作。
左侧项目菜单有个Commits项,点击,就可以看到项目目前的所有提交。
点击提交记录的一项,你可以看到这个提交的详情。
Project视图,选择Commits,找到对应的分支,点击Merge Request发起merge请求
登陆之后,你会看到下图的界面。界面右边是你所参与的项目
点击项目名称,可进入相应项目界面
]]>
通过命令1
adb shell dumpsys -l
可查看该机器支持的所有dump服务:
(以nexus 5 Android 6.0为例)
1 | lcg@ubuntu:~$ adb shell dumpsys -l |
通过命令1
service list
可进一步了解以上服务名具体对应的服务:
1 | shell@M1000:/ $ service list |
通过命令1
dumpsys activity -h
可查看所有参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29shell@M1000:/ $ dumpsys activity -h
Activity manager dump options:
[-a] [-c] [-p package] [-h] [cmd] ...
cmd may be one of:
a[ctivities]: activity stack state //activity 栈状态
r[recents]: recent activities state //最近使用Activity状态
b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state //广播状态
i[ntents] [PACKAGE_NAME]: pending intent state // Pending intent状态
p[rocesses] [PACKAGE_NAME]: process state //进程状态
o[om]: out of memory management // OOM信息
perm[issions]: URI permission grant state //授权状态
prov[iders] [COMP_SPEC ...]: content provider state //ContentProvider状态
provider [COMP_SPEC]: provider client-side state //ContentProvider(客户端)状态
s[ervices] [COMP_SPEC ...]: service state //服务状态
as[sociations]: tracked app associations
service [COMP_SPEC]: service client-side state //服务(客户端)状态
package [PACKAGE_NAME]: all state related to given package //所有与给予包名相关的状态
all: dump all activities //所有的activities信息
top: dump the top activity //栈顶activity信息
write: write all pending state to storage //状态持久化到存储
track-associations: enable association tracking //
untrack-associations: disable and clear association tracking
cmd may also be a COMP_SPEC to dump activities.
COMP_SPEC may be a component name (com.foo/.myApp),
a partial substring in a component name, a
hex object identifier.
-a: include all available server state. //列出所有可用的服务状态
-c: include client state. //列出客户端状态
-p: limit output to given package. //过滤,只显示该包名
通过命令1
adb shell dumpsys -l
可查看该机器支持的所有dump服务:
(以nexus 5 Android 6.0为例)
]]>am也是Android自带的一个脚本命令,位于:/system/bin/目录下,通过cat命令可查看其内容:1
2
3
4
5
6
7
8
9shell@M1000:/system/bin $ cat am
#!/system/bin/sh
#
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
通过终端输入adb shell am可查看所有命令详情:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237lcg@lcg-work-pc:~$ adb shell am
usage: am [subcommand] [options]
usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]
[--sampling INTERVAL] [-R COUNT] [-S] [--opengl-trace]
[--user <USER_ID> | current] <INTENT>
am startservice [--user <USER_ID> | current] <INTENT> //开启服务
am stopservice [--user <USER_ID> | current] <INTENT> //关闭服务
am force-stop [--user <USER_ID> | all | current] <PACKAGE> //强杀进程
am kill [--user <USER_ID> | all | current] <PACKAGE> //强杀进程
am kill-all //强杀所有后台进程
am broadcast [--user <USER_ID> | all | current] <INTENT> //发送广播
am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]
[--user <USER_ID> | current]
[--no-window-animation] [--abi <ABI>] <COMPONENT>
am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>
am profile stop [--user <USER_ID> current] [<PROCESS>]
am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>
am set-debug-app [-w] [--persistent] <PACKAGE>
am clear-debug-app
am set-watch-heap <PROCESS> <MEM-LIMIT>
am clear-watch-heap
am monitor [--gdb <port>]
am hang [--allow-restart]
am restart //重启机器
am idle-maintenance
am screen-compat [on|off] <PACKAGE>
am package-importance <PACKAGE>
am to-uri [INTENT]
am to-intent-uri [INTENT]
am to-app-uri [INTENT]
am switch-user <USER_ID>
am start-user <USER_ID>
am stop-user [-w] <USER_ID>
am stack start <DISPLAY_ID> <INTENT>
am stack movetask <TASK_ID> <STACK_ID> [true|false]
am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
am stack split <STACK_ID> <v|h> [INTENT]
am stack list
am stack info <STACK_ID>
am task lock <TASK_ID>
am task lock stop
am task resizeable <TASK_ID> [true|false]
am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>
am get-config
am set-inactive [--user <USER_ID>] <PACKAGE> true|false
am get-inactive [--user <USER_ID>] <PACKAGE>
am send-trim-memory [--user <USER_ID>] <PROCESS>
[HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]
am start: start an Activity. Options are:
-D: enable debugging
-W: wait for launch to complete
--start-profiler <FILE>: start profiler and send results to <FILE>
--sampling INTERVAL: use sample profiling with INTERVAL microseconds
between samples (use with --start-profiler)
-P <FILE>: like above, but profiling stops when app goes idle
-R: repeat the activity launch <COUNT> times. Prior to each repeat,
the top activity will be finished.
-S: force stop the target app before starting the activity
--opengl-trace: enable tracing of OpenGL functions
--user <USER_ID> | current: Specify which user to run as; if not
specified then run as the current user.
am startservice: start a Service. Options are:
--user <USER_ID> | current: Specify which user to run as; if not
specified then run as the current user.
am stopservice: stop a Service. Options are:
--user <USER_ID> | current: Specify which user to run as; if not
specified then run as the current user.
am force-stop: force stop everything associated with <PACKAGE>.
--user <USER_ID> | all | current: Specify user to force stop;
all users if not specified.
am kill: Kill all processes associated with <PACKAGE>. Only kills.
processes that are safe to kill -- that is, will not impact the user
experience.
--user <USER_ID> | all | current: Specify user whose processes to kill;
all users if not specified.
am kill-all: Kill all background processes.
am broadcast: send a broadcast Intent. Options are:
--user <USER_ID> | all | current: Specify which user to send to; if not
specified then send to all users.
--receiver-permission <PERMISSION>: Require receiver to hold permission.
am instrument: start an Instrumentation. Typically this target <COMPONENT>
is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:
-r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with
[-e perf true] to generate raw output for performance measurements.
-e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a
common form is [-e <testrunner_flag> <value>[,<value>...]].
-p <FILE>: write profiling data to <FILE>
-w: wait for instrumentation to finish before returning. Required for
test runners.
--user <USER_ID> | current: Specify user instrumentation runs in;
current user if not specified.
--no-window-animation: turn off window animations while running.
--abi <ABI>: Launch the instrumented process with the selected ABI.
This assumes that the process supports the selected ABI.
am profile: start and stop profiler on a process. The given <PROCESS> argument
may be either a process name or pid. Options are:
--user <USER_ID> | current: When supplying a process name,
specify user of process to profile; uses current user if not specified.
am dumpheap: dump the heap of a process. The given <PROCESS> argument may
be either a process name or pid. Options are:
-n: dump native heap instead of managed heap
--user <USER_ID> | current: When supplying a process name,
specify user of process to dump; uses current user if not specified.
am set-debug-app: set application <PACKAGE> to debug. Options are:
-w: wait for debugger when application starts
--persistent: retain this value
am clear-debug-app: clear the previously set-debug-app.
am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or
above <HEAP-LIMIT> then a heap dump is collected for the user to report
am clear-watch-heap: clear the previously set-watch-heap.
am bug-report: request bug report generation; will launch UI
when done to select where it should be delivered.
am monitor: start monitoring for crashes or ANRs.
--gdb: start gdbserv on the given port at crash/ANR
am hang: hang the system.
--allow-restart: allow watchdog to perform normal system restart
am restart: restart the user-space system.
am idle-maintenance: perform idle maintenance now.
am screen-compat: control screen compatibility mode of <PACKAGE>.
am package-importance: print current importance of <PACKAGE>.
am to-uri: print the given Intent specification as a URI.
am to-intent-uri: print the given Intent specification as an intent: URI.
am to-app-uri: print the given Intent specification as an android-app: URI.
am switch-user: switch to put USER_ID in the foreground, starting
execution of that user if it is currently stopped.
am start-user: start USER_ID in background if it is currently stopped,
use switch-user if you want to start the user in foreground.
am stop-user: stop execution of USER_ID, not allowing it to run any
code until a later explicit start or switch to it.
-w: wait for stop-user to complete.
am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.
am stack movetask: move <TASK_ID> from its current stack to the top (true) or bottom (false) of <STACK_ID>.
am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.
am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally
starting the new stack with [INTENT] if specified. If [INTENT] isn't
specified and the current stack has more than one task, then the top task
of the current task will be moved to the new stack. Command will also force
all current tasks in both stacks to be resizeable.
am stack list: list all of the activity stacks and their sizes.
am stack info: display the information about activity stack <STACK_ID>.
am task lock: bring <TASK_ID> to the front and don't allow other tasks to run.
am task lock stop: end the current task lock.
am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).
am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.
Forces the task to be resizeable and creates a stack if no existing stack
has the specified bounds.
am get-config: retrieve the configuration and any recent configurations
of the device.
am set-inactive: sets the inactive state of an app.
am get-inactive: returns the inactive state of an app.
am send-trim-memory: Send a memory trim event to a <PROCESS>.
<INTENT> specifications include these flags and arguments:
[-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
[-c <CATEGORY> [-c <CATEGORY>] ...]
[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
[--esn <EXTRA_KEY> ...]
[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
[--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
[--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]
[--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]
[--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]
[--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]
[--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
(mutiple extras passed as Integer[])
[--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
(mutiple extras passed as List<Integer>)
[--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
(mutiple extras passed as Long[])
[--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
(mutiple extras passed as List<Long>)
[--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
(mutiple extras passed as Float[])
[--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
(mutiple extras passed as List<Float>)
[--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
(mutiple extras passed as String[]; to embed a comma into a string,
escape it using "\,")
[--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
(mutiple extras passed as List<String>; to embed a comma into a string,
escape it using "\,")
[--grant-read-uri-permission] [--grant-write-uri-permission]
[--grant-persistable-uri-permission] [--grant-prefix-uri-permission]
[--debug-log-resolution] [--exclude-stopped-packages]
[--include-stopped-packages]
[--activity-brought-to-front] [--activity-clear-top]
[--activity-clear-when-task-reset] [--activity-exclude-from-recents]
[--activity-launched-from-history] [--activity-multiple-task]
[--activity-no-animation] [--activity-no-history]
[--activity-no-user-action] [--activity-previous-is-top]
[--activity-reorder-to-front] [--activity-reset-task-if-needed]
[--activity-single-top] [--activity-clear-task]
[--activity-task-on-home]
[--receiver-registered-only] [--receiver-replace-pending]
[--selector]
[<URI> | <PACKAGE> | <COMPONENT>]
通用的使用方法是: am + 子命令 + 参数
]]>am也是Android自带的一个脚本命令,位于:/system/bin/目录下,通过cat命令可查看其内容:1
2
3
4
5
6
7
8
9shell@M1000:/system/bin $ cat am
#!/system/bin/sh
#
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
svc是Android的一个脚本命令,在/system/bin目录下,我们通过cat命令可查看其详细信息:1
2
3
4
5
6
7caigandeMacBook-Pro:~ lcg$ adb shell cat /system/bin/svc
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/svc.jar
exec app_process $base/bin com.android.commands.svc.Svc $*
通过-h参数可查看所有命令:1
2
3
4
5
6
7caigandeMacBook-Pro:~ lcg$ adb shell svc -h
Available commands:
help Show information about the subcommands
power Control the power manager
data Control mobile data connectivity
wifi Control the Wi-Fi manager
usb Control Usb state
1 | shell@mx2:/ $ svc power -h |
svc power stayon [true|false|usb|ac|wireless]: 设置保持唤醒状态
1.true:常亮,相当于设置了所有标记(usb, ac, wireless)
2.false:清除所有标记
3.usb:插入usb时常亮
4.ac:充电时常亮
5.wireless:无线充电时常亮
当设置usb/ac/wireless其中一个标记时,会清除其余标记
svc power reboot [reason]: 设置设备在特定条件下关机并重启
svc power shutdown: 设置设备关机
1 | shell@mx2:/ $ svc data -h |
svc data [enable|disable]:控制设备数据连接开与关
1 | shell@mx2:/ $ svc wifi -h |
svc wifi [enable|disable]:控制wifi开与关
1 | shell@mx2:/ $ svc usb -h |
svc usb setFunction [function]:设置当前USB功能
其中[function]包括:mtp,adb等
svc usb getFunction:获取当前可用功能列表
]]>svc是Android的一个脚本命令,在/system/bin目录下,我们通过cat命令可查看其详细信息:1
2
3
4
5
6
7caigandeMacBook-Pro:~ lcg$ adb shell cat /system/bin/svc
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/svc.jar
exec app_process $base/bin com.android.commands.svc.Svc $*
通过-h参数可查看所有命令:1
2
3
4
5
6
7caigandeMacBook-Pro:~ lcg$ adb shell svc -h
Available commands:
help Show information about the subcommands
power Control the power manager
data Control mobile data connectivity
wifi Control the Wi-Fi manager
usb Control Usb state
Monkey是我们在Android平台常用的一种压力测试方法,通过Monkey可模拟用户触摸,按键,滑动操作,常用于测试程序的稳定性。
monkey是一个shell脚本,存放于:/system/bin/monkey
使用如下命令: adb shell cat /system/bin/monkey 可以查看具体内容
1 | lcg@lcg-work-pc:~$ adb shell cat /system/bin/monkey |
从上面内容可以看到,执行的时:/system/framework/monkey.jar 中内容.
查看帮助:1
adb shell monkey -help
1 | lcg@lcg-work-pc:~$ adb shell monkey -help |
-p: 用于指定一个或者多个包,Monkey将只允许系统去访问这些包的activitys,如果应用需要访问其他包的activitys,连同这些包也一起指定在内.如果不指定任何包,Monkey默认可启动任何包的activitys.指定多个包,需要多次使用-p参数,一个-p参数对应一个包名,示例如下:
adb shell monkey -p com.android.monkeytest1 -p com.android.monkeytest2
-c: 用于指定一个或多个categories,Monkey将只能访问指定categories的activitys;如果未指定任何categories,将默认访问带有 Intent.CATEGORY_LAUNCHER 或 Intent.CATEGORY_MONKEY的activitys.指定多个categories的使用上与-p一致,一个参数对应一个categorie.
[–ignore-crashes]: Monkey运行时忽略程序Crash或者异常信息未捕获,直到达到指定执行次数
[–ignore-security-exceptions]: Monkey运行时忽略程序权限访问异常,直到达到指定执行次数
[–monitor-native-crashes]: 观察并上报Android system native code异常
[–kill-process-after-error]: 终止出现错误的进程
[–pct-touch PERCENT]: 调整touch事件(down-up event)比例
[–pct-trackball PERCENT]: 调整trackball事件(trackball事件:包含一个或多个随机动作,有时发生在点击事件之后)比例
[–pct-nav PERCENT]: 调整”basic” navigation事件比例. (Navigation事件即: 从可输入方向设备输入包含上/下/左/右方向事件.)
[–pct-appswitch PERCENT]: Monkey会在随机间隔时间,通过调用startActivity()来保证最大化覆盖包内所有activitys
[–pct-anyevent PERCENT]: 调整所有其他类型事件的比例,包括按键事件,其他在设备上很少使用的按钮等等
[–pct-permission PERCENT]:
[–pkg-blacklist-file PACKAGE_BLACKLIST_FILE]: 执行黑名单以外的应用
[–pkg-whitelist-file PACKAGE_WHITELIST_FILE]: 执行白名单以外的应用
[–wait-dbg]: 停止执行中的Monkey,直到有调试器和它相连接
[–setup scriptfile]: 执行按照一定的语法规则编写有序的用户事件流并适用于monkey命令工具的脚本。
[–port port]: 为monkey开启专用端口
[-s SEED]: 随机数生成器的seed值。如果使用相同的seed值再次运行monkey,它将生成相同的事件序列
[–throttle MILLISEC]: 设置每一次有效执行事件后休眠时间
[–profile-wait MILLISEC]:
[–device-sleep-time MILLISEC]: 设备休眠时间
[–randomize-script]: monkey脚本内容随机执行
[–script-log]: 输出monkey脚本log
[–bugreport]: 设置Monkey运行时自动记录发生crash,anr,system not responding的错误信息。
[–periodic-bugreport]:
[–permission-target-system]:
[COUNT]: Monkey执行次数
Monkey是我们在Android平台常用的一种压力测试方法,通过Monkey可模拟用户触摸,按键,滑动操作,常用于测试程序的稳定性。
monkey是一个shell脚本,存放于:/system/bin/monkey
使用如下命令: adb shell cat /system/bin/monkey 可以查看具体内容
1 | lcg@lcg-work-pc:~$ adb shell cat /system/bin/monkey |
从上面内容可以看到,执行的时:/system/framework/monkey.jar 中内容.
]]>
Java一个非常重要的优点就是垃圾回收机制,但如果使用不当的话,很容易引发内存泄漏问题。
Java内存回收机制:只有当某个对象不再引用时,它的内存才会被回收,如果某个本该被释放的
对象的引用仍然被持有时,此时内存泄漏就会发生。
Java定义了四种类型的引用:
强引用(Strong)
弱引用(Weak)
软引用(Soft)
虚引用(Phantom)
最常见的一种,我们所写的代码中大部分都是强引用,如果一个对象具有强引用,那垃圾回收器绝不会回收它。如:1
Object o = new Object();
如果该对象不再使用,需要显式将其置为null1
o = null;
当存在足够的内存保存对象时,垃圾收集器不会回收,只有当内存不足时才会被GC回收,适合用于设计Cache。
一旦GC的时候发现了某个对象是弱引用,就会被回收,不管现在内存是否足够;适合应用于映射,这种映射可以自动删除不再被引用的键(如WeakHashMap)
通常用于在某处保存对象引用,而又不干扰该对象被GC回收,通常用于Debug、内存监视工具等程序中。因为这类程序一般要求即要观察到对象,又不能影响该对象正常的GC过程。
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
Android3.0以上:
1、Activity泄漏
2、其他对象泄漏
3、对象未关闭造成的泄漏(如游标,输入输出流等所有实现Closeable接口的类)
以下是示例代码实现(记得只在开发和调试中使用):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class MyApplication extends Application {
public static final boolean DEBUG_MODLE = true;
@Override
public void onCreate() {
super.onCreate();
if(DEBUG_MODLE){
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
builder.detectAll();
builder.penaltyLog();
// builder.penaltyDeath();
StrictMode.VmPolicy vmp = builder.build();
StrictMode.setVmPolicy(vmp);
}
}
}
OnLowMemory是Android提供的API,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,在系统内存还不足时,系统会调用OnLowMemory。
OnTrimMemory是Android 4.0之后提供的API,系统会根据不同的内存状态来回调。根据不同的内存状态,来响应不同的内存释放策略。
以下几点是我们常常要考虑释放的资源:
缓存或缓存条目(如使用强引用的LruCache)
可以再次按需生成的位图对象
不可见的布局对象
数据库对象
先找瓶颈,再优化代码,物尽其用
1、检查是否允许后台传输数据1
2
复杂布局在代码中展开
Java一个非常重要的优点就是垃圾回收机制,但如果使用不当的话,很容易引发内存泄漏问题。
Java内存回收机制:只有当某个对象不再引用时,它的内存才会被回收,如果某个本该被释放的
对象的引用仍然被持有时,此时内存泄漏就会发生。
Java定义了四种类型的引用:
强引用(Strong)
弱引用(Weak)
软引用(Soft)
虚引用(Phantom)
最常见的一种,我们所写的代码中大部分都是强引用,如果一个对象具有强引用,那垃圾回收器绝不会回收它。如:1
Object o = new Object();
如果该对象不再使用,需要显式将其置为null1
o = null;
当存在足够的内存保存对象时,垃圾收集器不会回收,只有当内存不足时才会被GC回收,适合用于设计Cache。
一旦GC的时候发现了某个对象是弱引用,就会被回收,不管现在内存是否足够;适合应用于映射,这种映射可以自动删除不再被引用的键(如WeakHashMap)
通常用于在某处保存对象引用,而又不干扰该对象被GC回收,通常用于Debug、内存监视工具等程序中。因为这类程序一般要求即要观察到对象,又不能影响该对象正常的GC过程。
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
]]>
单元测试是最基础的测试,有效的单元测试将直接提升产品质量。软件开发工程师应当将编写和运行测试作为开发过程的一部分,
良好的单元测试能够在开发早期发现软件缺陷,让工程师对自己写的代码感到自信。
本文将描述如何使用JUnit4框架在Android工程中进行单元测试,开发环境为Android Studio,Android中有两种单元测试:
Local Unit Tests和Instrumented Tests,Instrumented Tests依赖于设备,可进行单元、组件、界面测试,
本文重点描述如何进行本地单元测试(Local Unit Tests)。
注:文中提到的例子在Google Samples的BasicSample基础上进行了部分修改。
使用版本管理控制软件,推荐使用git,目前最好的版本控制软件,没有之一。
https://git-scm.com/downloads
Android Studio默认集成工具为gradle。
https://docs.gradle.org/current/userguide/userguide.html
单元测试框架junit4
http://junit.org/junit4/
模拟对象框架mockito
http://mockito.org/
模拟真机功能Robolectric。
http://robolectric.org/
自动化构建工具,推荐使用jenkins。
https://jenkins.io/index.html
工程目录app->src->test目录
在工程app/build.gralde文件中增加如下依赖1
2
3
4
5dependencies {
// Unit testing dependencies.
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
}
增加jacoco支持1
apply plugin: 'jacoco'
1 | ependencies { |
// 增加jacoco,工具版本可以根据最新版本进行修改1
2
3jacoco {
toolVersion = "0.7.6.201602180812"
}
Android节点buildTypes增加testCoverageEnabled = true
Lint选项设置为遇到错误不终止。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22android {
compileSdkVersion 23
buildToolsVersion '23.0.2'
defaultConfig {
applicationId "com.example.android.testing.unittesting.BasicSample"
minSdkVersion 8
versionCode 1
versionName "1.0"
targetSdkVersion 23
}
buildTypes {
debug {
testCoverageEnabled = true
}
}
productFlavors {
}
lintOptions {
// I prefer avoiding a build fail if there is any warning, for they are only warnings
abortOnError false
}
}
android studio自动集成了单元测试覆盖率统计工具,选中编写好的测试类,右键点击Run ‘XXXXXX’ with Coverage。
出现覆盖率面板,按F4或双击相关行,可以打开源代码查看具体哪些行没有覆盖到。
两种颜色表明覆盖和未覆盖两种状态,此时开发工程师应当分析是否需要增加新的测试代码对未进行测试的语句行覆盖。
推荐使用git,目前最好的版本控制软件,没有之一。
一般选择定时检测版本库,有提交就自动构建。
在Lint files项填入**/app/build/outputs/lint-results-debug.xml
在测试报告项填入/build/test-results//*.xml
1 | Path to exec files项增加**/build/jacoco/*.exec |
填写接收构建失败邮件的邮箱地址,需要确认在Jenkins的系统管理中增加了邮件服务器和管理员的配置。
点击各目录可查看详细的问题信息
点击文件名可查看具体的代码行覆盖情况
单元测试是最基础的测试,有效的单元测试将直接提升产品质量。软件开发工程师应当将编写和运行测试作为开发过程的一部分,
良好的单元测试能够在开发早期发现软件缺陷,让工程师对自己写的代码感到自信。
本文将描述如何使用JUnit4框架在Android工程中进行单元测试,开发环境为Android Studio,Android中有两种单元测试:
Local Unit Tests和Instrumented Tests,Instrumented Tests依赖于设备,可进行单元、组件、界面测试,
本文重点描述如何进行本地单元测试(Local Unit Tests)。
注:文中提到的例子在Google Samples的BasicSample基础上进行了部分修改。
]]>
在android的自定义view中,onMeasure与onLayout这两个方法无疑是最重要的,只有深刻理解了这两个方法,才能写出我们自己想要的view/viewgroup
我们先看源码注释中对这两个方法的解释:
注:本文源码基于android-17
* <p>
* Measure the view and its content to determine the measured width and the
* measured height. This method is invoked by {@link #measure(int, int)} and
* should be overriden by subclasses to provide accurate and efficient
* measurement of their contents.
* </p>
如注释中所述: 通过测量当前view和它的contents,来决定当前所测量出的宽度和高度.这个方法被measure(int, int)调用,并且子类应当重写该方法,
用以提供精确高效的测量方法来测量它的contents.
上文提到onMeasure是在measure(int, int)中被调用的,下面就来看一下measure(int, int)方法的源码:
/**
* <p>
* This is called to find out how big a view should be. The parent
* supplies constraint information in the width and height parameters.
* </p>
* <br>该方法被用于测量某个view所需大小,父视图提供宽度和高度的约束信息
*
* <p>
* The actual measurement work of a view is performed in
* {@link #onMeasure(int, int)}, called by this method. Therefore, only
* {@link #onMeasure(int, int)} can and must be overridden by subclasses.
* </p>
*
*
* @param widthMeasureSpec Horizontal space requirements as imposed by the
* parent
* @param heightMeasureSpec Vertical space requirements as imposed by the
* parent
*
* @see #onMeasure(int, int)
*/
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || //mPrivateFlags是否为FORCE LAYOUT
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) {
// first clears the measured dimension flag
//清除MEASURED_DIMENSION_SET标记
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
//Resolve all RTL related properties.
resolveRtlPropertiesIfNeeded();
// measure ourselves, this should set the measured dimension flag back
//测量view自身,并且重新设置PFLAG_MEASURED_DIMENSION_SET标记
onMeasure(widthMeasureSpec, heightMeasureSpec);
//如果未重新设置PFLAG_MEASURED_DIMENSION_SET标记将会抛出异常
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
throw new IllegalStateException("onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}
//设置标志,请求layout
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
}
下面我们看下onMeasure方法源码,及该方法中调用的相关源码
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
/**
* <p>This mehod must be called by {@link #onMeasure(int, int)} to store the
* measured width and measured height. Failing to do so will trigger an
* exception at measurement time.</p><br>设置当前视图的mMeasuredWidth与mMeasuredHeight
*
* @param measuredWidth The measured width of this view. May be a complex
* bit mask as defined by {@link #MEASURED_SIZE_MASK} and
* {@link #MEASURED_STATE_TOO_SMALL}.
* @param measuredHeight The measured height of this view. May be a complex
* bit mask as defined by {@link #MEASURED_SIZE_MASK} and
* {@link #MEASURED_STATE_TOO_SMALL}.
*/
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
/**
* Utility to return a default size. Uses the supplied size if the
* MeasureSpec imposed no constraints. Will get larger if allowed
* by the MeasureSpec.<br>返回一个默认大小。如果MeasureSpec中不包含限制,将返回参数size的大小;
*
* @param size Default size for this view
* @param measureSpec Constraints imposed by the parent
* @return The size this view should be.
*/
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
/**
* Returns the suggested minimum width that the view should use. This
* returns the maximum of the view's minimum width)
* and the background's minimum width<br>
* 返回视图建议使用的最小宽度(该视图最小宽度与背景图最小宽度中的最大值)
* ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
* <p>
* When being used in {@link #onMeasure(int, int)}, the caller should still
* ensure the returned width is within the requirements of the parent.
*
* @return The suggested minimum width of the view.
*/
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
protected int getSuggestedMinimumHeight() {
return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
}
]]>在android的自定义view中,onMeasure与onLayout这两个方法无疑是最重要的,只有深刻理解了这两个方法,才能写出我们自己想要的view/viewgroup
我们先看源码注释中对这两个方法的解释:
注:本文源码基于android-17
* <p>
* Measure the view and its content to determine the measured width and the
* measured height. This method is invoked by {@link #measure(int, int)} and
* should be overriden by subclasses to provide accurate and efficient
* measurement of their contents.
* </p>
]]>
屏幕尺寸: 就是我们通常所说的手机大小,比如iPhone6s大小为4.7寸,确切的来说这里指的是英寸(1 in ≈ 2.54 cm)
这个大小又屏幕对角线的长度确定
屏幕分辨率: 指的是屏幕纵向与横向上像素点的数量,比如1920×1080,代表的是在屏幕纵向有1920个像素点,横向有1080个像素点
屏幕像素密度: 每英寸屏幕所拥有的像素数(单位dpi)像素密度越大,显示画面细节就越丰富,也就是我们通常所说的屏幕越清晰
计算公式: dpi =√(widthPx^2 + heightPx^2) / 屏幕尺寸
屏幕尺寸: 就是我们通常所说的手机大小,比如iPhone6s大小为4.7寸,确切的来说这里指的是英寸(1 in ≈ 2.54 cm)
这个大小又屏幕对角线的长度确定
屏幕分辨率: 指的是屏幕纵向与横向上像素点的数量,比如1920×1080,代表的是在屏幕纵向有1920个像素点,横向有1080个像素点
屏幕像素密度: 每英寸屏幕所拥有的像素数(单位dpi)像素密度越大,显示画面细节就越丰富,也就是我们通常所说的屏幕越清晰
计算公式: dpi =√(widthPx^2 + heightPx^2) / 屏幕尺寸