blob: 99080f9d9155766d3bca17ca8241017065bdde4d [file] [log] [blame]
// Copyright (c) 2017, the Rex project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
import static com.android.tools.r8.utils.StringUtils.quote;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MarkerInfoConsumerDataImpl;
import com.android.tools.r8.utils.MarkerInfoImpl;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
/**
* A tool to extract markers generated by the R8 compiler and related tools.
*
* <p>The tool is run by defining a consumer and then building the command, such as:
*
* <pre>
* ExtractMarker.run(ExtractMarkerCommand.builder()
* .addProgramFiles(inputPathA, inputPathB)
* .setMarkerInfoConsumer(new MyInfoConsumer())
* .build());
* </pre>
*/
@KeepForApi
public class ExtractMarker {
private static class MarkerInfoPrintConsumer implements MarkerInfoConsumer {
private final PrintStream stream;
public MarkerInfoPrintConsumer(PrintStream stream) {
this.stream = stream;
}
private void printRow(Origin inputOrigin, String rawMarker) {
stream.print(inputOrigin.toString());
stream.print(": ");
stream.print(rawMarker);
stream.println();
}
@Override
public void acceptMarkerInfo(MarkerInfoConsumerData data) {
if (data.hasMarkers()) {
for (MarkerInfo marker : data.getMarkers()) {
printRow(data.getInputOrigin(), marker.getRawEncoding());
}
} else {
printRow(data.getInputOrigin(), quote("no marker"));
}
}
@Override
public void finished() {}
}
private static class InterceptedException extends RuntimeException {
private final CompilationFailedException compilationFailedException;
private InterceptedException(CompilationFailedException e) {
this.compilationFailedException = e;
}
}
private static Collection<Marker> extractMarker(AndroidApp app) throws IOException {
InternalOptions options = new InternalOptions();
options.skipReadingDexCode = true;
options.setMinApiLevel(AndroidApiLevel.P);
DexApplication dexApp = new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
return dexApp.dexItemFactory.extractMarkers();
}
private static void extractForConsumer(
MarkerInfoConsumer consumer, Reporter reporter, Origin origin, AndroidApp.Builder builder) {
List<Marker> markers = new ArrayList<>();
try {
ExceptionUtils.withCompilationHandler(
reporter, () -> markers.addAll(extractMarker(builder.build())));
} catch (CompilationFailedException e) {
throw new InterceptedException(e);
}
// Ensure the markers are sorted, so we have deterministic callback/print order.
markers.sort(Comparator.comparing(Marker::toString));
List<MarkerInfo> infos = ListUtils.map(markers, MarkerInfoImpl::new);
consumer.acceptMarkerInfo(new MarkerInfoConsumerDataImpl(origin, infos));
}
/**
* Main API entry for the extract marker tool.
*
* @param command Extract marker command specification.
*/
public static void run(ExtractMarkerCommand command) throws CompilationFailedException {
MarkerInfoConsumer consumer = command.getMarkerInfoConsumer();
Reporter reporter = new Reporter(command.getDiagnosticsHandler());
try {
command.forEachEntry(
(path, origin) ->
extractForConsumer(
consumer, reporter, origin, AndroidApp.builder().addProgramFile(path)),
(data, origin) ->
extractForConsumer(
consumer, reporter, origin, AndroidApp.builder().addDexProgramData(data, origin)),
(data, origin) ->
extractForConsumer(
consumer,
reporter,
origin,
AndroidApp.builder().addClassProgramData(data, origin)));
} catch (InterceptedException e) {
throw e.compilationFailedException;
}
}
private static void run(String[] args) throws CompilationFailedException {
PrintStream out = System.out;
ExtractMarkerCommand.Builder builder = ExtractMarkerCommand.parse(args);
MarkerInfoConsumer consumer = new MarkerInfoPrintConsumer(out);
ExtractMarkerCommand command = builder.setMarkerInfoConsumer(consumer).build();
if (command.isPrintHelp()) {
System.out.println(ExtractMarkerCommand.USAGE_MESSAGE);
return;
}
run(command);
}
/**
* Command-line entry to the extract marker tool.
*
* <p>See {@link ExtractMarkerCommand#USAGE_MESSAGE} or run with {@code --help} for usage
* information.
*/
public static void main(String[] args) throws Exception {
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
}