Output changed inputs in the edge started events.

Bug: 323021988
Test: run soong builds and verify build.trace
Change-Id: Ib735c45fabd43867e145cda99c96430cd4c3fe41
diff --git a/frontend/frontend.pb b/frontend/frontend.pb
index 87685e8..7f396ad 100644
--- a/frontend/frontend.pb
+++ b/frontend/frontend.pb
Binary files differ
diff --git a/src/frontend.pb.h b/src/frontend.pb.h
index 86c1b76..8af9e72 100644
--- a/src/frontend.pb.h
+++ b/src/frontend.pb.h
@@ -165,6 +165,8 @@
     bool has_command_;
     bool console_;
     bool has_console_;
+    std::vector< std::string > changed_inputs_;
+    bool has_changed_inputs_;
 
     EdgeStarted() {
       has_id_ = false;
@@ -177,6 +179,7 @@
       has_command_ = false;
       has_console_ = false;
       console_ = static_cast< bool >(0);
+      has_changed_inputs_ = false;
     }
 
     EdgeStarted(const EdgeStarted&);
@@ -196,6 +199,10 @@
       WriteString(output__, 5, desc_);
       WriteString(output__, 6, command_);
       WriteVarint32(output__, 7, console_);
+      for (std::vector< std::string >::const_iterator it_ = changed_inputs_.begin();
+          it_ != changed_inputs_.end(); it_++) {
+        WriteString(output__, 8, *it_);
+      }
     }
 
     size_t ByteSizeLong() const {
@@ -213,6 +220,10 @@
       size += StringSize(desc_) + 1;
       size += StringSize(command_) + 1;
       size += VarintSizeBool(console_) + 1;
+      for (std::vector< std::string >::const_iterator it_ = changed_inputs_.begin();
+          it_ != changed_inputs_.end(); it_++) {
+        size += StringSize(*it_) + 1;
+      }
       return size;
     }
 
@@ -224,6 +235,7 @@
       desc_.clear();
       command_.clear();
       console_ = static_cast< bool >(0);
+      changed_inputs_.clear();
     }
 
     uint32_t* mutable_id() {
@@ -290,6 +302,18 @@
       has_console_ = true;
       console_ = value;
     }
+    std::vector< std::string >* mutable_changed_inputs() {
+      has_changed_inputs_ = true;
+      return &changed_inputs_;
+    }
+    void add_changed_inputs(const std::string& value) {
+      has_changed_inputs_ = true;
+      changed_inputs_.push_back(value);
+    }
+    void set_changed_inputs(const std::vector< std::string >& value) {
+      has_changed_inputs_ = true;
+      changed_inputs_ = value;
+    }
   };
 
   struct EdgeFinished {
diff --git a/src/frontend.proto b/src/frontend.proto
index dfdefb5..7d0d7a6 100644
--- a/src/frontend.proto
+++ b/src/frontend.proto
@@ -53,6 +53,8 @@
     optional string command = 6;
     // Edge uses console.
     optional bool console = 7;
+    // Changed inputs since last build.
+    repeated string changed_inputs = 8;
   }
 
   message EdgeFinished {
diff --git a/src/graph.cc b/src/graph.cc
index e4ca090..69d8e92 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -478,6 +478,7 @@
         (entry = build_log()->LookupByOutput(output->globalPath()))) {
       output_mtime = entry->mtime;
       used_restat = true;
+      output->set_restat_mtime(output_mtime);
     }
 
     if (output_mtime < most_recent_input->mtime()) {
diff --git a/src/graph.h b/src/graph.h
index c4dd3e4..b1e170e 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -237,6 +237,8 @@
   // Used in the inputs debug tool.
   bool InputsChecked() const { return inputs_checked_; }
   void MarkInputsChecked() { inputs_checked_ = true; }
+  TimeStamp restat_mtime() { return restat_mtime_; }
+  void set_restat_mtime(TimeStamp mtime) { restat_mtime_ = mtime; }
 
 private:
   HashedStr path_;
@@ -250,6 +252,9 @@
   /// If this value is >= 0, it represents a precomputed mtime for the node.
   TimeStamp precomputed_mtime_ = -1;
 
+  // For restat rule this is the mtime read from build_log.
+  TimeStamp restat_mtime_ = -1;
+
   /// Dirty is true when the underlying file is out-of-date.
   /// But note that Edge::outputs_ready_ is also used in judging which
   /// edges to build.
diff --git a/src/status.cc b/src/status.cc
index 1d809b4..eadb517 100644
--- a/src/status.cc
+++ b/src/status.cc
@@ -342,16 +342,29 @@
   edge_started->set_id(edge->id_);
   edge_started->set_start_time(start_time_millis);
 
+  int64_t earliest_output_time = INT64_MAX;
+  edge_started->mutable_outputs()->reserve(edge->outputs_.size());
+
+  for (vector<Node*>::iterator it = edge->outputs_.begin();
+       it != edge->outputs_.end(); ++it) {
+    edge_started->add_outputs((*it)->globalPath().h.data());
+    TimeStamp output_mtime = (*it)->mtime();
+    if ((*it)->restat_mtime() != -1) {
+      output_mtime = (*it)->restat_mtime();
+    }
+
+    if (output_mtime > 0 && output_mtime < earliest_output_time) {
+      earliest_output_time = output_mtime;
+    }
+  }
+
   edge_started->mutable_inputs()->reserve(edge->inputs_.size());
   for (vector<Node*>::iterator it = edge->inputs_.begin();
        it != edge->inputs_.end(); ++it) {
     edge_started->add_inputs((*it)->globalPath().h.data());
-  }
-
-  edge_started->mutable_outputs()->reserve(edge->inputs_.size());
-  for (vector<Node*>::iterator it = edge->outputs_.begin();
-       it != edge->outputs_.end(); ++it) {
-    edge_started->add_outputs((*it)->globalPath().h.data());
+    if (((*it)->mtime() > earliest_output_time) && (!((*it)->in_edge()) || (*it)->in_edge()->inputs_.empty())) {
+      edge_started->add_changed_inputs((*it)->globalPath().h.data());
+    }
   }
 
   const auto& proirity_suffix = config_.weight_list_path ? (" (priority: " + std::to_string(edge->priority()) + ")") : "";