db: Store timestamps to the sqlite db.

Test: make
Bug: 137786053
Change-Id: I401e80e6168c717258644a37e9d8753c61248acd
diff --git a/src/db/models.h b/src/db/models.h
index f2ff651..0eac13f 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -306,9 +306,18 @@
     return static_cast<int>(last_rowid);
   }
 
-  // Returns the row ID that was inserted last.
   template <typename... Args>
   static bool Delete(DbHandle db, const std::string& sql, Args&&... args) {
+    return ExecuteOnce(db, sql, std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  static bool Update(DbHandle db, const std::string& sql, Args&&... args) {
+    return ExecuteOnce(db, sql, std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  static bool ExecuteOnce(DbHandle db, const std::string& sql, Args&&... args) {
     ScopedLockDb lock{db};
 
     DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
@@ -705,6 +714,7 @@
                                     p.temperature,
                                     p.trace_enabled,
                                     p.readahead_enabled,
+                                    p.intent_started_ns,
                                     p.total_time_ns,
                                     p.report_fully_drawn_ns)) {
       return std::nullopt;
@@ -718,13 +728,14 @@
                                                      AppLaunchHistoryModel::Temperature temperature,
                                                      bool trace_enabled,
                                                      bool readahead_enabled,
+                                                     std::optional<uint64_t> intent_started_ns,
                                                      std::optional<uint64_t> total_time_ns,
                                                      std::optional<uint64_t> report_fully_drawn_ns)
   {
     const char* sql = "INSERT INTO app_launch_histories (activity_id, temperature, trace_enabled, "
-                                                        "readahead_enabled, total_time_ns, "
-                                                        "report_fully_drawn_ns) "
-                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6);";
+                                                        "readahead_enabled, intent_started_ns, "
+                                                        "total_time_ns, report_fully_drawn_ns) "
+                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
 
     std::optional<int> inserted_row_id =
         DbQueryBuilder::Insert(db,
@@ -733,6 +744,7 @@
                                temperature,
                                trace_enabled,
                                readahead_enabled,
+                               intent_started_ns,
                                total_time_ns,
                                report_fully_drawn_ns);
     if (!inserted_row_id) {
@@ -745,17 +757,36 @@
     p.temperature = temperature;
     p.trace_enabled = trace_enabled;
     p.readahead_enabled = readahead_enabled;
+    p.intent_started_ns = intent_started_ns;
     p.total_time_ns = total_time_ns;
     p.report_fully_drawn_ns = report_fully_drawn_ns;
 
     return p;
   }
 
+  static bool UpdateReportFullyDrawn(DbHandle db,
+                                     int history_id,
+                                     std::optional<uint64_t> report_fully_drawn_ns)
+  {
+    const char* sql = "UPDATE app_launch_histories "
+                      "SET report_fully_drawn_ns = ?1 "
+                      "WHERE id = ?2;";
+
+    bool result = DbQueryBuilder::Update(db, sql, history_id, report_fully_drawn_ns);
+
+    if (!result) {
+      LOG(ERROR)<< "Failed to update history_id:"<< history_id
+                << ", report_fully_drawn_ns: " << report_fully_drawn_ns.value();
+    }
+    return result;
+  }
+
   int id;
   int activity_id;  // ActivityModel::id
   Temperature temperature = Temperature::kUninitialized;
   bool trace_enabled;
   bool readahead_enabled;
+  std::optional<uint64_t> intent_started_ns;
   std::optional<uint64_t> total_time_ns;
   std::optional<uint64_t> report_fully_drawn_ns;
 };
@@ -766,7 +797,14 @@
      << "temperature=" << static_cast<int>(p.temperature) << ","
      << "trace_enabled=" << p.trace_enabled << ","
      << "readahead_enabled=" << p.readahead_enabled << ","
-     << "total_time_ns=";
+     << "intent_started_ns=";
+  if (p.intent_started_ns) {
+    os << *p.intent_started_ns;
+  } else {
+    os << "(nullopt)";
+  }
+  os << ",";
+  os << "total_time_ns=";
   if (p.total_time_ns) {
     os << *p.total_time_ns;
   } else {
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index 434568a..3909bef 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -68,6 +68,14 @@
   std::optional<rxcpp::subscriber<int>> history_id_subscriber_;
   rxcpp::observable<int> history_id_observable_;
 
+  std::optional<uint64_t> intent_started_ns_;
+  std::optional<uint64_t> total_time_ns_;
+
+  // Used by kReportFullyDrawn to find the right history_id.
+  // We assume no interleaving between different sequences.
+  // This assumption is checked in the Java service code.
+  std::optional<uint64_t> recent_history_id_;
+
   // labeled as 'shared' due to rx not being able to handle move-only objects.
   // lifetime: in practice equivalent to unique_ptr.
   std::shared_ptr<prefetcher::ReadAhead> read_ahead_;
@@ -161,6 +169,12 @@
           rx_lifetime_ = StartTracing(std::move(component_name));
         }
 
+        if (event.timestamp_nanos >= 0) {
+          intent_started_ns_ = event.timestamp_nanos;
+        } else {
+          LOG(WARNING) << "Negative event timestamp: " << event.timestamp_nanos;
+        }
+
         break;
       }
       case Type::kIntentFailed:
@@ -219,6 +233,9 @@
         break;
       }
       case Type::kActivityLaunchFinished:
