Proto v2 for aquery proto output formats (--incompatible_proto_output_v2)

To try out this change, please include --incompatible_proto_output_v2 in your aquery invocation. Note that this flag is experimental and its API will change in the future.

The existing analysis.proto uses String as the format for messages' ids. This follows the convention, but results in a bloated output size. This CL introduces the 2nd version of the proto (analysis_v2.proto), which uses uint64 as ids instead. We've observed a significant improvement in output size.

RELNOTES: --incompatible_proto_output_v2: proto v2 for aquery proto output formats, which reduces the output size compared to v1. Note that the messages' ids in v2 are in uint64 instead of string like in v1.
PiperOrigin-RevId: 281709375
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 1a5477f..0481a4c 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -606,6 +606,7 @@
             "rules/repository/*.java",
             "skyframe/*.java",
             "skyframe/actiongraph/*.java",
+            "skyframe/actiongraph/v2/*.java",
         ],
         allow_empty = True,
         exclude = [
@@ -682,6 +683,7 @@
         "//src/main/java/com/google/devtools/common/options",
         "//src/main/java/com/google/devtools/common/options:invocation_policy",
         "//src/main/protobuf:analysis_java_proto",
+        "//src/main/protobuf:analysis_v2_java_proto",
         "//src/main/protobuf:extra_actions_base_java_proto",
         "//src/main/protobuf:invocation_policy_java_proto",
         "//src/main/protobuf:spawn_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/BUILD b/src/main/java/com/google/devtools/build/lib/query2/BUILD
index 63d5a91..957b880 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/BUILD
@@ -49,6 +49,7 @@
         "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
         "//src/main/java/com/google/devtools/common/options",
         "//src/main/protobuf:analysis_java_proto",
+        "//src/main/protobuf:analysis_v2_java_proto",
         "//src/main/protobuf:build_java_proto",
         "//third_party:guava",
         "//third_party:jsr305",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoV2OutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoV2OutputFormatterCallback.java
new file mode 100644
index 0000000..6919478
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoV2OutputFormatterCallback.java
@@ -0,0 +1,122 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.query2.aquery;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.devtools.build.lib.actions.CommandLineExpansionException;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
+import com.google.devtools.build.lib.skyframe.actiongraph.v2.ActionGraphDump;
+import com.google.protobuf.TextFormat;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Default output callback for aquery, prints proto output. */
+public class ActionGraphProtoV2OutputFormatterCallback extends AqueryThreadsafeCallback {
+
+  /** Defines the types of proto output this class can handle. */
+  public enum OutputType {
+    BINARY("proto"),
+    TEXT("textproto");
+
+    private final String formatName;
+
+    OutputType(String formatName) {
+      this.formatName = formatName;
+    }
+
+    public String formatName() {
+      return formatName;
+    }
+  }
+
+  private final OutputType outputType;
+  private final ActionGraphDump actionGraphDump;
+  private final AqueryActionFilter actionFilters;
+
+  ActionGraphProtoV2OutputFormatterCallback(
+      ExtendedEventHandler eventHandler,
+      AqueryOptions options,
+      OutputStream out,
+      SkyframeExecutor skyframeExecutor,
+      TargetAccessor<ConfiguredTargetValue> accessor,
+      OutputType outputType,
+      AqueryActionFilter actionFilters) {
+    super(eventHandler, options, out, skyframeExecutor, accessor);
+    this.outputType = outputType;
+    this.actionFilters = actionFilters;
+    this.actionGraphDump =
+        new ActionGraphDump(
+            options.includeCommandline,
+            options.includeArtifacts,
+            this.actionFilters,
+            options.includeParamFiles);
+  }
+
+  @Override
+  public String getName() {
+    return outputType.formatName();
+  }
+
+  @Override
+  public void processOutput(Iterable<ConfiguredTargetValue> partialResult)
+      throws IOException, InterruptedException {
+    try {
+      // Enabling includeParamFiles should enable includeCommandline by default.
+      options.includeCommandline |= options.includeParamFiles;
+
+      for (ConfiguredTargetValue configuredTargetValue : partialResult) {
+        actionGraphDump.dumpConfiguredTarget(configuredTargetValue);
+        if (options.useAspects) {
+          if (configuredTargetValue.getConfiguredTarget() instanceof RuleConfiguredTarget) {
+            for (AspectValue aspectValue : accessor.getAspectValues(configuredTargetValue)) {
+              actionGraphDump.dumpAspect(aspectValue, configuredTargetValue);
+            }
+          }
+        }
+      }
+    } catch (CommandLineExpansionException e) {
+      throw new IOException(e.getMessage());
+    }
+  }
+
+  @Override
+  public void close(boolean failFast) throws IOException {
+    if (!failFast && printStream != null) {
+      ActionGraphContainer actionGraphContainer = actionGraphDump.build();
+
+      // Write the data.
+      switch (outputType) {
+        case BINARY:
+          actionGraphContainer.writeTo(printStream);
+          break;
+        case TEXT:
+          TextFormat.print(actionGraphContainer, printStream);
+          break;
+        default:
+          throw new IllegalStateException("Unknown outputType " + outputType.formatName());
+      }
+    }
+  }
+
+  @VisibleForTesting
+  public ActionGraphContainer getProtoResult() {
+    return actionGraphDump.build();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
index 638c201..f004f83 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphQueryEnvironment.java
@@ -159,25 +159,45 @@
           BuildConfiguration hostConfiguration,
           @Nullable TransitionFactory<Rule> trimmingTransitionFactory,
           PackageManager packageManager) {
-    return ImmutableList.of(
-        new ActionGraphProtoOutputFormatterCallback(
-            eventHandler,
-            aqueryOptions,
-            out,
-            skyframeExecutor,
-            accessor,
-            OutputType.BINARY,
-            actionFilters),
-        new ActionGraphProtoOutputFormatterCallback(
-            eventHandler,
-            aqueryOptions,
-            out,
-            skyframeExecutor,
-            accessor,
-            OutputType.TEXT,
-            actionFilters),
-        new ActionGraphTextOutputFormatterCallback(
-            eventHandler, aqueryOptions, out, skyframeExecutor, accessor, actionFilters));
+    return aqueryOptions.protoV2
+        ? ImmutableList.of(
+            new ActionGraphProtoV2OutputFormatterCallback(
+                eventHandler,
+                aqueryOptions,
+                out,
+                skyframeExecutor,
+                accessor,
+                ActionGraphProtoV2OutputFormatterCallback.OutputType.BINARY,
+                actionFilters),
+            new ActionGraphProtoV2OutputFormatterCallback(
+                eventHandler,
+                aqueryOptions,
+                out,
+                skyframeExecutor,
+                accessor,
+                ActionGraphProtoV2OutputFormatterCallback.OutputType.TEXT,
+                actionFilters),
+            new ActionGraphTextOutputFormatterCallback(
+                eventHandler, aqueryOptions, out, skyframeExecutor, accessor, actionFilters))
+        : ImmutableList.of(
+            new ActionGraphProtoOutputFormatterCallback(
+                eventHandler,
+                aqueryOptions,
+                out,
+                skyframeExecutor,
+                accessor,
+                OutputType.BINARY,
+                actionFilters),
+            new ActionGraphProtoOutputFormatterCallback(
+                eventHandler,
+                aqueryOptions,
+                out,
+                skyframeExecutor,
+                accessor,
+                OutputType.TEXT,
+                actionFilters),
+            new ActionGraphTextOutputFormatterCallback(
+                eventHandler, aqueryOptions, out, skyframeExecutor, accessor, actionFilters));
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
index 82dc918..da45a89 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java
@@ -17,6 +17,7 @@
 import com.google.devtools.common.options.Option;
 import com.google.devtools.common.options.OptionDocumentationCategory;
 import com.google.devtools.common.options.OptionEffectTag;
+import com.google.devtools.common.options.OptionMetadataTag;
 
 /** Options class for aquery specific query options. */
 public class AqueryOptions extends CommonQueryOptions {
@@ -76,4 +77,18 @@
               + "Note: Specifying a target with --skyframe_state is currently not supported. "
               + "This flag is only available with --output=proto or --output=textproto.")
   public boolean queryCurrentSkyframeState;
+
+  @Option(
+      name = "incompatible_proto_output_v2",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.QUERY,
+      effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help =
+          "Whether aquery should print proto/textproto results with proto v2 "
+              + "(with ids in uint64 instead of string).")
+  public boolean protoV2;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/AqueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/AqueryCommand.java
index ed637be..8984e2d 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/AqueryCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/AqueryCommand.java
@@ -67,6 +67,13 @@
     // TODO(twerth): Reduce overlap with CqueryCommand.
     AqueryOptions aqueryOptions = options.getOptions(AqueryOptions.class);
     boolean queryCurrentSkyframeState = aqueryOptions.queryCurrentSkyframeState;
+    if (aqueryOptions.protoV2) {
+      env.getReporter()
+          .handle(
+              Event.warn(
+                  "Note that --incompatible_proto_output_v2 is still experimental "
+                      + "and its API will change in the future."));
+    }
 
     // When querying for the state of Skyframe, it's possible to omit the query expression.
     if (options.getResidue().isEmpty() && !queryCurrentSkyframeState) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java
new file mode 100644
index 0000000..2b4b1e0
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/ActionGraphDump.java
@@ -0,0 +1,283 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Action;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.ActionExecutionMetadata;
+import com.google.devtools.build.lib.actions.ActionKeyContext;
+import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.CommandAction;
+import com.google.devtools.build.lib.actions.CommandLineExpansionException;
+import com.google.devtools.build.lib.actions.ExecutionInfoSpecifier;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.packages.AspectDescriptor;
+import com.google.devtools.build.lib.query2.aquery.AqueryActionFilter;
+import com.google.devtools.build.lib.query2.aquery.AqueryUtils;
+import com.google.devtools.build.lib.rules.AliasConfiguredTarget;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Encapsulates necessary functionality to dump the current skyframe state of the action graph to
+ * proto format.
+ */
+public class ActionGraphDump {
+
+  private final ActionGraphContainer.Builder actionGraphBuilder = ActionGraphContainer.newBuilder();
+  private final ActionKeyContext actionKeyContext = new ActionKeyContext();
+  private final Set<String> actionGraphTargets;
+
+  private final KnownRuleClassStrings knownRuleClassStrings;
+  private final KnownArtifacts knownArtifacts;
+  private final KnownConfigurations knownConfigurations;
+  private final KnownNestedSets knownNestedSets;
+  private final KnownAspectDescriptors knownAspectDescriptors;
+  private final KnownRuleConfiguredTargets knownRuleConfiguredTargets;
+  private final AqueryActionFilter actionFilters;
+  private final boolean includeActionCmdLine;
+  private final boolean includeArtifacts;
+  private final boolean includeParamFiles;
+
+  private Map<String, Iterable<String>> paramFileNameToContentMap;
+
+  public ActionGraphDump(
+      boolean includeActionCmdLine,
+      boolean includeArtifacts,
+      AqueryActionFilter actionFilters,
+      boolean includeParamFiles) {
+    this(
+        /* actionGraphTargets= */ ImmutableList.of("..."),
+        includeActionCmdLine,
+        includeArtifacts,
+        actionFilters,
+        includeParamFiles);
+  }
+
+  public ActionGraphDump(
+      List<String> actionGraphTargets, boolean includeActionCmdLine, boolean includeArtifacts) {
+    this(
+        actionGraphTargets,
+        includeActionCmdLine,
+        includeArtifacts,
+        /* actionFilters= */ AqueryActionFilter.emptyInstance(),
+        /* includeParamFiles */ false);
+  }
+
+  public ActionGraphDump(
+      List<String> actionGraphTargets,
+      boolean includeActionCmdLine,
+      boolean includeArtifacts,
+      AqueryActionFilter actionFilters,
+      boolean includeParamFiles) {
+    this.actionGraphTargets = ImmutableSet.copyOf(actionGraphTargets);
+    this.includeActionCmdLine = includeActionCmdLine;
+    this.includeArtifacts = includeArtifacts;
+    this.actionFilters = actionFilters;
+    this.includeParamFiles = includeParamFiles;
+
+    knownRuleClassStrings = new KnownRuleClassStrings(actionGraphBuilder);
+    knownArtifacts = new KnownArtifacts(actionGraphBuilder);
+    knownConfigurations = new KnownConfigurations(actionGraphBuilder);
+    knownNestedSets = new KnownNestedSets(actionGraphBuilder, knownArtifacts);
+    knownAspectDescriptors = new KnownAspectDescriptors(actionGraphBuilder);
+    knownRuleConfiguredTargets = new KnownRuleConfiguredTargets(actionGraphBuilder,
+        knownRuleClassStrings);
+  }
+
+  public ActionKeyContext getActionKeyContext() {
+    return actionKeyContext;
+  }
+
+  private boolean includeInActionGraph(String labelString) {
+    if (actionGraphTargets.size() == 1
+        && Iterables.getOnlyElement(actionGraphTargets).equals("...")) {
+      return true;
+    }
+    return actionGraphTargets.contains(labelString);
+  }
+
+  private void dumpSingleAction(ConfiguredTarget configuredTarget, ActionAnalysisMetadata action)
+      throws CommandLineExpansionException {
+
+    // Store the content of param files.
+    if (includeParamFiles && (action instanceof ParameterFileWriteAction)) {
+      ParameterFileWriteAction parameterFileWriteAction = (ParameterFileWriteAction) action;
+
+      Iterable<String> fileContent = parameterFileWriteAction.getArguments();
+      String paramFileExecPath = action.getPrimaryOutput().getExecPathString();
+      getParamFileNameToContentMap().put(paramFileExecPath, fileContent);
+    }
+
+    if (!AqueryUtils.matchesAqueryFilters(action, actionFilters)) {
+      return;
+    }
+
+    while (configuredTarget instanceof AliasConfiguredTarget) {
+      configuredTarget = ((AliasConfiguredTarget) configuredTarget).getActual();
+    }
+
+    Preconditions.checkState(configuredTarget instanceof RuleConfiguredTarget);
+    RuleConfiguredTarget ruleConfiguredTarget = (RuleConfiguredTarget) configuredTarget;
+    AnalysisProtosV2.Action.Builder actionBuilder =
+        AnalysisProtosV2.Action.newBuilder()
+            .setMnemonic(action.getMnemonic())
+            .setTargetId(knownRuleConfiguredTargets.dataToId(ruleConfiguredTarget));
+
+    if (action instanceof ActionExecutionMetadata) {
+      ActionExecutionMetadata actionExecutionMetadata = (ActionExecutionMetadata) action;
+      actionBuilder
+          .setActionKey(actionExecutionMetadata.getKey(getActionKeyContext()))
+          .setDiscoversInputs(actionExecutionMetadata.discoversInputs());
+    }
+
+    // store environment
+    if (action instanceof SpawnAction) {
+      SpawnAction spawnAction = (SpawnAction) action;
+      // TODO(twerth): This handles the fixed environment. We probably want to output the inherited
+      // environment as well.
+      Map<String, String> fixedEnvironment = spawnAction.getEnvironment().getFixedEnv().toMap();
+      for (Map.Entry<String, String> environmentVariable : fixedEnvironment.entrySet()) {
+        AnalysisProtosV2.KeyValuePair.Builder keyValuePairBuilder =
+            AnalysisProtosV2.KeyValuePair.newBuilder();
+        keyValuePairBuilder
+            .setKey(environmentVariable.getKey())
+            .setValue(environmentVariable.getValue());
+        actionBuilder.addEnvironmentVariables(keyValuePairBuilder.build());
+      }
+    }
+
+    if (includeActionCmdLine && action instanceof CommandAction) {
+      CommandAction commandAction = (CommandAction) action;
+      actionBuilder.addAllArguments(commandAction.getArguments());
+    }
+
+    // Include the content of param files in output.
+    if (includeParamFiles) {
+      // Assumption: if an Action takes a params file as an input, it will be used
+      // to provide params to the command.
+      for (Artifact input : action.getInputs()) {
+        String inputFileExecPath = input.getExecPathString();
+        if (getParamFileNameToContentMap().containsKey(inputFileExecPath)) {
+          AnalysisProtosV2.ParamFile paramFile =
+              AnalysisProtosV2.ParamFile.newBuilder()
+                  .setExecPath(inputFileExecPath)
+                  .addAllArguments(getParamFileNameToContentMap().get(inputFileExecPath))
+                  .build();
+          actionBuilder.addParamFiles(paramFile);
+        }
+      }
+    }
+
+    if (action instanceof ExecutionInfoSpecifier) {
+      ExecutionInfoSpecifier executionInfoSpecifier = (ExecutionInfoSpecifier) action;
+      for (Map.Entry<String, String> info : executionInfoSpecifier.getExecutionInfo().entrySet()) {
+        actionBuilder.addExecutionInfo(
+            AnalysisProtosV2.KeyValuePair.newBuilder()
+                .setKey(info.getKey())
+                .setValue(info.getValue()));
+      }
+    }
+
+    ActionOwner actionOwner = action.getOwner();
+    if (actionOwner != null) {
+      BuildEvent event = actionOwner.getConfiguration();
+      actionBuilder.setConfigurationId(knownConfigurations.dataToId(event));
+
+      // Store aspects.
+      // Iterate through the aspect path and dump the aspect descriptors.
+      // In the case of aspect-on-aspect, AspectDescriptors are listed in topological order
+      // of the configured target graph.
+      // e.g. [A, B] would imply that aspect A is applied on top of aspect B.
+      for (AspectDescriptor aspectDescriptor : actionOwner.getAspectDescriptors().reverse()) {
+        actionBuilder.addAspectDescriptorIds(knownAspectDescriptors.dataToId(aspectDescriptor));
+      }
+    }
+
+    if (includeArtifacts) {
+      // Store inputs
+      Iterable<Artifact> inputs = action.getInputs();
+      if (!(inputs instanceof NestedSet)) {
+        inputs = NestedSetBuilder.wrap(Order.STABLE_ORDER, inputs);
+      }
+      NestedSetView<Artifact> nestedSetView = new NestedSetView<>((NestedSet<Artifact>) inputs);
+
+      if (nestedSetView.directs().size() > 0 || nestedSetView.transitives().size() > 0) {
+        actionBuilder.addInputDepSetIds(knownNestedSets.dataToId(nestedSetView));
+      }
+
+      // store outputs
+      for (Artifact artifact : action.getOutputs()) {
+        actionBuilder.addOutputIds(knownArtifacts.dataToId(artifact));
+      }
+    }
+
+    actionGraphBuilder.addActions(actionBuilder.build());
+  }
+
+  public void dumpAspect(AspectValue aspectValue, ConfiguredTargetValue configuredTargetValue)
+      throws CommandLineExpansionException {
+    ConfiguredTarget configuredTarget = configuredTargetValue.getConfiguredTarget();
+    if (!includeInActionGraph(configuredTarget.getLabel().toString())) {
+      return;
+    }
+    for (int i = 0; i < aspectValue.getNumActions(); i++) {
+      Action action = aspectValue.getAction(i);
+      dumpSingleAction(configuredTarget, action);
+    }
+  }
+
+  public void dumpConfiguredTarget(ConfiguredTargetValue configuredTargetValue)
+      throws CommandLineExpansionException {
+    ConfiguredTarget configuredTarget = configuredTargetValue.getConfiguredTarget();
+    if (!includeInActionGraph(configuredTarget.getLabel().toString())) {
+      return;
+    }
+    List<ActionAnalysisMetadata> actions = configuredTargetValue.getActions();
+    for (ActionAnalysisMetadata action : actions) {
+      dumpSingleAction(configuredTarget, action);
+    }
+  }
+
+  public ActionGraphContainer build() {
+    return actionGraphBuilder.build();
+  }
+
+  /** Lazy initialization of paramFileNameToContentMap. */
+  private Map<String, Iterable<String>> getParamFileNameToContentMap() {
+    if (paramFileNameToContentMap == null) {
+      paramFileNameToContentMap = new HashMap<>();
+    }
+    return paramFileNameToContentMap;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/BaseCache.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/BaseCache.java
new file mode 100644
index 0000000..ef22f9d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/BaseCache.java
@@ -0,0 +1,58 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Basic class to abstract action graph cache functionality.
+ */
+abstract class BaseCache<K, P> {
+  private final Map<K, Long> cache = new HashMap<>();
+  protected final ActionGraphContainer.Builder actionGraphBuilder;
+
+  BaseCache(ActionGraphContainer.Builder actionGraphBuilder) {
+    this.actionGraphBuilder = actionGraphBuilder;
+  }
+
+  private long generateNextId() {
+    return cache.size();
+  }
+
+  protected K transformToKey(K data) {
+    // In most cases, the data is the key but it can be overridden by subclasses.
+    return data;
+  }
+
+  Long dataToId(K data) {
+    K key = transformToKey(data);
+    Long id = cache.get(key);
+    if (id == null) {
+      // Note that this cannot be replaced by computeIfAbsent since createProto is a recursive
+      // operation for the case of nested sets which will call dataToId on the same object and thus
+      // computeIfAbsent again.
+      id = generateNextId();
+      cache.put(key, id);
+      P proto = createProto(data, id);
+      addToActionGraphBuilder(proto);
+    }
+    return id;
+  }
+
+  abstract P createProto(K key, Long id);
+
+  abstract void addToActionGraphBuilder(P proto);
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownArtifacts.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownArtifacts.java
new file mode 100644
index 0000000..8b4989f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownArtifacts.java
@@ -0,0 +1,40 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+
+/** Cache for Artifacts in the action graph. */
+public class KnownArtifacts extends BaseCache<Artifact, AnalysisProtosV2.Artifact> {
+
+  KnownArtifacts(ActionGraphContainer.Builder actionGraphBuilder) {
+    super(actionGraphBuilder);
+  }
+
+  @Override
+  AnalysisProtosV2.Artifact createProto(Artifact artifact, Long id) {
+    return AnalysisProtosV2.Artifact.newBuilder()
+        .setId(id)
+        .setExecPath(artifact.getExecPathString())
+        .setIsTreeArtifact(artifact.isTreeArtifact())
+        .build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(AnalysisProtosV2.Artifact artifactProto) {
+    actionGraphBuilder.addArtifacts(artifactProto);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownAspectDescriptors.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownAspectDescriptors.java
new file mode 100644
index 0000000..46ef651
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownAspectDescriptors.java
@@ -0,0 +1,49 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.KeyValuePair;
+import com.google.devtools.build.lib.packages.AspectDescriptor;
+import java.util.Map;
+
+/** Cache for AspectDescriptors in the action graph. */
+public class KnownAspectDescriptors
+    extends BaseCache<AspectDescriptor, AnalysisProtosV2.AspectDescriptor> {
+
+  KnownAspectDescriptors(ActionGraphContainer.Builder actionGraphBuilder) {
+    super(actionGraphBuilder);
+  }
+
+  @Override
+  AnalysisProtosV2.AspectDescriptor createProto(AspectDescriptor aspectDescriptor, Long id) {
+    AnalysisProtosV2.AspectDescriptor.Builder aspectDescriptorBuilder =
+        AnalysisProtosV2.AspectDescriptor.newBuilder()
+            .setId(id)
+            .setName(aspectDescriptor.getAspectClass().getName());
+    for (Map.Entry<String, String> parameter :
+        aspectDescriptor.getParameters().getAttributes().entries()) {
+      KeyValuePair.Builder keyValuePairBuilder = KeyValuePair.newBuilder();
+      keyValuePairBuilder.setKey(parameter.getKey()).setValue(parameter.getValue());
+      aspectDescriptorBuilder.addParameters(keyValuePairBuilder.build());
+    }
+    return aspectDescriptorBuilder.build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(AnalysisProtosV2.AspectDescriptor aspectDescriptorProto) {
+    actionGraphBuilder.addAspectDescriptors(aspectDescriptorProto);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownConfigurations.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownConfigurations.java
new file mode 100644
index 0000000..ac26714
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownConfigurations.java
@@ -0,0 +1,44 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.Configuration;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+
+/** Cache for BuildConfigurations in the action graph. */
+public class KnownConfigurations extends BaseCache<BuildEvent, Configuration> {
+
+  KnownConfigurations(ActionGraphContainer.Builder actionGraphBuilder) {
+    super(actionGraphBuilder);
+  }
+
+  @Override
+  Configuration createProto(BuildEvent config, Long id) {
+    BuildEventStreamProtos.Configuration configProto =
+        config.asStreamProto(/*context=*/ null).getConfiguration();
+    return Configuration.newBuilder()
+        .setChecksum(config.getEventId().asStreamProto().getConfiguration().getId())
+        .setMnemonic(configProto.getMnemonic())
+        .setPlatformName(configProto.getPlatformName())
+        .setId(id)
+        .build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(Configuration configurationProto) {
+    actionGraphBuilder.addConfiguration(configurationProto);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownNestedSets.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownNestedSets.java
new file mode 100644
index 0000000..0031b8f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownNestedSets.java
@@ -0,0 +1,55 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.DepSetOfFiles;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
+
+/** Cache for NestedSets in the action graph. */
+public class KnownNestedSets extends BaseCache<Object, DepSetOfFiles> {
+  private final KnownArtifacts knownArtifacts;
+
+  KnownNestedSets(ActionGraphContainer.Builder actionGraphBuilder, KnownArtifacts knownArtifacts) {
+    super(actionGraphBuilder);
+    this.knownArtifacts = knownArtifacts;
+  }
+
+  @Override
+  protected Object transformToKey(Object nestedSetViewObject) {
+    NestedSetView<?> nestedSetView = (NestedSetView<?>) nestedSetViewObject;
+    // The NestedSet is identified by their raw 'children' object since multiple NestedSetViews
+    // can point to the same object.
+    return nestedSetView.identifier();
+  }
+
+  @Override
+  DepSetOfFiles createProto(Object nestedSetViewObject, Long id) {
+    NestedSetView<?> nestedSetView = (NestedSetView) nestedSetViewObject;
+    DepSetOfFiles.Builder depSetBuilder = DepSetOfFiles.newBuilder().setId(id);
+    for (NestedSetView<?> transitiveNestedSet : nestedSetView.transitives()) {
+      depSetBuilder.addTransitiveDepSetIds(this.dataToId(transitiveNestedSet));
+    }
+    for (Object directArtifact : nestedSetView.directs()) {
+      depSetBuilder.addDirectArtifactIds(knownArtifacts.dataToId((Artifact) directArtifact));
+    }
+    return depSetBuilder.build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(DepSetOfFiles depSetOfFilesProto) {
+    actionGraphBuilder.addDepSetOfFiles(depSetOfFilesProto);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleClassStrings.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleClassStrings.java
new file mode 100644
index 0000000..3a7765f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleClassStrings.java
@@ -0,0 +1,35 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.RuleClass;
+
+/** Cache for RuleClassStrings in the action graph. */
+public class KnownRuleClassStrings extends BaseCache<String, RuleClass> {
+
+  KnownRuleClassStrings(ActionGraphContainer.Builder actionGraphBuilder) {
+    super(actionGraphBuilder);
+  }
+
+  @Override
+  RuleClass createProto(String ruleClassString, Long id) {
+    return RuleClass.newBuilder().setId(id).setName(ruleClassString).build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(RuleClass ruleClassProto) {
+    actionGraphBuilder.addRuleClasses(ruleClassProto);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleConfiguredTargets.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleConfiguredTargets.java
new file mode 100644
index 0000000..b494bfc
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/v2/KnownRuleConfiguredTargets.java
@@ -0,0 +1,48 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+package com.google.devtools.build.lib.skyframe.actiongraph.v2;
+
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.ActionGraphContainer;
+import com.google.devtools.build.lib.analysis.AnalysisProtosV2.Target;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.cmdline.Label;
+
+/** Cache for RuleConfiguredTargets in the action graph. */
+public class KnownRuleConfiguredTargets extends BaseCache<RuleConfiguredTarget, Target> {
+
+  private final KnownRuleClassStrings knownRuleClassStrings;
+
+  KnownRuleConfiguredTargets(
+      ActionGraphContainer.Builder actionGraphBuilder,
+      KnownRuleClassStrings knownRuleClassStrings) {
+    super(actionGraphBuilder);
+    this.knownRuleClassStrings = knownRuleClassStrings;
+  }
+
+  @Override
+  Target createProto(RuleConfiguredTarget ruleConfiguredTarget, Long id) {
+    Label label = ruleConfiguredTarget.getLabel();
+    String ruleClassString = ruleConfiguredTarget.getRuleClassString();
+    Target.Builder targetBuilder = Target.newBuilder().setId(id).setLabel(label.toString());
+    if (ruleClassString != null) {
+      targetBuilder.setRuleClassId(knownRuleClassStrings.dataToId(ruleClassString));
+    }
+    return targetBuilder.build();
+  }
+
+  @Override
+  void addToActionGraphBuilder(Target targetProto) {
+    actionGraphBuilder.addTargets(targetProto);
+  }
+}
diff --git a/src/main/protobuf/BUILD b/src/main/protobuf/BUILD
index 311e448..16b967c 100644
--- a/src/main/protobuf/BUILD
+++ b/src/main/protobuf/BUILD
@@ -1,7 +1,4 @@
 load("@rules_java//java:defs.bzl", "java_proto_library")
-
-package(default_visibility = ["//visibility:public"])
-
 load("//tools/build_rules:genproto.bzl", "cc_grpc_library")
 load("//tools/build_rules:utilities.bzl", "java_library_srcs")
 load("//third_party/protobuf/3.6.1:protobuf.bzl", "py_proto_library")
@@ -9,6 +6,8 @@
 load("@rules_cc//cc:defs.bzl", "cc_proto_library")
 load("@rules_proto//proto:defs.bzl", "proto_library")
 
+package(default_visibility = ["//visibility:public"])
+
 exports_files(
     ["execution_statitics.proto"],
     visibility = [
@@ -74,6 +73,30 @@
     deps = [":analysis_java_proto"],
 )
 
+proto_library(
+    name = "analysis_v2_proto",
+    srcs = ["analysis_v2.proto"],
+    deps = [":build_proto"],
+)
+
+py_proto_library(
+    name = "analysis_v2_py_proto",
+    srcs = ["analysis_v2.proto"],
+    default_runtime = "//third_party/protobuf:protobuf_python",
+    protoc = "//third_party/protobuf:protoc",
+    deps = [":build_pb_py"],
+)
+
+java_proto_library(
+    name = "analysis_v2_java_proto",
+    deps = [":analysis_v2_proto"],
+)
+
+java_library_srcs(
+    name = "analysis_v2_java_proto_srcs",
+    deps = [":analysis_v2_java_proto"],
+)
+
 # This new option tagging method is in flux while being applied to the options
 # in the Bazel code base. The visibility should not be changed to allow external
 # dependencies until the interface has stabilized and can commit to maintaining
@@ -201,6 +224,7 @@
     name = "dist_jars",
     srcs = [s + "_java_proto_srcs" for s in FILES] + [
         ":analysis_java_proto_srcs",
+        ":analysis_v2_java_proto_srcs",
         ":command_line_java_proto_srcs",
         ":command_server_java_grpc_srcs",
         ":option_filters_java_proto_srcs",
diff --git a/src/main/protobuf/analysis_v2.proto b/src/main/protobuf/analysis_v2.proto
new file mode 100644
index 0000000..eaba2a6
--- /dev/null
+++ b/src/main/protobuf/analysis_v2.proto
@@ -0,0 +1,200 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+syntax = "proto3";
+
+package analysis;
+
+import "src/main/protobuf/build.proto";
+
+option java_package = "com.google.devtools.build.lib.analysis";
+option java_outer_classname = "AnalysisProtosV2";
+
+// Container for the action graph properties.
+message ActionGraphContainer {
+  repeated Artifact artifacts = 1;
+  repeated Action actions = 2;
+  repeated Target targets = 3;
+  repeated DepSetOfFiles dep_set_of_files = 4;
+  repeated Configuration configuration = 5;
+  repeated AspectDescriptor aspect_descriptors = 6;
+  repeated RuleClass rule_classes = 7;
+}
+
+// Represents a single artifact, whether it's a source file or a derived output
+// file.
+message Artifact {
+  // Identifier for this artifact; this is a uint64, only valid for this
+  // particular dump of the analysis.
+  uint64 id = 1;
+
+  // The relative path of the file within the execution root.
+  string exec_path = 2;
+
+  // True iff the artifact is a tree artifact, i.e. the above exec_path refers
+  // a directory.
+  bool is_tree_artifact = 3;
+}
+
+// Represents a single action, which is a function from Artifact(s) to
+// Artifact(s).
+message Action {
+  // The target that was responsible for the creation of the action.
+  uint64 target_id = 1;
+
+  // The aspects that were responsible for the creation of the action (if any).
+  // In the case of aspect-on-aspect, AspectDescriptors are listed in
+  // topological order of the dependency graph.
+  // e.g. [A, B] would imply that aspect A is applied on top of aspect B.
+  repeated uint64 aspect_descriptor_ids = 2;
+
+  // Encodes all significant behavior that might affect the output. The key
+  // must change if the work performed by the execution of this action changes.
+  // Note that the key doesn't include checksums of the input files.
+  string action_key = 3;
+
+  // The mnemonic for this kind of action.
+  string mnemonic = 4;
+
+  // The configuration under which this action is executed.
+  uint64 configuration_id = 5;
+
+  // The command line arguments of the action. This will be only set if
+  // explicitly requested.
+  repeated string arguments = 6;
+
+  // The list of environment variables to be set before executing the command.
+  repeated KeyValuePair environment_variables = 7;
+
+  // The set of input dep sets that the action depends upon. If the action does
+  // input discovery, the contents of this set might change during execution.
+  repeated uint64 input_dep_set_ids = 8;
+
+  // The list of Artifact IDs that represent the output files that this action
+  // will generate.
+  repeated uint64 output_ids = 9;
+
+  // True iff the action does input discovery during execution.
+  bool discovers_inputs = 10;
+
+  // Execution info for the action.  Remote execution services may use this
+  // information to modify the execution environment, but actions will
+  // generally not be aware of it.
+  repeated KeyValuePair execution_info = 11;
+
+  // The list of param files. This will be only set if explicitly requested.
+  repeated ParamFile param_files = 12;
+}
+
+// Represents a single target (without configuration information) that is
+// associated with an action.
+message Target {
+  // Identifier for this target; this is a uint64, only valid for this
+  // particular dump of the analysis.
+  uint64 id = 1;
+
+  // Label of the target, e.g. //foo:bar.
+  string label = 2;
+
+  // Class of the rule.
+  uint64 rule_class_id = 3;
+}
+
+message RuleClass {
+  // Identifier for this rule class; this is a uint64, only valid for
+  // this particular dump of the analysis.
+  uint64 id = 1;
+
+  // Name of the rule class, e.g. cc_library.
+  string name = 2;
+}
+
+// Represents an invocation specific descriptor of an aspect.
+message AspectDescriptor {
+  // Identifier for this aspect descriptor; this is a uint64, only valid
+  // for the particular dump of the analysis.
+  uint64 id = 1;
+
+  // The name of the corresponding aspect. For native aspects, it's the Java
+  // class name, for Skylark aspects it's the bzl file followed by a % sign
+  // followed by the name of the aspect.
+  string name = 2;
+
+  // The list of parameters bound to a particular invocation of that aspect on
+  // a target. Note that aspects can be executed multiple times on the same
+  // target in different order.
+  repeated KeyValuePair parameters = 3;
+}
+
+message DepSetOfFiles {
+  // Identifier for this named set of files; this is a uint64, only
+  // valid for the particular dump of the analysis.
+  uint64 id = 1;
+
+  // Other transitively included named set of files.
+  repeated uint64 transitive_dep_set_ids = 2;
+
+  // The list of input artifact IDs that are immediately contained in this set.
+  repeated uint64 direct_artifact_ids = 3;
+}
+
+message Configuration {
+  // Identifier for this configuration; this is a uint64, only valid for
+  // the particular dump of the analysis.
+  uint64 id = 1;
+
+  // The mnemonic representing the build configuration.
+  string mnemonic = 2;
+
+  // The platform string.
+  string platform_name = 3;
+
+  // The checksum representation of the configuration options;
+  string checksum = 4;
+}
+
+message KeyValuePair {
+  // The variable name.
+  string key = 1;
+
+  // The variable value.
+  string value = 2;
+}
+
+message ConfiguredTarget {
+  // The target. We use blaze_query.Target defined in build.proto instead of
+  // the Target defined in this file because blaze_query.Target is much heavier
+  // and will output proto results similar to what users are familiar with from
+  // regular blaze query.
+  blaze_query.Target target = 1;
+
+  // The configuration
+  Configuration configuration = 2;
+}
+
+// Container for cquery results
+message CqueryResult {
+  // All the configuredtargets returns by cquery
+  repeated ConfiguredTarget results = 1;
+}
+
+// Content of a param file.
+message ParamFile {
+  // The exec path of the param file artifact.
+  string exec_path = 1;
+
+  // The arguments in the param file.
+  // Each argument corresponds to a line in the param file.
+  repeated string arguments = 2;
+}
diff --git a/src/test/shell/integration/aquery_test.sh b/src/test/shell/integration/aquery_test.sh
index aac6b59..5952164 100755
--- a/src/test/shell/integration/aquery_test.sh
+++ b/src/test/shell/integration/aquery_test.sh
@@ -1060,4 +1060,49 @@
   assert_only_action_foo_textproto output
 }
 
+function test_basic_aquery_proto_v2() {
+  local pkg="${FUNCNAME[0]}"
+  mkdir -p "$pkg" || fail "mkdir -p $pkg"
+  cat > "$pkg/BUILD" <<'EOF'
+genrule(
+    name = "bar",
+    srcs = ["dummy.txt"],
+    outs = ["bar_out.txt"],
+    cmd = "echo unused > $(OUTS)",
+)
+EOF
+  bazel aquery --output=proto "//$pkg:bar" > output_v1 || fail "Expected success"
+  bazel clean
+
+  bazel aquery --incompatible_proto_output_v2 --output=proto "//$pkg:bar" > output_v2 \
+    || fail "Expected success"
+  [[ output_v1 != output_v2 ]] || fail "proto content should be different."
+}
+
+function test_basic_aquery_textproto_v2() {
+  local pkg="${FUNCNAME[0]}"
+  mkdir -p "$pkg" || fail "mkdir -p $pkg"
+  cat > "$pkg/BUILD" <<'EOF'
+genrule(
+    name = "bar",
+    srcs = ["dummy.txt"],
+    outs = ["bar_out.txt"],
+    cmd = "echo unused > $(OUTS)",
+)
+EOF
+  echo "hello aquery" > "$pkg/in.txt"
+  bazel aquery --incompatible_proto_output_v2 --output=proto "//$pkg:bar" \
+    || fail "Expected success"
+
+  bazel aquery --incompatible_proto_output_v2 --output=textproto "//$pkg:bar" > output 2> "$TEST_log" \
+    || fail "Expected success"
+  cat output >> "$TEST_log"
+  # Verify than ids come in integers instead of strings.
+  assert_contains "id: 1" output
+  assert_not_contains "id: \"1\"" output
+  assert_contains "exec_path: \"$pkg/dummy.txt\"" output
+  assert_contains "nemonic: \"Genrule\"" output
+  assert_contains "mnemonic: \".*-fastbuild\"" output
+  assert_contains "echo unused" output
+}
 run_suite "${PRODUCT_NAME} action graph query tests"