| // 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)); |
| } |
| } |