aboutsummaryrefslogtreecommitdiff
path: root/zh-cn/source/jack.html
blob: 261efadfd6ef0ace7f40f45a21424944d04fc41c (plain)
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
<html devsite><head>
    <title>使用 Jack 编译</title>
    <meta name="project_path" value="/_project.yaml"/>
    <meta name="book_path" value="/_book.yaml"/>
  </head>
  <body>
  <!--
      Copyright 2017 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.
  -->

<h2 id="the_jack_toolchain">Jack 工具链</h2>

<p class="warning">
  根据<a href="https://android-developers.googleblog.com/2017/03/future-of-java-8-language-feature.html">此公告</a>,<b>Jack 工具链已被弃用</b>。不过,在我们提供替代工具之前,您可以继续使用它<a href="https://developer.android.com/preview/j8-jack.html">启用 Java 8 语言功能</a>。
</p>

<p>Jack 是一种新型 Android 工具链,用于将 Java 源代码编译成 Android dex 字节码。它取代了之前由 javac、ProGuard、jarjar 和 dx 等多种工具组成的 Android 工具链。</p>

<p>Jack 工具链具有以下优势:</p>

<ul>
  <li> <strong>完全开放源代码</strong><br />
它是在 AOSP 中提供的;并且欢迎用户贡献资源。
  </li><li> <strong>提高编译速度</strong><br />

Jack 提供以下具体支持来减少编译时间:dex 预处理、增量编译和 Jack 编译服务器。
  </li><li> <strong>支持压缩、混淆、重新打包和多 dex 处理</strong><br />
不再需要使用单独的软件包(如 ProGuard)
</li></ul>

<p class="note">请注意,从 Android 7.0 (N) 开始,Jack 支持使用 JaCoCo 衡量代码覆盖率。如需了解详情,请参阅<a href="https://android.googlesource.com/platform/prebuilts/sdk/+/master/tools/README-jack-code-coverage.md">使用 JaCoCo 衡量代码覆盖率</a>和 <a href="https://developer.android.com/preview/j8-jack.html">Java 8 语言功能</a>。</p>

<img src="/images/jack-overview.png" height="75%" width="75%" alt="Jack 概览"/>
<p class="img-caption"><strong>图 1. </strong>Jack 概览</p>

<h2 id="the_jack_library_format">.jack 库格式</h2>

<p>Jack 具有自己的 .jack 文件格式,其中包含相应库的预编译 dex 代码,可实现更快速的编译 (dex 预处理)。</p>

<img src="/images/jack-library-file.png" height="75%" width="75%" alt="Jack 库文件内容"/>
<p class="img-caption"><strong>图 2. </strong>Jack 库文件内容</p>

<h2 id="jill">Jill</h2>

<p>Jill 工具可将现有的 .jar 库转换为新的库格式,如下图所示。</p>

<img src="/images/jill.png" alt="使用 Jill 导入现有的 .jar 库"/>
<p class="img-caption"><strong>图 3. </strong>导入现有 .jar 库的工作流程</p>

<h2 id="using_jack_in_your_android_build">使用 Jack 进行 Android 编译</h2>

<div class="note">如需了解在 Android 7.0 (N) 及更高版本中使用 Jack 的说明,请参阅 <a href="https://android.googlesource.com/platform/prebuilts/sdk/+/master/tools/README-jack-server.md">Jack 服务器文档</a>。对于 Android 6.0 (M),请使用本部分中的说明。</div>

<p>要使用 Jack,您只需使用标准的 Makefile 命令来编译树或您的项目即可,无需进行任何其他操作。Jack 是适合 M 的默认 Android 编译工具链。</p>

<p>首次使用 Jack 时,它会在您的计算机上启动一个本地 Jack 编译服务器:</p>

<ul>
  <li>该服务器能够让 Jack 实现内在加速,因为它可以避免在每次编译时启动新的主机 JRE JVM、加载 Jack 代码、初始化 Jack 以及准备 JIT。此外,它还会在小规模编译期间(例如增量模式下)尽可能优化编译所需时间。
  </li><li>该服务器还是在短时间内控制并行 Jack 编译数量的解决方案,因此可以避免计算机过载(内存或磁盘问题),因为它会限制并行编译的数量。
</li></ul>

