|
13 | 13 | // limitations under the License. |
14 | 14 | package com.google.devtools.build.android; |
15 | 15 |
|
| 16 | +import static java.lang.Math.min; |
16 | 17 | import static java.nio.charset.StandardCharsets.UTF_8; |
17 | 18 | import static java.util.concurrent.TimeUnit.MILLISECONDS; |
18 | 19 |
|
19 | 20 | import com.beust.jcommander.JCommander; |
20 | 21 | import com.beust.jcommander.Parameter; |
21 | 22 | import com.beust.jcommander.ParameterException; |
22 | 23 | import com.beust.jcommander.Parameters; |
| 24 | +import com.google.common.cache.Cache; |
| 25 | +import com.google.common.cache.CacheBuilder; |
| 26 | +import com.google.common.cache.Weigher; |
23 | 27 | import com.google.common.collect.Sets; |
24 | 28 | import com.google.common.io.ByteStreams; |
25 | 29 | import com.google.devtools.build.android.Converters.CompatExistingPathConverter; |
26 | 30 | import com.google.devtools.build.android.Converters.CompatPathConverter; |
27 | 31 | import com.google.devtools.build.android.r8.CompatDexBuilder; |
| 32 | +import com.google.devtools.build.android.r8.CompatDexBuilder.DexingKeyR8; |
28 | 33 | import com.google.devtools.build.android.r8.Constants; |
29 | 34 | import com.google.devtools.build.android.r8.Desugar; |
| 35 | +import com.google.devtools.build.lib.worker.ProtoWorkerMessageProcessor; |
| 36 | +import com.google.devtools.build.lib.worker.WorkRequestHandler; |
30 | 37 | import java.io.BufferedReader; |
31 | 38 | import java.io.FileInputStream; |
32 | 39 | import java.io.FileOutputStream; |
33 | 40 | import java.io.IOException; |
34 | 41 | import java.io.InputStream; |
| 42 | +import java.io.PrintStream; |
| 43 | +import java.io.PrintWriter; |
35 | 44 | import java.nio.file.Files; |
36 | 45 | import java.nio.file.Path; |
37 | 46 | import java.nio.file.attribute.FileTime; |
| 47 | +import java.time.Duration; |
38 | 48 | import java.util.ArrayList; |
39 | 49 | import java.util.Arrays; |
40 | 50 | import java.util.Enumeration; |
@@ -169,8 +179,27 @@ private static void dexbuilder(Options options, Path jar, Path outputZip) |
169 | 179 | args.add(Integer.toString(options.minSdkVersion)); |
170 | 180 | } |
171 | 181 |
|
| 182 | + // Set up dexer cache |
| 183 | + Cache<DexingKeyR8, byte[]> dexCache = null; |
| 184 | + if (options.persistentWorker) { |
| 185 | + final long ONE_MEG = 1024 * 1024; |
| 186 | + dexCache = |
| 187 | + CacheBuilder.newBuilder() |
| 188 | + // Use at most 200 MB for cache and leave at least 25 MB of heap space alone. For |
| 189 | + // reference: |
| 190 | + // .class & class.dex files are around 1-5 KB, so this fits ~30K-35K class-dex pairs. |
| 191 | + .maximumWeight(min(Runtime.getRuntime().maxMemory() - 25 * ONE_MEG, 200 * ONE_MEG)) |
| 192 | + .weigher( |
| 193 | + new Weigher<DexingKeyR8, byte[]>() { |
| 194 | + @Override |
| 195 | + public int weigh(DexingKeyR8 key, byte[] value) { |
| 196 | + return key.classfileContent().length + value.length; |
| 197 | + } |
| 198 | + }) |
| 199 | + .build(); |
| 200 | + } |
172 | 201 | CompatDexBuilder compatDexBuilder = new CompatDexBuilder(); |
173 | | - compatDexBuilder.dexEntries(args); |
| 202 | + compatDexBuilder.dexEntries(dexCache, args); |
174 | 203 | } |
175 | 204 |
|
176 | 205 | private static int indexAny(String s, char[] chars) { |
@@ -272,25 +301,68 @@ private static void zipShard(Path zip, List<Path> outs) throws IOException { |
272 | 301 |
|
273 | 302 | public static void main(String[] args) throws Exception { |
274 | 303 | List<String> argsList = new ArrayList<>(Arrays.asList(args)); |
275 | | - Options options = new Options(); |
276 | 304 |
|
277 | | - final String flagfilePrefix = "-flagfile="; |
| 305 | + if (argsList.contains("--persistent_worker")) { |
| 306 | + System.exit(runPersistentWorker()); |
| 307 | + } else { |
| 308 | + processRequest(argsList); |
| 309 | + } |
| 310 | + } |
278 | 311 |
|
| 312 | + private static int runPersistentWorker() { |
| 313 | + PrintStream realStdErr = System.err; |
| 314 | + |
| 315 | + try { |
| 316 | + WorkRequestHandler workerHandler = |
| 317 | + new WorkRequestHandler.WorkRequestHandlerBuilder( |
| 318 | + new WorkRequestHandler.WorkRequestCallback( |
| 319 | + (request, pw) -> processRequestForWorker(request.getArgumentsList(), pw, realStdErr)), |
| 320 | + realStdErr, |
| 321 | + new ProtoWorkerMessageProcessor(System.in, System.out)) |
| 322 | + .setCpuUsageBeforeGc(Duration.ofSeconds(10)) |
| 323 | + .build(); |
| 324 | + workerHandler.processRequests(); |
| 325 | + } catch (IOException e) { |
| 326 | + realStdErr.println(e); |
| 327 | + e.printStackTrace(realStdErr); |
| 328 | + return 1; |
| 329 | + } |
| 330 | + return 0; |
| 331 | + } |
| 332 | + |
| 333 | + private static int processRequestForWorker(List<String> argsList, PrintWriter pw, PrintStream ps) { |
| 334 | + try { |
| 335 | + processRequest(argsList); |
| 336 | + } catch (Exception e) { |
| 337 | + // In worker mode, if we catch an exception, don't throw it, just write it to the PrintStream |
| 338 | + ps.println(e); |
| 339 | + e.printStackTrace(pw); |
| 340 | + |
| 341 | + return 1; |
| 342 | + } |
| 343 | + |
| 344 | + return 0; |
| 345 | + } |
| 346 | + |
| 347 | + private static void processRequest(List<String> argsList) throws Exception { |
| 348 | + final String flagfilePrefix = "-flagfile="; |
279 | 349 | // Deal with param files. |
280 | | - if (args.length >= 1 && args[0].startsWith(flagfilePrefix)) { |
281 | | - argsList.clear(); |
| 350 | + if (argsList.size() >= 1 && argsList.get(0).startsWith(flagfilePrefix)) { |
| 351 | + List<String> argsListTmp = new ArrayList<>(); |
282 | 352 | // Check if the first argument is a flagfile |
283 | | - String flagfile = args[0].substring(flagfilePrefix.length()); |
| 353 | + String flagfile = argsList.get(0).substring(flagfilePrefix.length()); |
284 | 354 |
|
285 | 355 | // Read the flagfile |
286 | 356 | try (BufferedReader reader = Files.newBufferedReader(Path.of(flagfile))) { |
287 | 357 | String line; |
288 | 358 | while ((line = reader.readLine()) != null) { |
289 | | - argsList.add(line); |
| 359 | + argsListTmp.add(line); |
290 | 360 | } |
291 | 361 | } |
| 362 | + argsList = argsListTmp; |
292 | 363 | } |
293 | 364 |
|
| 365 | + Options options = new Options(); |
294 | 366 | JCommander.newBuilder().addObject(options).build().parse(argsList.toArray(new String[0])); |
295 | 367 |
|
296 | 368 | if (options.androidJar == null) { |
|
0 commit comments