Commit c16d425a authored by Bartosz Fabianowski's avatar Bartosz Fabianowski Committed by Commit Bot

Add class that holds app push-install event log

This adds a class that holds a log of events related to a single
app's push install process. The class is not hooked up to anything
yet, so no log entries are read or written.

Bug: b/73277923
Test: unit_tests
Change-Id: I046f5c4871e1ae8867c96c3f6bd5c6cee31b8e01
Reviewed-on: https://chromium-review.googlesource.com/915924
Commit-Queue: Bartosz Fabianowski <bartfab@chromium.org>
Reviewed-by: default avatarJulian Pastarmov <pastarmovj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537639}
parent bc446d8e
...@@ -1342,6 +1342,8 @@ source_set("chromeos") { ...@@ -1342,6 +1342,8 @@ source_set("chromeos") {
"policy/server_backed_device_state.h", "policy/server_backed_device_state.h",
"policy/server_backed_state_keys_broker.cc", "policy/server_backed_state_keys_broker.cc",
"policy/server_backed_state_keys_broker.h", "policy/server_backed_state_keys_broker.h",
"policy/single_app_install_event_log.cc",
"policy/single_app_install_event_log.h",
"policy/status_uploader.cc", "policy/status_uploader.cc",
"policy/status_uploader.h", "policy/status_uploader.h",
"policy/system_log_uploader.cc", "policy/system_log_uploader.cc",
...@@ -1937,6 +1939,7 @@ source_set("unit_tests") { ...@@ -1937,6 +1939,7 @@ source_set("unit_tests") {
"policy/remote_commands/device_command_set_volume_job_unittest.cc", "policy/remote_commands/device_command_set_volume_job_unittest.cc",
"policy/secondary_google_account_signin_policy_handler_unittest.cc", "policy/secondary_google_account_signin_policy_handler_unittest.cc",
"policy/server_backed_state_keys_broker_unittest.cc", "policy/server_backed_state_keys_broker_unittest.cc",
"policy/single_app_install_event_log_unittest.cc",
"policy/status_uploader_unittest.cc", "policy/status_uploader_unittest.cc",
"policy/system_log_uploader_unittest.cc", "policy/system_log_uploader_unittest.cc",
"policy/temp_certs_cache_nss_unittest.cc", "policy/temp_certs_cache_nss_unittest.cc",
......
// 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
// 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.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_APP_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_APP_INSTALL_EVENT_LOG_H_
#include <deque>
#include <memory>
#include <string>
#include "components/policy/proto/device_management_backend.pb.h"
#include "base/macros.h"
namespace base {
class File;
}
namespace policy {
// An event log for a single app's push-install process. The log can be stored
// on disk and serialized for upload to a server. The log is internally held in
// a round-robin buffer. A flag indicates whether any log entries were lost
// (e.g. entry too large or buffer wrapped around). Log entries are pruned and
// the flag is cleared after upload has completed.
class SingleAppInstallEventLog {
public:
explicit SingleAppInstallEventLog(const std::string& package);
~SingleAppInstallEventLog();
const std::string& package() const { return package_; }
int size() const { return events_.size(); }
bool empty() const { return events_.empty(); }
// Add a log entry. If the buffer is full, the oldest entry is removed and
// |incomplete_| is set.
void Add(const enterprise_management::AppInstallReportLogEvent& event);
// Restores the event log from |file| into |log|. Returns |true| if the
// self-delimiting format of the log was parsed successfully and further logs
// stored in the file may be loaded.
// |incomplete_| is set to |true| if it was set when storing the log to the
// file, the buffer wraps around or any log entries cannot be fully parsed. If
// not even the app name can be parsed, |log| is set to |nullptr|.
static bool Load(base::File* file,
std::unique_ptr<SingleAppInstallEventLog>* log);
// Stores the event log to |file|. Returns |true| if the log was written
// successfully in a self-delimiting manner and the file may be used to store
// further logs.
bool Store(base::File* file) const;
// Serializes the log to a protobuf for upload to a server. Records which
// entries were serialized so that they may be cleared after successful
// upload.
void Serialize(enterprise_management::AppInstallReport* report);
// Clears log entries that were previously serialized. Also clears
// |incomplete_| if all log entries added since serialization are still
// present in the log.
void ClearSerialized();
private:
// The app this event log pertains to.
const std::string package_;
// The buffer holding log entries.
std::deque<enterprise_management::AppInstallReportLogEvent> events_;
// Whether any log entries were lost (e.g. entry too large or buffer wrapped
// around).
bool incomplete_ = false;
// The number of entries that were serialized and can be cleared from the log
// after successful upload to the server, or -1 if none.
int serialized_entries_ = -1;
DISALLOW_COPY_AND_ASSIGN(SingleAppInstallEventLog);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_APP_INSTALL_EVENT_LOG_H_
...@@ -1466,6 +1466,95 @@ message TpmVersionInfo { ...@@ -1466,6 +1466,95 @@ message TpmVersionInfo {
optional string vendor_specific = 6; optional string vendor_specific = 6;
} }
// System state included with some log events.
message SystemState {
// VolumeInfo is reused from existing Chrome reporting.
repeated VolumeInfo volume_info = 1;
}
// A single entry in the push-install log for an app.
message AppInstallReportLogEvent {
// Enumerates the possible event types.
enum EventType {
// Request received by device
SERVER_REQUEST = 0;
// Request forwarded to CloudDPC
CLOUDDPC_REQUEST = 1;
// Request forwarded to CloudDPS
CLOUDDPS_REQUEST = 2;
// Response received from CloudDPS
CLOUDDPS_RESPONSE = 3;
// Log line written by Phonesky
PHONESKY_LOG = 4;
// Install success
SUCCESS = 5;
// Request canceled
CANCELED = 6;
// Connectivity state changed
CONNECTIVITY_CHANGE = 7;
// Session state changed
SESSION_STATE_CHANGE = 8;
}
// Enumerates the possible changes in session state.
enum SessionStateChangeType {
// Session starting
LOGIN = 0;
// Session ending
LOGOUT = 1;
// Suspending
SUSPEND = 2;
// Resuming
RESUME = 3;
}
// Timestamp, in milliseconds since epoch. Set for all log
// events.
optional int64 timestamp = 1;
// Event type. Set for all log events.
optional EventType event_type = 2;
// System state. Set for event types SERVER_REQUEST,
// CLOUDDPS_RESPONSE and SUCCESS.
optional SystemState system_state = 3;
// CloudDPS response. Set for event type CLOUDDPS_RESPONSE.
optional int32 clouddps_response = 4;
// Log line written by Phonesky. Set for event type PHONESKY_LOG.
optional string phonesky_log = 5;
// Network state. Set for SERVER_REQUEST and CONNECTIVITY_CHANGE.
optional NetworkState network_state = 6;
// Type of session state change. Set for SESSION_STATE_CHANGE.
optional SessionStateChangeType session_state_change_type = 7;
}
// Log bucket for an app.
message AppInstallReport {
// Package name of the app.
optional string package = 1;
// Whether the log is incomplete, e.g. due to the log ring buffer overflowing
// or disk corruption.
optional bool incomplete = 2;
// Log events for the app.
repeated AppInstallReportLogEvent log = 3;
}
// Push-install logs for all apps.
message AppInstallReportRequest {
// Log buckets for each app.
repeated AppInstallReport app_install_report = 1;
}
// Response from server after receiving a report on the status of app
// push-installs.
message AppInstallReportResponse {}
// Request from the DMAgent on the device to the DMServer. This is // Request from the DMAgent on the device to the DMServer. This is
// container for all requests from device to server. The overall HTTP // container for all requests from device to server. The overall HTTP
// request MUST be in the following format: // request MUST be in the following format:
...@@ -1548,6 +1637,7 @@ message TpmVersionInfo { ...@@ -1548,6 +1637,7 @@ message TpmVersionInfo {
// check_device_license: check_device_license_request // check_device_license: check_device_license_request
// active_directory_user_signin: active_directory_user_signin_request // active_directory_user_signin: active_directory_user_signin_request
// register_browser: register_browser_request // register_browser: register_browser_request
// app_install_report: app_install_report_request
// //
message DeviceManagementRequest { message DeviceManagementRequest {
// Register request. // Register request.
...@@ -1625,6 +1715,9 @@ message DeviceManagementRequest { ...@@ -1625,6 +1715,9 @@ message DeviceManagementRequest {
// A Chrome desktop report request. // A Chrome desktop report request.
optional ChromeDesktopReportRequest chrome_desktop_report_request = 24; optional ChromeDesktopReportRequest chrome_desktop_report_request = 24;
// A report on the status of app push-installs.
optional AppInstallReportRequest app_install_report_request = 25;
} }
// Response from server to device. // Response from server to device.
...@@ -1751,4 +1844,7 @@ message DeviceManagementResponse { ...@@ -1751,4 +1844,7 @@ message DeviceManagementResponse {
// Response to a Chrome browser registration request. // Response to a Chrome browser registration request.
optional RegisterBrowserResponse register_browser_response = 24; optional RegisterBrowserResponse register_browser_response = 24;
// Response a report on the status of app push-installs
optional AppInstallReportResponse app_install_report_response = 25;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment