blob: 8202a75acce5875ca8706cc31cee312222cb58e3 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_TRACING_TRACE_REPORT_DATABASE_H_
#define CONTENT_BROWSER_TRACING_TRACE_REPORT_DATABASE_H_
#include <optional>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/token.h"
#include "content/common/content_export.h"
#include "sql/database.h"
#include "sql/statement.h"
#include "sql/transaction.h"
namespace content {
enum class ReportUploadState {
kNotUploaded = 0,
kPending,
kPending_UserRequested,
kUploaded
};
enum class SkipUploadReason {
kNoSkip = 0,
kSizeLimitExceeded = 1,
kNotAnonymized = 2,
kScenarioQuotaExceeded = 3,
kUploadTimedOut = 4,
kLocalScenario = 5,
};
// BaseTraceReport contains common data used to create and display a trace
// report.
struct CONTENT_EXPORT BaseTraceReport {
BaseTraceReport();
BaseTraceReport(const BaseTraceReport& other);
~BaseTraceReport();
// A unique identifier by which this report will always be known to the
// database as well as outside of it (e.g.: perfetto).
base::Token uuid;
// The time at which the report was created.
base::Time creation_time;
// The name of the scenario that triggered this trace to be collected and
// report to be created.
std::string scenario_name;
// The upload rule name that triggered this report.
std::string upload_rule_name;
// The upload rule value that triggered this report.
std::optional<int32_t> upload_rule_value;
// The total size in bytes taken by the report.
uint64_t total_size = 0;
// The reason for which a report was not uploaded even if the upload rules
// were met.
SkipUploadReason skip_reason = SkipUploadReason::kNoSkip;
};
// NewTraceReport represents the metadata needed to create and add a new
// report into the TraceReportDatabase.
struct CONTENT_EXPORT NewTraceReport : BaseTraceReport {
NewTraceReport();
// NOLINTNEXTLINE(google-explicit-constructor)
NewTraceReport(const BaseTraceReport& report) : BaseTraceReport(report) {}
~NewTraceReport();
NewTraceReport(const NewTraceReport& new_report) = delete;
NewTraceReport(NewTraceReport&& new_report) = default;
NewTraceReport& operator=(const NewTraceReport& new_report) = delete;
NewTraceReport& operator=(NewTraceReport&& new_report) = default;
// The serialized trace report content.
std::string trace_content;
// The serialized system profile information.
std::string system_profile;
};
// ClientTraceReport represents all metadata of a trace report to be displayed
// to user. Proto member is not included here since it can be of significant
// size. Therefore, if proto is needed it can be obtained through
// GetProtoValue().
struct CONTENT_EXPORT ClientTraceReport : BaseTraceReport {
ClientTraceReport();
~ClientTraceReport();
// The current upload state for this report represented by
// ReportUploadState.
ReportUploadState upload_state = ReportUploadState::kNotUploaded;
// The time at which the report was successfully uploaded to a server.
base::Time upload_time;
// Whether the report has content (payload) attached to it.
bool has_trace_content = false;
};
class CONTENT_EXPORT TraceReportDatabase {
public:
TraceReportDatabase();
~TraceReportDatabase() = default;
TraceReportDatabase(const TraceReportDatabase&) = delete;
TraceReportDatabase& operator=(const TraceReportDatabase&) = delete;
bool is_open() const { return database_.is_open(); }
bool is_initialized() const { return initialized_; }
bool OpenDatabase(const base::FilePath& path);
// Open database only if it already exists.
bool OpenDatabaseIfExists(const base::FilePath& path);
// Initialize DB and open in it memory.
bool OpenDatabaseInMemoryForTesting();
// Adds a new row (trace) to the local_traces table.
bool AddTrace(const NewTraceReport& new_report);
// Delete a row (trace) from the local_traces table.
bool DeleteTrace(const base::Token& uuid);
// Deletes all rows (traces) from the local_traces.
bool DeleteAllTraces();
// Delete traces between the |start| and |end| dates inclusively.
bool DeleteTracesInDateRange(base::Time start, base::Time end);
// Delete all reports older than |age| from today.
bool DeleteTraceReportsOlderThan(base::TimeDelta age);
// Delete uploaded trace content older than |age| from today.
bool DeleteUploadedTraceContentOlderThan(base::TimeDelta age);
// Delete old trace content, keeping up to `max_traces`.
bool DeleteOldTraceContent(size_t max_traces);
// Mark all reports that are pending upload as skipped with `skip_reason`.
bool AllPendingUploadSkipped(SkipUploadReason skip_reason);
bool UserRequestedUpload(const base::Token& uuid);
bool UploadComplete(const base::Token& uuid, base::Time time);
bool UploadSkipped(const base::Token& uuid, SkipUploadReason skip_reason);
// Returns the serialized trace content string if any.
std::optional<std::string> GetTraceContent(const base::Token& uuid);
// Returns the serialize system profile information if any.
std::optional<std::string> GetSystemProfile(const base::Token& uuid);
// Returns the number of trace for |scenario_name| since |since|.
std::optional<size_t> UploadCountSince(const std::string& scenario_name,
const std::string& upload_rule_name,
base::Time since);
// Returns the saved count per scenario since `since`.
base::flat_map<std::string, size_t> GetScenarioCountsSince(base::Time since);
// Returns all the reports currently stored in the database.
std::vector<ClientTraceReport> GetAllReports();
// Returns the next report pending upload.
std::optional<ClientTraceReport> GetNextReportPendingUpload();
private:
bool EnsureTableCreated();
sql::Database database_;
base::FilePath db_file_path_;
bool initialized_ = false;
// Guards usage of |database_|
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace content
#endif // CONTENT_BROWSER_TRACING_TRACE_REPORT_DATABASE_H_