#ifndef CHROME_UPDATER_EVENT_HISTORY_H_
#define CHROME_UPDATER_EVENT_HISTORY_H_
#include <concepts>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/json/values_util.h"
#include "base/logging.h"
#include "base/process/process.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/updater_scope.h"
namespace updater {
void InitHistoryLogging(const base::FilePath& path, size_t max_file_size_bytes);
void InitHistoryLogging(UpdaterScope updater_scope);
std::string GenerateEventId();
const std::string& GetProcessToken();
void WriteHistoryEvent(base::Value::Dict event);
struct HistoryEventError {
int category = 0;
int code = 0;
int extracode1 = 0;
base::Value::Dict ToDict() const;
};
template <typename T>
class HistoryEventBuilder {
public:
T& SetEventId(const std::string& event_id) {
event_id_ = event_id;
return static_cast<T&>(*this);
}
T& AddError(const HistoryEventError& error) {
errors_.push_back(error);
return static_cast<T&>(*this);
}
std::optional<base::Value::Dict> Build() const {
base::Value::Dict dict =
base::Value::Dict()
.Set("eventId", event_id_)
.Set("deviceUptime",
base::TimeDeltaToValue(base::SysInfo::Uptime()))
.Set("pid", static_cast<int>(base::Process::Current().Pid()))
.Set("processToken", GetProcessToken());
if (!errors_.empty()) {
base::Value::List errors;
for (const auto& error : errors_) {
errors.Append(error.ToDict());
}
dict.Set("errors", std::move(errors));
}
return BuildInternal(std::move(dict));
}
void Write() {
std::optional<base::Value::Dict> event = Build();
if (!event) {
base::debug::DumpWithoutCrashing();
return;
}
WriteHistoryEvent(*std::move(event));
}
void WriteAsync() {
std::optional<base::Value::Dict> event = Build();
if (!event) {
base::debug::DumpWithoutCrashing();
return;
}
base::ThreadPool::PostTask(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&WriteHistoryEvent, *std::move(event)));
}
auto WriteAsyncAndReturnEndEvent()
requires requires {
typename T::EndEventType;
std::default_initializable<typename T::EndEventType>;
std::derived_from<typename T::EndEventType,
HistoryEventBuilder<typename T::EndEventType>>;
}
{
WriteAsync();
typename T::EndEventType end_event;
end_event.SetEventId(event_id_);
return end_event;
}
protected:
HistoryEventBuilder() = default;
virtual ~HistoryEventBuilder() = default;
virtual std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const = 0;
std::string event_id_ = GenerateEventId();
std::vector<HistoryEventError> errors_;
};
class InstallEndEvent : public HistoryEventBuilder<InstallEndEvent> {
public:
InstallEndEvent();
InstallEndEvent(InstallEndEvent&&);
InstallEndEvent& operator=(InstallEndEvent&&);
InstallEndEvent(const InstallEndEvent&) = delete;
InstallEndEvent& operator=(const InstallEndEvent&) = delete;
~InstallEndEvent() override;
InstallEndEvent& SetVersion(const std::string& version);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<std::string> version_;
};
class InstallStartEvent : public HistoryEventBuilder<InstallStartEvent> {
public:
using EndEventType = InstallEndEvent;
InstallStartEvent();
InstallStartEvent(InstallStartEvent&&);
InstallStartEvent& operator=(InstallStartEvent&&);
InstallStartEvent(const InstallStartEvent&) = delete;
InstallStartEvent& operator=(const InstallStartEvent&) = delete;
~InstallStartEvent() override;
InstallStartEvent& SetAppId(const std::string& app_id);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::string app_id_;
};
class UninstallEndEvent : public HistoryEventBuilder<UninstallEndEvent> {
public:
UninstallEndEvent();
UninstallEndEvent(UninstallEndEvent&&);
UninstallEndEvent& operator=(UninstallEndEvent&&);
UninstallEndEvent(const UninstallEndEvent&) = delete;
UninstallEndEvent& operator=(const UninstallEndEvent&) = delete;
~UninstallEndEvent() override;
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
};
class UninstallStartEvent : public HistoryEventBuilder<UninstallStartEvent> {
public:
using EndEventType = UninstallEndEvent;
UninstallStartEvent();
UninstallStartEvent(UninstallStartEvent&&);
UninstallStartEvent& operator=(UninstallStartEvent&&);
UninstallStartEvent(const UninstallStartEvent&) = delete;
UninstallStartEvent& operator=(const UninstallStartEvent&) = delete;
~UninstallStartEvent() override;
UninstallStartEvent& SetAppId(const std::string& app_id);
UninstallStartEvent& SetVersion(const std::string& version);
UninstallStartEvent& SetReason(UninstallPingReason reason);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::string app_id_;
std::string version_;
std::optional<UninstallPingReason> reason_;
};
class QualifyEndEvent : public HistoryEventBuilder<QualifyEndEvent> {
public:
QualifyEndEvent();
QualifyEndEvent(QualifyEndEvent&&);
QualifyEndEvent& operator=(QualifyEndEvent&&);
QualifyEndEvent(const QualifyEndEvent&) = delete;
QualifyEndEvent& operator=(const QualifyEndEvent&) = delete;
~QualifyEndEvent() override;
QualifyEndEvent& SetQualified(bool qualified);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
bool qualified_ = false;
};
class QualifyStartEvent : public HistoryEventBuilder<QualifyStartEvent> {
public:
using EndEventType = QualifyEndEvent;
QualifyStartEvent();
QualifyStartEvent(QualifyStartEvent&&);
QualifyStartEvent& operator=(QualifyStartEvent&&);
QualifyStartEvent(const QualifyStartEvent&) = delete;
QualifyStartEvent& operator=(const QualifyStartEvent&) = delete;
~QualifyStartEvent() override;
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
};
class ActivateEndEvent : public HistoryEventBuilder<ActivateEndEvent> {
public:
ActivateEndEvent();
ActivateEndEvent(ActivateEndEvent&&);
ActivateEndEvent& operator=(ActivateEndEvent&&);
ActivateEndEvent(const ActivateEndEvent&) = delete;
ActivateEndEvent& operator=(const ActivateEndEvent&) = delete;
~ActivateEndEvent() override;
ActivateEndEvent& SetActivated(bool activated);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
bool activated_ = false;
};
class ActivateStartEvent : public HistoryEventBuilder<ActivateStartEvent> {
public:
using EndEventType = ActivateEndEvent;
ActivateStartEvent();
ActivateStartEvent(ActivateStartEvent&&);
ActivateStartEvent& operator=(ActivateStartEvent&&);
ActivateStartEvent(const ActivateStartEvent&) = delete;
ActivateStartEvent& operator=(const ActivateStartEvent&) = delete;
~ActivateStartEvent() override;
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
};
class PersistedDataEvent : public HistoryEventBuilder<PersistedDataEvent> {
public:
struct RegisteredApp {
RegisteredApp();
RegisteredApp(const RegisteredApp&);
RegisteredApp& operator=(const RegisteredApp&);
~RegisteredApp();
std::string app_id;
std::string version;
std::optional<std::string> cohort;
std::optional<std::string> brand_code;
};
PersistedDataEvent();
PersistedDataEvent(PersistedDataEvent&&);
PersistedDataEvent& operator=(PersistedDataEvent&&);
PersistedDataEvent(const PersistedDataEvent&) = delete;
PersistedDataEvent& operator=(const PersistedDataEvent&) = delete;
~PersistedDataEvent() override;
PersistedDataEvent& SetEulaRequired(bool eula_required);
PersistedDataEvent& SetLastChecked(const base::Time& last_checked);
PersistedDataEvent& SetLastStarted(const base::Time& last_started);
PersistedDataEvent& AddRegisteredApp(const RegisteredApp& registered_app);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
bool eula_required_ = false;
std::optional<base::Time> last_checked_;
std::optional<base::Time> last_started_;
std::vector<RegisteredApp> registered_apps_;
};
class PostRequestEndEvent : public HistoryEventBuilder<PostRequestEndEvent> {
public:
PostRequestEndEvent();
PostRequestEndEvent(PostRequestEndEvent&&);
PostRequestEndEvent& operator=(PostRequestEndEvent&&);
PostRequestEndEvent(const PostRequestEndEvent&) = delete;
PostRequestEndEvent& operator=(const PostRequestEndEvent&) = delete;
~PostRequestEndEvent() override;
PostRequestEndEvent& SetResponse(const std::string& response);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<std::string> response_;
};
class PostRequestStartEvent
: public HistoryEventBuilder<PostRequestStartEvent> {
public:
using EndEventType = PostRequestEndEvent;
PostRequestStartEvent();
PostRequestStartEvent(PostRequestStartEvent&&);
PostRequestStartEvent& operator=(PostRequestStartEvent&&);
PostRequestStartEvent(const PostRequestStartEvent&) = delete;
PostRequestStartEvent& operator=(const PostRequestStartEvent&) = delete;
~PostRequestStartEvent() override;
PostRequestStartEvent& SetRequest(const std::string& request);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::string request_;
};
class LoadPolicyEndEvent : public HistoryEventBuilder<LoadPolicyEndEvent> {
public:
LoadPolicyEndEvent();
LoadPolicyEndEvent(LoadPolicyEndEvent&&);
LoadPolicyEndEvent& operator=(LoadPolicyEndEvent&&);
LoadPolicyEndEvent(const LoadPolicyEndEvent&) = delete;
LoadPolicyEndEvent& operator=(const LoadPolicyEndEvent&) = delete;
~LoadPolicyEndEvent() override;
LoadPolicyEndEvent& SetPolicySet(const base::Value::Dict& policy_set);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
base::Value::Dict policy_set_;
};
class LoadPolicyStartEvent : public HistoryEventBuilder<LoadPolicyStartEvent> {
public:
using EndEventType = LoadPolicyEndEvent;
LoadPolicyStartEvent();
LoadPolicyStartEvent(LoadPolicyStartEvent&&);
LoadPolicyStartEvent& operator=(LoadPolicyStartEvent&&);
LoadPolicyStartEvent(const LoadPolicyStartEvent&) = delete;
LoadPolicyStartEvent& operator=(const LoadPolicyStartEvent&) = delete;
~LoadPolicyStartEvent() override;
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
};
class UpdateEndEvent : public HistoryEventBuilder<UpdateEndEvent> {
public:
UpdateEndEvent();
UpdateEndEvent(UpdateEndEvent&&);
UpdateEndEvent& operator=(UpdateEndEvent&&);
UpdateEndEvent(const UpdateEndEvent&) = delete;
UpdateEndEvent& operator=(const UpdateEndEvent&) = delete;
~UpdateEndEvent() override;
UpdateEndEvent& SetOutcome(UpdateService::UpdateState::State outcome);
UpdateEndEvent& SetNextVersion(const std::string& next_version);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<UpdateService::UpdateState::State> outcome_;
std::optional<std::string> next_version_;
};
class UpdateStartEvent : public HistoryEventBuilder<UpdateStartEvent> {
public:
using EndEventType = UpdateEndEvent;
UpdateStartEvent();
UpdateStartEvent(UpdateStartEvent&&);
UpdateStartEvent& operator=(UpdateStartEvent&&);
UpdateStartEvent(const UpdateStartEvent&) = delete;
UpdateStartEvent& operator=(const UpdateStartEvent&) = delete;
~UpdateStartEvent() override;
UpdateStartEvent& SetAppId(const std::string& app_id);
UpdateStartEvent& SetConnectionMetered(bool connection_metered);
UpdateStartEvent& SetPriority(UpdateService::Priority priority);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<std::string> app_id_;
std::optional<bool> connection_metered_;
std::optional<UpdateService::Priority> priority_;
std::optional<std::string> install_source_;
};
class UpdaterProcessEndEvent
: public HistoryEventBuilder<UpdaterProcessEndEvent> {
public:
UpdaterProcessEndEvent();
UpdaterProcessEndEvent(UpdaterProcessEndEvent&&);
UpdaterProcessEndEvent& operator=(UpdaterProcessEndEvent&&);
UpdaterProcessEndEvent(const UpdaterProcessEndEvent&) = delete;
UpdaterProcessEndEvent& operator=(const UpdaterProcessEndEvent&) = delete;
~UpdaterProcessEndEvent() override;
UpdaterProcessEndEvent& SetExitCode(int exit_code);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<int> exit_code_;
};
class UpdaterProcessStartEvent
: public HistoryEventBuilder<UpdaterProcessStartEvent> {
public:
using EndEventType = UpdaterProcessEndEvent;
UpdaterProcessStartEvent();
UpdaterProcessStartEvent(UpdaterProcessStartEvent&&);
UpdaterProcessStartEvent& operator=(UpdaterProcessStartEvent&&);
UpdaterProcessStartEvent(const UpdaterProcessStartEvent&) = delete;
UpdaterProcessStartEvent& operator=(const UpdaterProcessStartEvent&) = delete;
~UpdaterProcessStartEvent() override;
UpdaterProcessStartEvent& SetCommandLine(const std::string& command_line);
UpdaterProcessStartEvent& SetTimestamp(const base::Time& timestamp);
UpdaterProcessStartEvent& SetUpdaterVersion(
const std::string& updater_version);
UpdaterProcessStartEvent& SetScope(UpdaterScope scope);
UpdaterProcessStartEvent& SetOsPlatform(const std::string& os_platform);
UpdaterProcessStartEvent& SetOsVersion(const std::string& os_version);
UpdaterProcessStartEvent& SetOsArchitecture(
const std::string& os_architecture);
UpdaterProcessStartEvent& SetUpdaterArchitecture(
const std::string& updater_architecture);
UpdaterProcessStartEvent& SetParentPid(int parent_pid);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<std::string> command_line_;
std::optional<base::Time> timestamp_;
std::optional<std::string> updater_version_;
std::optional<UpdaterScope> scope_;
std::optional<std::string> os_platform_;
std::optional<std::string> os_version_;
std::optional<std::string> os_architecture_;
std::optional<std::string> updater_architecture_;
std::optional<int> parent_pid_;
};
class AppCommandEndEvent : public HistoryEventBuilder<AppCommandEndEvent> {
public:
AppCommandEndEvent();
AppCommandEndEvent(AppCommandEndEvent&&);
AppCommandEndEvent& operator=(AppCommandEndEvent&&);
AppCommandEndEvent(const AppCommandEndEvent&) = delete;
AppCommandEndEvent& operator=(const AppCommandEndEvent&) = delete;
~AppCommandEndEvent() override;
AppCommandEndEvent& SetExitCode(int exit_code);
AppCommandEndEvent& SetOutput(const std::string& output);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::optional<int> exit_code_;
std::optional<std::string> output_;
};
class AppCommandStartEvent : public HistoryEventBuilder<AppCommandStartEvent> {
public:
using EndEventType = AppCommandEndEvent;
AppCommandStartEvent();
AppCommandStartEvent(AppCommandStartEvent&&);
AppCommandStartEvent& operator=(AppCommandStartEvent&&);
AppCommandStartEvent(const AppCommandStartEvent&) = delete;
AppCommandStartEvent& operator=(const AppCommandStartEvent&) = delete;
~AppCommandStartEvent() override;
AppCommandStartEvent& SetAppId(const std::string& app_id);
AppCommandStartEvent& SetCommandLine(const std::string& command_line);
private:
std::optional<base::Value::Dict> BuildInternal(
base::Value::Dict event) const override;
std::string app_id_;
std::optional<std::string> command_line_;
};
}
#endif