+        if (event.timestamp_nanos >= 0) {
+           total_time_ns_ = event.timestamp_nanos;
+        }
         RecordDbLaunchHistory();
         // Finish tracing and collect trace buffer.
         //
@@ -234,9 +251,14 @@
         AbortTrace();
         AbortReadAhead();
         break;
-      case Type::kReportFullyDrawn:
-        // TODO(yawanng) add handling of this event.
+      case Type::kReportFullyDrawn: {
+        if (!recent_history_id_) {
+          LOG(WARNING) << "Dangling kReportFullyDrawn event";
+          return;
+        }
+        UpdateReportFullyDrawn(event.timestamp_nanos, *recent_history_id_);
         break;
+      }
       default:
         DCHECK(false) << "invalid type: " << event;  // binder layer should've rejected this.
         LOG(ERROR) << "invalid type: " << event;  // binder layer should've rejected this.
@@ -426,11 +448,14 @@
     if (!history) {
       history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
           std::ios_base::failure("Failed to insert history id")));
+      recent_history_id_ = std::nullopt;
     } else {
       // Note: we must have already subscribed, or this value will disappear.
       LOG(VERBOSE) << "history_id_subscriber on_next history_id=" << history->id;
       history_id_subscriber_->on_next(history->id);
       history_id_subscriber_->on_completed();
+
+      recent_history_id_ = history->id;
     }
     history_id_subscriber_ = std::nullopt;
   }
@@ -468,8 +493,11 @@
                                       temp,
                                       IsTracing(),
                                       IsReadAhead(),
-                                      /*total_time_ns*/std::nullopt,
-                                      /*report_fully_drawn_ns*/std::nullopt);
+                                      intent_started_ns_,
+                                      total_time_ns_,
+                                      // ReportFullyDrawn event normally occurs after this. Need update later.
+                                      /* report_fully_drawn_ns= */ std::nullopt);
+    //Repo
     if (!alh) {
       LOG(WARNING) << "Failed to insert app_launch_histories row";
       return std::nullopt;
@@ -478,6 +506,26 @@
     LOG(VERBOSE) << "RecordDbLaunchHistory: " << *alh;
     return alh;
   }
+
+  void UpdateReportFullyDrawn(int history_id, uint64_t timestamp_ns) {
+    if (timestamp_ns < 0) {
+      LOG(WARNING) << "Invalid timestamp_ns: " << timestamp_ns;
+      return;
+    }
+
+    android::ScopedTrace trace{ATRACE_TAG_PACKAGE_MANAGER,
+                               "IorapNativeService::UpdateReportFullyDrawn"};
+    db::DbHandle db{db::SchemaModel::GetSingleton()};
+
+    bool result =
+        db::AppLaunchHistoryModel::UpdateReportFullyDrawn(db,
+                                                          history_id,
+                                                          timestamp_ns);
+
+    if (!result) {
+      LOG(WARNING) << "Failed to update app_launch_histories row";
+    }
+  }
 };
 
 // Convert callback pattern into reactive pattern.