blob: b2657538a7199731f010b3db0806a516d48c377c [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/single_app_install_event_log.h"
#include <stddef.h>
#include <stdint.h>
#include "base/files/file.h"
namespace em = enterprise_management;
namespace policy {
namespace {
static const int kLogCapacity = 1024;
static const int kMaxBufferSize = 65536;
} // namespace
SingleAppInstallEventLog::SingleAppInstallEventLog(const std::string& package)
: package_(package) {}
SingleAppInstallEventLog::~SingleAppInstallEventLog() {}
void SingleAppInstallEventLog::Add(const em::AppInstallReportLogEvent& event) {
events_.push_back(event);
if (events_.size() > kLogCapacity) {
incomplete_ = true;
if (serialized_entries_ > -1) {
--serialized_entries_;
}
events_.pop_front();
}
}
bool SingleAppInstallEventLog::Load(
base::File* file,
std::unique_ptr<SingleAppInstallEventLog>* log) {
log->reset();
if (!file->IsValid()) {
return false;
}
ssize_t size;
if (file->ReadAtCurrentPos(reinterpret_cast<char*>(&size), sizeof(size)) !=
sizeof(size) ||
size > kMaxBufferSize) {
return false;
}
std::unique_ptr<char[]> package_buffer = std::make_unique<char[]>(size);
if (file->ReadAtCurrentPos(package_buffer.get(), size) != size) {
return false;
}
*log = std::make_unique<SingleAppInstallEventLog>(
std::string(package_buffer.get(), size));
int64_t incomplete;
if (file->ReadAtCurrentPos(reinterpret_cast<char*>(&incomplete),
sizeof(incomplete)) != sizeof(incomplete)) {
return false;
}
(*log)->incomplete_ = incomplete;
ssize_t entries;
if (file->ReadAtCurrentPos(reinterpret_cast<char*>(&entries),
sizeof(entries)) != sizeof(entries)) {
return false;
}
for (ssize_t i = 0; i < entries; ++i) {
if (file->ReadAtCurrentPos(reinterpret_cast<char*>(&size), sizeof(size)) !=
sizeof(size) ||
size > kMaxBufferSize) {
(*log)->incomplete_ = true;
return false;
}
if (size == 0) {
// Zero-size entries are written if serialization of a log entry fails.
// Skip these on read.
(*log)->incomplete_ = true;
continue;
}
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size);
if (file->ReadAtCurrentPos(buffer.get(), size) != size) {
(*log)->incomplete_ = true;
return false;
}
em::AppInstallReportLogEvent event;
if (event.ParseFromArray(buffer.get(), size)) {
(*log)->Add(event);
} else {
(*log)->incomplete_ = true;
}
}
return true;
}
bool SingleAppInstallEventLog::Store(base::File* file) const {
if (!file->IsValid()) {
return false;
}
ssize_t size = package_.size();
if (file->WriteAtCurrentPos(reinterpret_cast<const char*>(&size),
sizeof(size)) != sizeof(size)) {
return false;
}
if (file->WriteAtCurrentPos(package_.data(), size) != size) {
return false;
}
const int64_t incomplete = incomplete_;
if (file->WriteAtCurrentPos(reinterpret_cast<const char*>(&incomplete),
sizeof(incomplete)) != sizeof(incomplete)) {
return false;
}
const ssize_t entries = events_.size();
if (file->WriteAtCurrentPos(reinterpret_cast<const char*>(&entries),
sizeof(entries)) != sizeof(entries)) {
return false;
}
for (const em::AppInstallReportLogEvent& event : events_) {
size = event.ByteSizeLong();
std::unique_ptr<char[]> buffer;
if (size > kMaxBufferSize) {
// Log entry too large. Skip it.
size = 0;
} else {
buffer = std::make_unique<char[]>(size);
if (!event.SerializeToArray(buffer.get(), size)) {
// Log entry serialization failed. Skip it.
size = 0;
}
}
if (file->WriteAtCurrentPos(reinterpret_cast<const char*>(&size),
sizeof(size)) != sizeof(size) ||
(size && file->WriteAtCurrentPos(buffer.get(), size) != size)) {
return false;
}
}
return true;
}
void SingleAppInstallEventLog::Serialize(em::AppInstallReport* report) {
report->Clear();
report->set_package(package_);
report->set_incomplete(incomplete_);
for (const auto& event : events_) {
em::AppInstallReportLogEvent* const log_event = report->add_log();
*log_event = event;
}
serialized_entries_ = events_.size();
}
void SingleAppInstallEventLog::ClearSerialized() {
if (serialized_entries_ == -1) {
return;
}
events_.erase(events_.begin(), events_.begin() + serialized_entries_);
serialized_entries_ = -1;
incomplete_ = false;
}
} // namespace policy