| // 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.internal.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.MarkerInfoConsumerDataImpl; | |
| import com.android.tools.r8.utils.MarkerInfoImpl; | |
| import com.android.tools.r8.utils.Reporter; | |
| import com.android.tools.r8.utils.internal.ListUtils; | |
| import com.android.tools.r8.utils.timing.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; | |
| 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, Timing.empty()).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.usageMessage()); | |
| return; | |
| } | |
| run(command); | |
| } | |
| /** | |
| * Command-line entry to the extract marker tool. | |
| * | |
| * <p>See {@link ExtractMarkerCommand#usageMessage()} or run with {@code --help} for usage | |
| * information. | |
| */ | |
| public static void main(String[] args) throws Exception { | |
| ExceptionUtils.withMainProgramHandler(() -> run(args)); | |
| } | |
| } |