perfetto: Keep a ring buffer of traces per-app
Use the property 'iorapd.perfetto.max_traces' to determine how many
maximum traces there should be per-app. Excess traces are deleted
from disk and db.
In addition, associate each new perfetto_trace.pb in the raw_traces
table with the app_launch_histories table.
Bug: 141378186
Test: manual
Change-Id: I4e9d2e01cf5ac1360c55de5bf65c554fb865fa4c
diff --git a/src/db/models.h b/src/db/models.h
index ed6c16d..f2ff651 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -22,6 +22,7 @@
#include <string>
#include <sstream>
#include <type_traits>
+#include <vector>
#include <sqlite3.h>
@@ -112,6 +113,7 @@
return db_;
}
+ // Successive BindAll calls *do not* start back at the 0th bind position.
template <typename T, typename ... Args>
void BindAll(T&& arg, Args&&... args) {
Bind(std::forward<T>(arg));
@@ -177,10 +179,13 @@
return true;
}
+ // Successive ColumnAll calls start at the 0th column again.
template <typename T, typename ... Args>
void ColumnAll(T& first, Args&... rest) {
Column(first);
ColumnAll(rest...);
+ // Reset column counter back to 0
+ column_counter_ = 0;
}
void ColumnAll() {}
@@ -221,6 +226,15 @@
void Column(std::string& value) {
const unsigned char* text = sqlite3_column_text(stmt_, column_counter_++);
+
+ DCHECK(text != nullptr) << "Column should be marked NOT NULL, otherwise use optional<string>";
+ if (text == nullptr) {
+ LOG(ERROR) << "Got NULL back for column " << column_counter_-1
+ << "; is this column marked NOT NULL?";
+ value = "(((null)))"; // Don't segfault, keep going.
+ return;
+ }
+
value = std::string{reinterpret_cast<const char*>(text)};
}
@@ -292,6 +306,20 @@
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) {
+ ScopedLockDb lock{db};
+
+ DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
+
+ if (!stmt.Step(SQLITE_DONE)) {
+ return false;
+ }
+
+ return true;
+ }
+
template <typename... Args>
static bool SelectOnce(DbStatement& stmt, Args&... args) {
int rc = stmt.Step();
@@ -755,6 +783,76 @@
return os;
}
+class RawTraceModel : public Model {
+ protected:
+ RawTraceModel(DbHandle db) : Model{db} {
+ }
+
+ public:
+
+ // Return raw_traces, sorted ascending by the id.
+ static std::vector<RawTraceModel> SelectByPackageNameActivityName(DbHandle db,
+ std::string package_name,
+ std::string activity_name) {
+ ScopedLockDb lock{db};
+
+ const char* sql =
+ "SELECT raw_traces.id, raw_traces.history_id, raw_traces.file_path "
+ "FROM raw_traces "
+ "INNER JOIN app_launch_histories ON raw_traces.history_id = app_launch_histories.id "
+ "INNER JOIN activities ON activities.id = app_launch_histories.activity_id "
+ "INNER JOIN packages ON packages.id = activities.package_id "
+ "WHERE packages.name = ? AND activities.name = ? "
+ "ORDER BY raw_traces.id ASC";
+
+ DbStatement stmt = DbStatement::Prepare(db, sql, package_name, activity_name);
+
+ std::vector<RawTraceModel> results;
+
+ RawTraceModel p{db};
+ while (DbQueryBuilder::SelectOnce(stmt, p.id, p.history_id, p.file_path)) {
+ results.push_back(p);
+ }
+
+ return results;
+ }
+
+ static std::optional<RawTraceModel> Insert(DbHandle db,
+ int history_id,
+ std::string file_path) {
+ const char* sql = "INSERT INTO raw_traces (history_id, file_path) VALUES (?1, ?2);";
+
+ std::optional<int> inserted_row_id =
+ DbQueryBuilder::Insert(db, sql, history_id, file_path);
+ if (!inserted_row_id) {
+ return std::nullopt;
+ }
+
+ RawTraceModel p{db};
+ p.id = *inserted_row_id;
+ p.history_id = history_id;
+ p.file_path = file_path;
+
+ return p;
+ }
+
+ bool Delete() {
+ const char* sql = "DELETE FROM raw_traces WHERE id = ?";
+
+ return DbQueryBuilder::Delete(db(), sql, id);
+ }
+
+ int id;
+ int history_id;
+ std::string file_path;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const RawTraceModel& p) {
+ os << "RawTraceModel{id=" << p.id << ",history_id=" << p.history_id << ",";
+ os << "file_path=" << p.file_path << "}";
+ return os;
+}
+
} // namespace iorap::db
#endif // IORAP_SRC_DB_MODELS_H_