<p>如果没有任何编译工作,在空闲一段时间之后,Jack 服务器会自行关闭。它使用了 localhost 接口上的两个 TCP 端口,因此无法从外部访问。您可以通过修改<code> $HOME/.jack</code> 文件来修改所有这些参数(并行编译的数量、超时、端口号等)。</p>

<h3 id="$home_jack_file">$HOME/.jack 文件</h3>

<p><code>$HOME/.jack</code> 文件包含 Jack 服务器变量的设置,采用纯 bash 语法编写。</p>

<p>以下是可用设置及其定义和默认值:</p>

<ul>
  <li> <strong><code>SERVER=true</code></strong><code> </code>:启用 Jack 的服务器功能。
  </li><li> <strong><code>SERVER_PORT_SERVICE=8072</code>
</strong>设置服务器的用于编译的 TCP 端口号。
  </li><li> <strong><code>SERVER_PORT_ADMIN=8073</code></strong>:
设置服务器的用于管理的 TCP 端口号。
  </li><li> <strong><code>SERVER_COUNT=1</code></strong>:
目前未使用。
  </li><li> <strong><code>SERVER_NB_COMPILE=4</code></strong>:
允许的最大并行编译数量。
  </li><li> <strong><code>SERVER_TIMEOUT=60</code></strong>:
无编译工作时服务器在自行关闭之前必须等待的空闲秒数。
  </li><li> <strong><code>SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log}</code></strong>:
在其中写入服务器日志的文件。默认情况下,此变量可被环境变量重载。
  </li><li> <strong><code>JACK_VM_COMMAND=${JACK_VM_COMMAND:=java}</code></strong>:
用于在主机上启动 JVM 的默认命令。默认情况下,此变量可被环境变量重载。
</li></ul>

<h3 id="jack_troubleshooting">Jack 问题排查</h3>

<p><strong>如果您的计算机在编译期间无响应,或者如果 Jack 编译因“Out of memory error”(内存不足错误)而失败</strong></p>

<p>您可以通过修改<code> $HOME/.jack</code> 并将<code> SERVER_NB_COMPILE</code> 改为较低的值来减少同时进行的 Jack 编译的数量,以针对所遇到的问题予以改善。</p>

<p><strong>如果您的编译因“Cannot launch background server”(无法启动后台服务器)而失败</strong></p>

<p>最可能的原因是您的计算机上的 TCP 端口都被占用了。请尝试通过修改 <code>$HOME/.jack </code>(<code>SERVER_PORT_SERVICE</code> 和 <code>SERVER_PORT_ADMIN</code> 变量)进行更改。</p>

<p>如果问题没有解决,请报告此问题并附上您的编译日志和 Jack 服务器日志(请参阅下文中的“查找 Jack 日志”,了解从何处找到服务器日志文件)。要解决这种情况,请通过修改 <code>$HOME/.jack</code> 并将 <code>SERVER</code> 更改为 false 来停用 jack 编译服务器。遗憾的是,这将大大减慢您的编译速度,并可能强制您使用加载控制(<code>make</code> 的选项“<code>-l</code>”)启动 <code>make -j</code>。</p>

<p><strong>如果您的编译卡住了,没有任何进展</strong></p>

<p>请报告此问题,并向我们提供以下附加信息(如果可能的话):</p>

<ul>
  <li>卡住时所在的命令行。
  </li><li>此命令行的输出。
  </li><li>运行 <code>jack-admin server-stat</code> 的结果。
  </li><li><code>$HOME/.jack</code> 文件。
  </li><li>服务器日志(已转储服务器状态)的内容。要获取日志内容,请执行以下操作:<ul>
    <li>通过运行 <code>jack-admin list-server</code> 查找 Jack 后台服务器进程。
    </li><li>向此服务器发送 <code>kill -3</code> 命令,将其状态转储到日志文件中。
    </li><li>要找到该服务器日志文件,请参阅下文中的“查找 Jack 日志”。
  </li></ul>
  </li><li>运行 <code>ls -lR $TMPDIR/jack-$USER.</code> 的结果。
  </li><li>运行 <code>ps j -U $USER.</code> 的结果。
</li></ul>

