blob: 39f8bf4c4cb2e7632286dcfd0e0225984b67897d [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <memory>
#include "base/files/file.h"
#include "base/logging.h"
#include "chrome/browser/chromeos/policy/single_app_install_event_log.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy {
namespace {
static const int64_t kLogFileVersion = 3;
static const ssize_t kMaxLogs = 1024;
} // namespace
AppInstallEventLog::AppInstallEventLog(const base::FilePath& file_name)
: file_name_(file_name) {
base::File file(file_name_, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid()) {
return;
}
int64_t version;
if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&version),
sizeof(version)) != sizeof(version)) {
LOG(WARNING) << "Corrupted app install log.";
return;
}
if (version != kLogFileVersion) {
LOG(WARNING) << "Log file version mismatch.";
return;
}
ssize_t entries;
if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&entries),
sizeof(entries)) != sizeof(entries)) {
LOG(WARNING) << "Corrupted app install log.";
return;
}
for (int i = 0; i < std::min(entries, kMaxLogs); ++i) {
std::unique_ptr<SingleAppInstallEventLog> log;
const bool file_ok = SingleAppInstallEventLog::Load(&file, &log);
const bool log_ok = log && !log->package().empty() &&
logs_.find(log->package()) == logs_.end();
if (!file_ok || !log_ok) {
LOG(WARNING) << "Corrupted app install log.";
}
if (log_ok) {
total_size_ += log->size();
max_size_ = std::max(max_size_, log->size());
logs_[log->package()] = std::move(log);
}
if (!file_ok) {
return;
}
}
if (entries >= kMaxLogs) {
LOG(WARNING) << "Corrupted app install log.";
}
}
AppInstallEventLog::~AppInstallEventLog() {}
void AppInstallEventLog::Add(const std::string& package,
const em::AppInstallReportLogEvent& event) {
if (logs_.size() == kMaxLogs && logs_.find(package) == logs_.end()) {
LOG(WARNING) << "App install log overflow.";
return;
}
auto& log = logs_[package];
if (log == nullptr) {
log.reset(new SingleAppInstallEventLog(package));
}
total_size_ -= log->size();
log->Add(event);
total_size_ += log->size();
max_size_ = std::max(max_size_, log->size());
dirty_ = true;
}
void AppInstallEventLog::Store() {
if (!dirty_) {
return;
}
base::File file(file_name_,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!file.IsValid()) {
LOG(WARNING) << "Unable to store app install log.";
return;
}
if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kLogFileVersion),
sizeof(kLogFileVersion)) !=
sizeof(kLogFileVersion)) {
LOG(WARNING) << "Unable to store app install log.";
return;
}
ssize_t entries = logs_.size();
if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&entries),
sizeof(entries)) != sizeof(entries)) {
LOG(WARNING) << "Unable to store app install log.";
return;
}
for (const auto& log : logs_) {
if (!log.second->Store(&file)) {
LOG(WARNING) << "Unable to store app install log.";
return;
}
}
dirty_ = false;
}
void AppInstallEventLog::Serialize(em::AppInstallReportRequest* report) {
report->Clear();
for (const auto& log : logs_) {
em::AppInstallReport* const report_log = report->add_app_install_report();
log.second->Serialize(report_log);
}
}
void AppInstallEventLog::ClearSerialized() {
int total_size = 0;
max_size_ = 0;
auto log = logs_.begin();
while (log != logs_.end()) {
log->second->ClearSerialized();
if (log->second->empty()) {
log = logs_.erase(log);
} else {
total_size += log->second->size();
max_size_ = std::max(max_size_, log->second->size());
++log;
}
}
if (total_size != total_size_) {
total_size_ = total_size;
dirty_ = true;
}
}
} // namespace policy