<p>您应该能够通过停止 Jack 后台服务器(使用 <code>jack-admin kill-server</code>),然后移除临时目录(<code>/tmp</code> 或 <code>$TMPDIR</code>)的 <code>jack-$USER</code> 中包含的临时目录来解决卡住的情况。</p>

<p><strong>如果您有任何其他问题</strong></p>

<p>要报告错误或请求功能,请使用我们的公开问题跟踪工具(位于 <a href="http://b.android.com">http://b.android.com</a> 上),以及 <a href="https://code.google.com/p/android/issues/entry?template=Jack%20bug%20report">Jack 工具错误报告</a>或 <a href="https://code.google.com/p/android/issues/entry?template=Jack%20feature%20request">Jack 工具功能请求</a>模板。请在错误报告中附上 Jack 日志。</p>
<table>
 <tbody><tr>
    <td><strong>查找 Jack 日志</strong>
<ul>
  <li>如果您曾使用 dist 目标运行了 Make 命令,则 Jack 日志位于 <code>$ANDROID_BUILD_TOP/out/dist/logs/jack-server.log</code>
  </li><li>如果没有,则您可以通过运行 <code>jack-admin server-log</code> 找到该日志
</li></ul>
</td>
 </tr>
</tbody></table>

<p>对于可重现的 Jack 错误,您可以通过设置一个变量来获取更详细的日志,如下所示:</p>

<pre class="prettyprint">
$ export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -D
sched.runner=single-threaded"
</pre>

<p>然后使用标准 Makefile 命令编译树或您的项目,并附上其标准输出和错误。</p>

<p>要移除详细的编译日志,请使用以下命令:</p>

<pre class="prettyprint">
$ unset ANDROID_JACK_EXTRA_ARGS
</pre>

<h3 id="jack_limitations">Jack 的使用限制</h3>

<ul>
  <li>Jack 服务器默认为单用户模式,因此一台计算机上只能有一位用户使用。如果有多个用户要使用,请为每位用户选择不同的端口号,并相应调整 SERVER_NB_COMPILE。您还可以通过在 $HOME/.jack 中设置 SERVER=false 来停用 Jack 服务器。
  </li><li>当前的 vm-tests-tf 集成方案会导致 CTS 编译速度较慢。
  </li><li>不支持 JaCoCo 等字节码处理工具。
</li></ul>

<h2 id="using_jack_features">使用 Jack 功能</h2>

<p>Jack 支持 Java 编程语言 1.7,并集成了下面列出的额外功能。</p>

<h3 id="predexing">dex 预处理</h3>

<p>在生成 Jack 库文件时,系统也会生成该库的 .dex 文件并将其作为 dex 预处理文件存储在 .jack 库文件中。在进行编译时,Jack 会重复使用每个库的 dex 预处理文件。</p>

<p>所有库均经过 dex 预处理。</p>

<img src="/images/pre-dex.png" height="75%" width="75%" alt="包含 dex 预处理文件的 Jack 库"/>
<p class="img-caption"><strong>图 4. </strong>包含 dex 预处理文件的 Jack 库</p>

<h4 id="limitations">使用限制</h4>

<p>目前,如果在编译过程中使用了压缩/混淆/重新打包功能,则 Jack 不会重复使用库的 dex 预处理文件。</p>

<h3 id="incremental_compilation">增量编译</h3>

<p>增量编译指的是,仅重新编译自上次编译后出现过更改的组件及其依赖项。当只有少数组件出现过更改时,进行增量编译可能比完整编译快得多。</p>

<h4 id="limitations">使用限制</h4>

<p>当压缩、混淆、重新打包或对旧版 multi-dex 启用后,增量编译会被停用。

Benny: 如何理解 multi-dex legacy</p>

<h4 id="enabling_incremental_builds">启用增量编译</h4>

<p>目前,增量编译默认处于未启用状态。要启用增量编译,请将以下行内容添加到您要进行增量编译的项目的 Android.mk 文件中:</p>

<pre class="prettyprint">
LOCAL_JACK_ENABLED := incremental
</pre>

<p class="note"><strong>注意</strong>:首次使用 Jack 编译项目时,如果某些依赖项未编译,请使用 <code>mma</code> 进行编译,之后您可以使用标准编译命令。</p>

<h3 id="shrinking_and_obfuscation">压缩和混淆</h3>

<p>Jack 支持压缩和混淆,并使用 proguard 配置文件来实现压缩和混淆功能。以下是支持的选项和忽略的选项:</p>

<h4 id="supported_common_options">支持的常用选项</h4>

<p>常用选项包括:</p>

<ul>
  <li> <code>@</code>
  </li><li> <code>-include</code>
  </li><li> <code>-basedirectory</code>
  </li><li> <code>-injars</code>
  </li><li> <code>-outjars // only 1 output jar supported</code>
  </li><li> <code>-libraryjars</code>
  </li><li> <code>-keep</code>
  </li><li> <code>-keepclassmembers</code>
  </li><li> <code>-keepclasseswithmembers</code>
  </li><li> <code>-keepnames</code>
  </li><li> <code>-keepclassmembernames</code>
  </li><li> <code>-keepclasseswithmembernames</code>
  </li><li> <code>-printseeds</code>
</li></ul>

<h4 id="supported_shrinking_options">支持的压缩选项</h4>

<p>压缩选项包括:</p>

<ul>
  <li> <code>-dontshrink</code>
</li></ul>

<h4 id="supported_obfuscation_options">支持的混淆选项</h4>

<p>混淆选项包括:</p>

<ul>
  <li> <code>-dontobfuscate</code>
  </li><li> <code>-printmapping</code>
  </li><li> <code>-applymapping</code>
  </li><li> <code>-obfuscationdictionary</code>
  </li><li> <code>-classobfuscationdictionary</code>
  </li><li> <code>-packageobfuscationdictionary</code>
  </li><li> <code>-useuniqueclassmembernames</code>
  </li><li> <code>-dontusemixedcaseclassnames</code>
  </li><li> <code>-keeppackagenames</code>
  </li><li> <code>-flattenpackagehierarchy</code>
  </li><li> <code>-repackageclasses</code>
  </li><li> <code>-keepattributes</code>
  </li><li> <code>-adaptclassstrings</code>
</li></ul>

<h4 id="ignored_options">忽略的选项</h4>

<p>忽略的选项包括:</p>

<ul>
  <li> <code>-dontoptimize // Jack does not optimize</code>
  </li><li> <code>-dontpreverify // Jack does not preverify</code>
  </li><li> <code>-skipnonpubliclibraryclasses</code>
  </li><li> <code>-dontskipnonpubliclibraryclasses</code>
  </li><li> <code>-dontskipnonpubliclibraryclassmembers</code>
  </li><li> <code>-keepdirectories</code>
  </li><li> <code>-target</code>
  </li><li> <code>-forceprocessing</code>
  </li><li> <code>-printusage</code>
  </li><li> <code>-whyareyoukeeping</code>
  </li><li> <code>-optimizations</code>
  </li><li> <code>-optimizationpasses</code>
  </li><li> <code>-assumenosideeffects</code>
  </li><li> <code>-allowaccessmodification</code>
  </li><li> <code>-mergeinterfacesaggressively</code>
  </li><li> <code>-overloadaggressively</code>
  </li><li> <code>-microedition</code>
  </li><li> <code>-verbose</code>
  </li><li> <code>-dontnote</code>
  </li><li> <code>-dontwarn</code>
  </li><li> <code>-ignorewarnings</code>
  </li><li> <code>-printconfiguration</code>
  </li><li> <code>-dump</code>
</li></ul>

<p class="note"><strong>注意</strong>:其他选项会引发错误。</p>

<h3 id="repackaging">重新打包</h3>

<p>Jack 使用 jarjar 配置文件进行重新打包。</p>

<p class="note"><strong>注意</strong>:Jack 与“rule”规则类型兼容,但与“zap”或“keep”规则类型不兼容。如果您需要使用“zap”或“keep”规则类型,请提交一项功能请求,并在其中说明您在应用中如何使用该功能。</p>

<h3 id="multidex_support">多 dex 支持</h3>

<p>由于 dex 文件的方法数上限为 65K,因此方法数超过 65K 的应用必须拆分成多个 dex 文件(要详细了解多 dex,请参阅<a href="http://developer.android.com/tools/building/multidex.html">构建方法数超过 65K 的应用</a>)。</p>

<p>Jack 支持本地多 dex 和旧版多 dex。</p>

</body></html>