Commit f797abe0 authored by Swapnil's avatar Swapnil Committed by Commit Bot

Refactor AppInstallEventLog and SingleAppInstallEventLog

AppInstallEventLog and SingleAppInstallEventLog classes are used for
storing logs on the disk and prepare for upload. Extract the common
code with ARC++ unspecific code into common classes. This is a
prework for adding similar classes for extension events.

Bug: 1081192
Change-Id: I481e864c89ce34fb9c8ddbd8983ad119be8bdf85
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2193675
Commit-Queue: Swapnil Gupta <swapnilgupta@google.com>
Reviewed-by: default avatarOleg Davydov <burunduk@chromium.org>
Reviewed-by: default avatarAskar Aitzhan <askaraitzhan@google.com>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#775048}
parent d022c012
......@@ -1846,8 +1846,6 @@ source_set("chromeos") {
"policy/affiliated_invalidation_service_provider_impl.h",
"policy/android_management_client.cc",
"policy/android_management_client.h",
"policy/app_install_event_log.cc",
"policy/app_install_event_log.h",
"policy/app_install_event_log_collector.cc",
"policy/app_install_event_log_collector.h",
"policy/app_install_event_log_manager.cc",
......@@ -1860,6 +1858,8 @@ source_set("chromeos") {
"policy/app_install_event_log_util.h",
"policy/app_install_event_logger.cc",
"policy/app_install_event_logger.h",
"policy/arc_app_install_event_log.cc",
"policy/arc_app_install_event_log.h",
"policy/auto_enrollment_client.h",
"policy/auto_enrollment_client_impl.cc",
"policy/auto_enrollment_client_impl.h",
......@@ -1964,6 +1964,7 @@ source_set("chromeos") {
"policy/heartbeat_scheduler.h",
"policy/hostname_handler.cc",
"policy/hostname_handler.h",
"policy/install_event_log.h",
"policy/lock_to_single_user_manager.cc",
"policy/lock_to_single_user_manager.h",
"policy/login_profile_policy_provider.cc",
......@@ -2042,8 +2043,9 @@ source_set("chromeos") {
"policy/server_backed_device_state.h",
"policy/server_backed_state_keys_broker.cc",
"policy/server_backed_state_keys_broker.h",
"policy/single_app_install_event_log.cc",
"policy/single_app_install_event_log.h",
"policy/single_arc_app_install_event_log.cc",
"policy/single_arc_app_install_event_log.h",
"policy/single_install_event_log.h",
"policy/status_collector/activity_storage.cc",
"policy/status_collector/activity_storage.h",
"policy/status_collector/affiliated_session_service.cc",
......@@ -3121,9 +3123,9 @@ source_set("unit_tests") {
"policy/app_install_event_log_collector_unittest.cc",
"policy/app_install_event_log_manager_unittest.cc",
"policy/app_install_event_log_manager_wrapper_unittest.cc",
"policy/app_install_event_log_unittest.cc",
"policy/app_install_event_log_uploader_unittest.cc",
"policy/app_install_event_logger_unittest.cc",
"policy/arc_app_install_event_log_unittest.cc",
"policy/auto_enrollment_client_impl_unittest.cc",
"policy/bluetooth_policy_handler_unittest.cc",
"policy/cached_policy_key_loader_chromeos_unittest.cc",
......@@ -3171,7 +3173,7 @@ source_set("unit_tests") {
"policy/scheduled_update_checker/device_scheduled_update_checker_unittest.cc",
"policy/secondary_google_account_signin_policy_handler_unittest.cc",
"policy/server_backed_state_keys_broker_unittest.cc",
"policy/single_app_install_event_log_unittest.cc",
"policy/single_arc_app_install_event_log_unittest.cc",
"policy/status_collector/activity_storage_unittest.cc",
"policy/status_collector/affiliated_session_service_unittest.cc",
"policy/status_collector/app_info_generator_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.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_H_
#include <map>
#include <memory>
#include <string>
#include "base/files/file_path.h"
#include "base/macros.h"
namespace enterprise_management {
class AppInstallReportLogEvent;
class AppInstallReportRequest;
} // namespace enterprise_management
namespace policy {
class SingleAppInstallEventLog;
// An event log for app push-installs. The log entries for each app are kept in
// a separate round-robin buffer. The log can be stored on disk and serialized
// for upload to a server. Log entries are pruned after upload has completed.
class AppInstallEventLog {
public:
// Restores the event log from |file_name|. If there is an error parsing the
// file, as many log entries as possible are restored.
explicit AppInstallEventLog(const base::FilePath& file_name);
~AppInstallEventLog();
// The current total number of log entries, across all apps.
int total_size() { return total_size_; }
// The current maximum number of log entries for a single app.
int max_size() { return max_size_; }
// Add a log entry for |package|. If the buffer for that app is full, the
// oldest entry is removed.
void Add(const std::string& package,
const enterprise_management::AppInstallReportLogEvent& event);
// Stores the event log to the file name provided to the constructor. If the
// event log has not changed since it was last stored to disk (or initially
// loaded from disk), does nothing.
void Store();
// 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::AppInstallReportRequest* report);
// Clears log entries that were previously serialized.
void ClearSerialized();
private:
// The round-robin log event buffers for individual apps.
std::map<std::string, std::unique_ptr<SingleAppInstallEventLog>> logs_;
const base::FilePath file_name_;
// The current total number of log entries, across all apps.
int total_size_ = 0;
// The current maximum number of log entries for a single app.
int max_size_ = 0;
// Whether the event log changed since it was last stored to disk (or
// initially loaded from disk).
bool dirty_ = false;
DISALLOW_COPY_AND_ASSIGN(AppInstallEventLog);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_H_
......@@ -17,8 +17,8 @@
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_uploader.h"
#include "chrome/browser/chromeos/policy/arc_app_install_event_log.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/policy/proto/device_management_backend.pb.h"
......@@ -167,7 +167,7 @@ AppInstallEventLogManager::LogSize AppInstallEventLogManager::Log::Init(
const base::FilePath& file_path) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!log_);
log_ = std::make_unique<AppInstallEventLog>(file_path);
log_ = std::make_unique<ArcAppInstallEventLog>(file_path);
return GetSize();
}
......
......@@ -30,12 +30,12 @@ class AppInstallReportRequest;
namespace policy {
class AppInstallEventLog;
class ArcAppInstallEventLog;
// Ties together collection, storage and upload of app push-install event logs.
// Owns an |AppInstallEventLog| for log storage and an |AppInstallEventLogger|
// for log collection. The |AppInstallEventUploader| is passed to the
// constructor and must outlive |this|.
// Owns an |ArcAppInstallEventLog| for log storage and an
// |AppInstallEventLogger| for log collection. The |AppInstallEventUploader| is
// passed to the constructor and must outlive |this|.
//
// Newly added log entries are held in memory first and stored to disk no more
// than five seconds later. The log is also written to disk every time it has
......@@ -148,7 +148,7 @@ class AppInstallEventLogManager : public AppInstallEventLogger::Delegate,
LogSize GetSize() const;
// The actual log store.
std::unique_ptr<AppInstallEventLog> log_;
std::unique_ptr<ArcAppInstallEventLog> log_;
// Ensures that methods are not called from the wrong thread.
SEQUENCE_CHECKER(sequence_checker_);
......
......@@ -20,9 +20,9 @@
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_uploader.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/chromeos/policy/arc_app_install_event_log.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/system/fake_statistics_provider.h"
......@@ -285,7 +285,7 @@ class AppInstallEventLogManagerTest : public testing::Test {
void VerifyLogFile() {
EXPECT_TRUE(base::PathExists(log_file_path_));
AppInstallEventLog log(log_file_path_);
ArcAppInstallEventLog log(log_file_path_);
em::AppInstallReportRequest log_events;
log.Serialize(&log_events);
EXPECT_TRUE(ContainsSameEvents(events_, log_events));
......@@ -337,7 +337,7 @@ TEST_F(AppInstallEventLogManagerTest, CreateEmpty) {
// the log. Verify that no store is scheduled and an expedited initial upload
// occurs after fifteen minutes.
TEST_F(AppInstallEventLogManagerTest, CreateNonEmpty) {
AppInstallEventLog log(log_file_path_);
ArcAppInstallEventLog log(log_file_path_);
events_[kPackageNames[0]].push_back(event_);
log.Add(kPackageNames[0], event_);
log.Store();
......@@ -734,7 +734,7 @@ TEST_F(AppInstallEventLogManagerTest, StoreOnShutdown) {
// to the app-install event log. Verify that the prefs are cleared and an
// immediate deletion of the log file is scheduled.
TEST_F(AppInstallEventLogManagerTest, Clear) {
AppInstallEventLog log(log_file_path_);
ArcAppInstallEventLog log(log_file_path_);
events_[kPackageNames[0]].push_back(event_);
log.Add(kPackageNames[0], event_);
log.Store();
......
......@@ -12,7 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include "chrome/browser/chromeos/policy/arc_app_install_event_log.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "components/arc/arc_prefs.h"
......@@ -67,7 +67,7 @@ class AppInstallEventLogManagerWrapperTest : public testing::Test {
void SetUp() override { app_list_.AppendString(kPackageName); }
void PopulateLogFileAndPrefs() {
AppInstallEventLog log(log_file_path_);
ArcAppInstallEventLog log(log_file_path_);
em::AppInstallReportLogEvent event;
event.set_timestamp(0);
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
......
// 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/arc_app_install_event_log.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy {
ArcAppInstallEventLog::ArcAppInstallEventLog(const base::FilePath& file_name)
: InstallEventLog(file_name) {}
ArcAppInstallEventLog::~ArcAppInstallEventLog() = default;
void ArcAppInstallEventLog::Serialize(em::AppInstallReportRequest* report) {
report->Clear();
for (const auto& log : logs_) {
em::AppInstallReport* const report_log = report->add_app_install_reports();
log.second->Serialize(report_log);
}
}
} // 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_ARC_APP_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_ARC_APP_INSTALL_EVENT_LOG_H_
#include "chrome/browser/chromeos/policy/install_event_log.h"
#include "chrome/browser/chromeos/policy/single_arc_app_install_event_log.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace base {
class FilePath;
} // namespace base
namespace policy {
// An event log for ARC++ app push-installs.
class ArcAppInstallEventLog
: public InstallEventLog<enterprise_management::AppInstallReportLogEvent,
SingleArcAppInstallEventLog> {
public:
explicit ArcAppInstallEventLog(const base::FilePath& file_name);
~ArcAppInstallEventLog();
// 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::AppInstallReportRequest* report);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_ARC_APP_INSTALL_EVENT_LOG_H_
......@@ -2,7 +2,7 @@
// 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 "chrome/browser/chromeos/policy/arc_app_install_event_log.h"
#include <stddef.h>
#include <stdint.h>
......@@ -13,6 +13,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "chrome/browser/chromeos/policy/single_arc_app_install_event_log.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -22,9 +23,6 @@ namespace policy {
namespace {
static const int kLogCapacity = 1024;
static const int kMaxLogs = 1024;
static const char kFirstPackageName[] = "com.example.first";
static const char kSecondPackageName[] = "com.example.second";
static const char kPackageNameTemplate[] = "com.example.";
......@@ -32,14 +30,14 @@ static const char kFileName[] = "event.log";
} // namespace
class AppInstallEventLogTest : public testing::Test {
class ArcAppInstallEventLogTest : public testing::Test {
protected:
AppInstallEventLogTest() {}
ArcAppInstallEventLogTest() {}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_name_ = temp_dir_.GetPath().Append(kFileName);
log_ = std::make_unique<AppInstallEventLog>(file_name_);
log_ = std::make_unique<ArcAppInstallEventLog>(file_name_);
}
void VerifyTenLogEntriesEach(int first_app_timestamp_offset,
......@@ -71,31 +69,32 @@ class AppInstallEventLogTest : public testing::Test {
void OverflowMaxLogs() {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kMaxLogs - 1; ++i) {
for (int i = 0; i < ArcAppInstallEventLog::kMaxLogs - 1; ++i) {
event.set_timestamp(i);
std::stringstream package;
package << kPackageNameTemplate << i;
log_->Add(package.str(), event);
}
for (int i = 0; i < 10; ++i) {
event.set_timestamp(i + kMaxLogs - 1);
event.set_timestamp(i + ArcAppInstallEventLog::kMaxLogs - 1);
log_->Add(kFirstPackageName, event);
}
for (int i = 0; i < 20; ++i) {
event.set_timestamp(i + kMaxLogs + 29);
event.set_timestamp(i + ArcAppInstallEventLog::kMaxLogs + 29);
log_->Add(kSecondPackageName, event);
}
}
void VerifyOneLogEntryEachPlusFirstApp(int first_app_log_entries) {
ASSERT_EQ(kMaxLogs, report_.app_install_reports_size());
ASSERT_EQ(ArcAppInstallEventLog::kMaxLogs,
report_.app_install_reports_size());
std::map<std::string, em::AppInstallReport> logs;
for (int i = 0; i < kMaxLogs; ++i) {
for (int i = 0; i < ArcAppInstallEventLog::kMaxLogs; ++i) {
logs[report_.app_install_reports(i).package()] =
report_.app_install_reports(i);
}
for (int i = 0; i < kMaxLogs - 1; ++i) {
for (int i = 0; i < ArcAppInstallEventLog::kMaxLogs - 1; ++i) {
std::stringstream package;
package << kPackageNameTemplate << i;
const auto log = logs.find(package.str());
......@@ -112,7 +111,8 @@ class AppInstallEventLogTest : public testing::Test {
EXPECT_EQ(kFirstPackageName, log->second.package());
ASSERT_EQ(first_app_log_entries, log->second.logs_size());
for (int i = 0; i < first_app_log_entries; ++i) {
EXPECT_EQ(i + kMaxLogs - 1, log->second.logs(i).timestamp());
EXPECT_EQ(i + ArcAppInstallEventLog::kMaxLogs - 1,
log->second.logs(i).timestamp());
EXPECT_EQ(em::AppInstallReportLogEvent::SUCCESS,
log->second.logs(i).event_type());
}
......@@ -122,16 +122,16 @@ class AppInstallEventLogTest : public testing::Test {
base::ScopedTempDir temp_dir_;
base::FilePath file_name_;
std::unique_ptr<AppInstallEventLog> log_;
std::unique_ptr<ArcAppInstallEventLog> log_;
em::AppInstallReportRequest report_;
private:
DISALLOW_COPY_AND_ASSIGN(AppInstallEventLogTest);
DISALLOW_COPY_AND_ASSIGN(ArcAppInstallEventLogTest);
};
// Do not add any log entries. Serialize the log. Verify that the serialization
// contains no log entries.
TEST_F(AppInstallEventLogTest, SerializeEmpty) {
TEST_F(ArcAppInstallEventLogTest, SerializeEmpty) {
EXPECT_EQ(0, log_->total_size());
EXPECT_EQ(0, log_->max_size());
......@@ -141,7 +141,7 @@ TEST_F(AppInstallEventLogTest, SerializeEmpty) {
// Populate the logs for two apps. Verify that the entries are serialized
// correctly.
TEST_F(AppInstallEventLogTest, AddAndSerialize) {
TEST_F(ArcAppInstallEventLogTest, AddAndSerialize) {
em::AppInstallReportLogEvent event;
event.set_timestamp(0);
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
......@@ -182,7 +182,7 @@ TEST_F(AppInstallEventLogTest, AddAndSerialize) {
// Add 10 log entries for an app. Serialize the log. Clear the serialized log
// entries and verify that the log becomes empty. Then, serialize the log again
// and verify it contains no log entries.
TEST_F(AppInstallEventLogTest, SerializeAndClear) {
TEST_F(ArcAppInstallEventLogTest, SerializeAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -207,7 +207,7 @@ TEST_F(AppInstallEventLogTest, SerializeAndClear) {
// entries each for the first and a second app. Clear the serialized log
// entries. Then, serialize the log again. Verify that it now contains the
// entries added after the first serialization.
TEST_F(AppInstallEventLogTest, SerializeAddClearAndSerialize) {
TEST_F(ArcAppInstallEventLogTest, SerializeAddClearAndSerialize) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -243,9 +243,9 @@ TEST_F(AppInstallEventLogTest, SerializeAddClearAndSerialize) {
// more app. Serialize the log. Verify that the log entries for the last app
// were ignored. Then, clear the serialized log entries. Verify that the log
// becomes empty.
TEST_F(AppInstallEventLogTest, OverflowSerializeAndClear) {
TEST_F(ArcAppInstallEventLogTest, OverflowSerializeAndClear) {
OverflowMaxLogs();
EXPECT_EQ(kMaxLogs + 9, log_->total_size());
EXPECT_EQ(ArcAppInstallEventLog::kMaxLogs + 9, log_->total_size());
EXPECT_EQ(10, log_->max_size());
log_->Serialize(&report_);
......@@ -264,15 +264,15 @@ TEST_F(AppInstallEventLogTest, OverflowSerializeAndClear) {
// more app. Add more entries for one of the apps already in the log. Serialize
// the log. Verify that the log entries for the last app were ignored. Then,
// clear the serialized log entries. Verify that the log becomes empty.
TEST_F(AppInstallEventLogTest, OverflowAddSerializeAndClear) {
TEST_F(ArcAppInstallEventLogTest, OverflowAddSerializeAndClear) {
OverflowMaxLogs();
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 20; ++i) {
event.set_timestamp(i + kMaxLogs + 9);
event.set_timestamp(i + ArcAppInstallEventLog::kMaxLogs + 9);
log_->Add(kFirstPackageName, event);
}
EXPECT_EQ(kMaxLogs + 29, log_->total_size());
EXPECT_EQ(ArcAppInstallEventLog::kMaxLogs + 29, log_->total_size());
EXPECT_EQ(30, log_->max_size());
log_->Serialize(&report_);
......@@ -291,9 +291,9 @@ TEST_F(AppInstallEventLogTest, OverflowAddSerializeAndClear) {
// more app. Serialize the log. Add more entries for one of the apps already in
// the log and another app. Clear the log. Verify that the log now contains the
// entries added after serialization for the app that was already in the log.
TEST_F(AppInstallEventLogTest, OverflowSerializeAddAndClear) {
TEST_F(ArcAppInstallEventLogTest, OverflowSerializeAddAndClear) {
OverflowMaxLogs();
EXPECT_EQ(kMaxLogs + 9, log_->total_size());
EXPECT_EQ(ArcAppInstallEventLog::kMaxLogs + 9, log_->total_size());
EXPECT_EQ(10, log_->max_size());
log_->Serialize(&report_);
......@@ -301,11 +301,11 @@ TEST_F(AppInstallEventLogTest, OverflowSerializeAddAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 20; ++i) {
event.set_timestamp(i + kMaxLogs + 9);
event.set_timestamp(i + ArcAppInstallEventLog::kMaxLogs + 9);
log_->Add(kFirstPackageName, event);
}
for (int i = 0; i < 10; ++i) {
event.set_timestamp(i + kMaxLogs + 49);
event.set_timestamp(i + ArcAppInstallEventLog::kMaxLogs + 49);
log_->Add(kSecondPackageName, event);
}
......@@ -320,37 +320,38 @@ TEST_F(AppInstallEventLogTest, OverflowSerializeAddAndClear) {
EXPECT_EQ(kFirstPackageName, app_log.package());
ASSERT_EQ(20, app_log.logs_size());
for (int i = 0; i < 20; ++i) {
EXPECT_EQ(i + kMaxLogs + 9, app_log.logs(i).timestamp());
EXPECT_EQ(i + ArcAppInstallEventLog::kMaxLogs + 9,
app_log.logs(i).timestamp());
}
}
// Add 10 log entries for a first app and more entries than the log has capacity
// for for a second app. Verify that the total and maximum log sizes are
// reported correctly.
TEST_F(AppInstallEventLogTest, OverflowSingleApp) {
TEST_F(ArcAppInstallEventLogTest, OverflowSingleApp) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
event.set_timestamp(i);
log_->Add(kFirstPackageName, event);
}
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i + 10);
log_->Add(kSecondPackageName, event);
}
EXPECT_EQ(10 + kLogCapacity, log_->total_size());
EXPECT_EQ(kLogCapacity, log_->max_size());
EXPECT_EQ(10 + SingleArcAppInstallEventLog::kLogCapacity, log_->total_size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->max_size());
}
// Create an empty log. Store the log. Verify that no log file is created.
TEST_F(AppInstallEventLogTest, Store) {
TEST_F(ArcAppInstallEventLogTest, Store) {
log_->Store();
EXPECT_FALSE(base::PathExists(file_name_));
}
// Add a log entry. Store the log. Verify that a log file is created. Then,
// delete the log file. Store the log. Verify that no log file is created.
TEST_F(AppInstallEventLogTest, AddStoreAndStore) {
TEST_F(ArcAppInstallEventLogTest, AddStoreAndStore) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
event.set_timestamp(0);
......@@ -366,7 +367,7 @@ TEST_F(AppInstallEventLogTest, AddStoreAndStore) {
// Serialize the log. Clear the serialized log entries. Store the log. Verify
// that no log file is created.
TEST_F(AppInstallEventLogTest, SerializeClearAndStore) {
TEST_F(ArcAppInstallEventLogTest, SerializeClearAndStore) {
log_->Serialize(&report_);
log_->ClearSerialized();
log_->Store();
......@@ -376,7 +377,7 @@ TEST_F(AppInstallEventLogTest, SerializeClearAndStore) {
// Add a log entry. Serialize the log. Clear the serialized log entries. Store
// the log. Verify that a log file is created. Verify that that the log contents
// are loaded correctly.
TEST_F(AppInstallEventLogTest, AddSerializeCleaStoreAndLoad) {
TEST_F(ArcAppInstallEventLogTest, AddSerializeCleaStoreAndLoad) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
event.set_timestamp(0);
......@@ -386,7 +387,7 @@ TEST_F(AppInstallEventLogTest, AddSerializeCleaStoreAndLoad) {
log_->Store();
EXPECT_TRUE(base::PathExists(file_name_));
AppInstallEventLog log(file_name_);
ArcAppInstallEventLog log(file_name_);
EXPECT_EQ(0, log.total_size());
EXPECT_EQ(0, log.max_size());
......@@ -398,7 +399,7 @@ TEST_F(AppInstallEventLogTest, AddSerializeCleaStoreAndLoad) {
// Populate and store a log. Load the log. Verify that that the log contents are
// loaded correctly. Then, delete the log file. Store the log. Verify that no
// log file is created.
TEST_F(AppInstallEventLogTest, StoreLoadAndStore) {
TEST_F(ArcAppInstallEventLogTest, StoreLoadAndStore) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -412,7 +413,7 @@ TEST_F(AppInstallEventLogTest, StoreLoadAndStore) {
log_->Store();
AppInstallEventLog log(file_name_);
ArcAppInstallEventLog log(file_name_);
EXPECT_EQ(20, log.total_size());
EXPECT_EQ(10, log.max_size());
......@@ -428,7 +429,7 @@ TEST_F(AppInstallEventLogTest, StoreLoadAndStore) {
// Populate and serialize a log. Store the log. Load the log. Clear serialized
// entries in the loaded log. Verify that no entries are removed.
TEST_F(AppInstallEventLogTest, SerializeStoreLoadAndClear) {
TEST_F(ArcAppInstallEventLogTest, SerializeStoreLoadAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -440,7 +441,7 @@ TEST_F(AppInstallEventLogTest, SerializeStoreLoadAndClear) {
log_->Store();
AppInstallEventLog log(file_name_);
ArcAppInstallEventLog log(file_name_);
EXPECT_EQ(10, log.total_size());
EXPECT_EQ(10, log.max_size());
......@@ -461,7 +462,7 @@ TEST_F(AppInstallEventLogTest, SerializeStoreLoadAndClear) {
// Populate and serialize a log. Store the log. Change the version in the log
// file. Load the log. Verify that the log contents are not loaded.
TEST_F(AppInstallEventLogTest, LoadVersionMismatch) {
TEST_F(ArcAppInstallEventLogTest, LoadVersionMismatch) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -483,7 +484,7 @@ TEST_F(AppInstallEventLogTest, LoadVersionMismatch) {
file->Write(0, reinterpret_cast<const char*>(&version), sizeof(version)));
file.reset();
AppInstallEventLog log(file_name_);
ArcAppInstallEventLog log(file_name_);
EXPECT_EQ(0, log.total_size());
EXPECT_EQ(0, log.max_size());
......@@ -494,7 +495,7 @@ TEST_F(AppInstallEventLogTest, LoadVersionMismatch) {
// Add 10 log entries each for two apps. Store the log. Truncate the file to the
// length of a log containing 10 log entries for one app plus one byte. Load the
// log. Verify that the log contains 10 logs for one app.
TEST_F(AppInstallEventLogTest, LoadTruncated) {
TEST_F(ArcAppInstallEventLogTest, LoadTruncated) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -519,7 +520,7 @@ TEST_F(AppInstallEventLogTest, LoadTruncated) {
file->SetLength(size + 1);
file.reset();
AppInstallEventLog log(file_name_);
ArcAppInstallEventLog log(file_name_);
EXPECT_EQ(10, log.total_size());
EXPECT_EQ(10, log.max_size());
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2020 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"
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_INSTALL_EVENT_LOG_H_
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "base/files/file.h"
#include "base/files/file_path.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;
#include "base/macros.h"
#include "chrome/browser/chromeos/policy/single_install_event_log.h"
namespace policy {
namespace {
constexpr int64_t kLogFileVersion = 3;
constexpr ssize_t kMaxLogs = 1024;
} // namespace
// An event log for app installs. The app refers to extension or ARC++ app. The
// log entries for each app are kept in a separate round-robin buffer. The log
// can be stored on disk and serialized for upload to a server. Log entries are
// pruned after upload has completed. Uses a sequence checker in
// |AppInstallEventLogManager| to ensure that methods are called from the
// right thread. |T| specifies the event type, and |C| specifies the event log
// class for single app.
template <typename T, typename C>
class InstallEventLog {
public:
// Restores the event log from |file_name|. If there is an error parsing the
// file, as many log entries as possible are restored.
explicit InstallEventLog(const base::FilePath& file_name);
~InstallEventLog();
// The current total number of log entries across apps.
int total_size() { return total_size_; }
// The current maximum number of log entries for a single app.
int max_size() { return max_size_; }
// Add a log entry for |id|. If the buffer for that app is
// full, the oldest entry is removed.
void Add(const std::string& id, const T& event);
// Stores the event log to the file name provided to the constructor. If the
// event log has not changed since it was last stored to disk (or initially
// loaded from disk), does nothing.
void Store();
// Clears log entries that were previously serialized.
void ClearSerialized();
static constexpr int64_t kLogFileVersion = 3;
static constexpr ssize_t kMaxLogs = 1024;
protected:
// The round-robin log event buffers for individual apps.
std::map<std::string, std::unique_ptr<C>> logs_;
const base::FilePath file_name_;
// The current total number of log entries, across all apps.
int total_size_ = 0;
AppInstallEventLog::AppInstallEventLog(const base::FilePath& file_name)
// The current maximum number of log entries for a single app.
int max_size_ = 0;
// Whether the event log changed since it was last stored to disk (or
// initially loaded from disk).
bool dirty_ = false;
};
// Implementation details below here.
template <typename T, typename C>
constexpr int64_t InstallEventLog<T, C>::kLogFileVersion;
template <typename T, typename C>
constexpr ssize_t InstallEventLog<T, C>::kMaxLogs;
template <typename T, typename C>
InstallEventLog<T, C>::InstallEventLog(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())
......@@ -34,7 +91,7 @@ AppInstallEventLog::AppInstallEventLog(const base::FilePath& file_name)
int64_t version;
if (!file.ReadAtCurrentPosAndCheck(
base::as_writable_bytes(base::make_span(&version, 1)))) {
LOG(WARNING) << "Corrupted app install log.";
LOG(WARNING) << "Corrupted install log.";
return;
}
......@@ -46,22 +103,22 @@ AppInstallEventLog::AppInstallEventLog(const base::FilePath& file_name)
ssize_t entries;
if (!file.ReadAtCurrentPosAndCheck(
base::as_writable_bytes(base::make_span(&entries, 1)))) {
LOG(WARNING) << "Corrupted app install log.";
LOG(WARNING) << "Corrupted 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();
std::unique_ptr<C> log;
const bool file_ok = C::Load(&file, &log);
const bool log_ok =
log && !log->id().empty() && logs_.find(log->id()) == logs_.end();
if (!file_ok || !log_ok) {
LOG(WARNING) << "Corrupted app install log.";
LOG(WARNING) << "Corrupted install log.";
}
if (log_ok) {
total_size_ += log->size();
max_size_ = std::max(max_size_, log->size());
logs_[log->package()] = std::move(log);
logs_[log->id()] = std::move(log);
}
if (!file_ok) {
return;
......@@ -69,22 +126,24 @@ AppInstallEventLog::AppInstallEventLog(const base::FilePath& file_name)
}
if (entries >= kMaxLogs) {
LOG(WARNING) << "Corrupted app install log.";
LOG(WARNING) << "Corrupted install log.";
}
}
AppInstallEventLog::~AppInstallEventLog() = default;
template <typename T, typename C>
InstallEventLog<T, C>::~InstallEventLog() = default;
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.";
template <typename T, typename C>
void InstallEventLog<T, C>::Add(const std::string& extension_id,
const T& event) {
if (logs_.size() == kMaxLogs && logs_.find(extension_id) == logs_.end()) {
LOG(WARNING) << "Install log overflow.";
return;
}
auto& log = logs_[package];
auto& log = logs_[extension_id];
if (!log)
log = std::make_unique<SingleAppInstallEventLog>(package);
log = std::make_unique<C>(extension_id);
total_size_ -= log->size();
log->Add(event);
total_size_ += log->size();
......@@ -92,7 +151,8 @@ void AppInstallEventLog::Add(const std::string& package,
dirty_ = true;
}
void AppInstallEventLog::Store() {
template <typename T, typename C>
void InstallEventLog<T, C>::Store() {
if (!dirty_) {
return;
}
......@@ -100,26 +160,26 @@ void AppInstallEventLog::Store() {
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.";
LOG(WARNING) << "Unable to store install log.";
return;
}
if (!file.WriteAtCurrentPosAndCheck(
base::as_bytes(base::make_span(&kLogFileVersion, 1)))) {
LOG(WARNING) << "Unable to store app install log.";
LOG(WARNING) << "Unable to store install log.";
return;
}
ssize_t entries = logs_.size();
if (!file.WriteAtCurrentPosAndCheck(
base::as_bytes(base::make_span(&entries, 1)))) {
LOG(WARNING) << "Unable to store app install log.";
LOG(WARNING) << "Unable to store install log.";
return;
}
for (const auto& log : logs_) {
if (!log.second->Store(&file)) {
LOG(WARNING) << "Unable to store app install log.";
LOG(WARNING) << "Unable to store install log.";
return;
}
}
......@@ -127,15 +187,8 @@ void AppInstallEventLog::Store() {
dirty_ = false;
}
void AppInstallEventLog::Serialize(em::AppInstallReportRequest* report) {
report->Clear();
for (const auto& log : logs_) {
em::AppInstallReport* const report_log = report->add_app_install_reports();
log.second->Serialize(report_log);
}
}
void AppInstallEventLog::ClearSerialized() {
template <typename T, typename C>
void InstallEventLog<T, C>::ClearSerialized() {
int total_size = 0;
max_size_ = 0;
......@@ -158,3 +211,5 @@ void AppInstallEventLog::ClearSerialized() {
}
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_INSTALL_EVENT_LOG_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2020 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 "chrome/browser/chromeos/policy/single_arc_app_install_event_log.h"
#include "base/files/file.h"
......@@ -13,30 +10,15 @@ 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() {}
SingleArcAppInstallEventLog::SingleArcAppInstallEventLog(
const std::string& package)
: SingleInstallEventLog(package) {}
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();
}
}
SingleArcAppInstallEventLog::~SingleArcAppInstallEventLog() {}
bool SingleAppInstallEventLog::Load(
bool SingleArcAppInstallEventLog::Load(
base::File* file,
std::unique_ptr<SingleAppInstallEventLog>* log) {
std::unique_ptr<SingleArcAppInstallEventLog>* log) {
log->reset();
if (!file->IsValid()) {
......@@ -55,7 +37,7 @@ bool SingleAppInstallEventLog::Load(
return false;
}
*log = std::make_unique<SingleAppInstallEventLog>(
*log = std::make_unique<SingleArcAppInstallEventLog>(
std::string(package_buffer.get(), size));
int64_t incomplete;
......@@ -103,61 +85,9 @@ bool SingleAppInstallEventLog::Load(
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) {
void SingleArcAppInstallEventLog::Serialize(em::AppInstallReport* report) {
report->Clear();
report->set_package(package_);
report->set_package(id_);
report->set_incomplete(incomplete_);
for (const auto& event : events_) {
em::AppInstallReportLogEvent* const log_event = report->add_logs();
......@@ -166,14 +96,4 @@ void SingleAppInstallEventLog::Serialize(em::AppInstallReport* report) {
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
......@@ -2,42 +2,27 @@
// 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_
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_ARC_APP_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_ARC_APP_INSTALL_EVENT_LOG_H_
#include <deque>
#include <memory>
#include <string>
#include "chrome/browser/chromeos/policy/single_install_event_log.h"
#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 {
// An event log for a single ARC++ app's push-install process.
class SingleArcAppInstallEventLog
: public SingleInstallEventLog<
enterprise_management::AppInstallReportLogEvent> {
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);
explicit SingleArcAppInstallEventLog(const std::string& package);
~SingleArcAppInstallEventLog();
// Restores the event log from |file| into |log|. Returns |true| if the
// self-delimiting format of the log was parsed successfully and further logs
......@@ -46,41 +31,14 @@ class SingleAppInstallEventLog {
// 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;
std::unique_ptr<SingleArcAppInstallEventLog>* log);
// 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_
#endif // CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_ARC_APP_INSTALL_EVENT_LOG_H_
......@@ -2,13 +2,15 @@
// 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 "chrome/browser/chromeos/policy/single_arc_app_install_event_log.h"
#include <stdint.h>
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "chrome/browser/chromeos/policy/install_event_log.h"
#include "chrome/browser/chromeos/policy/single_install_event_log.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace em = enterprise_management;
......@@ -17,21 +19,19 @@ namespace policy {
namespace {
static const int kLogCapacity = 1024;
static const char kPackageName[] = "com.example.app";
static const int64_t kTimestamp = 12345;
static const char kFileName[] = "event.log";
} // namespace
class SingleAppInstallEventLogTest : public testing::Test {
class SingleArcAppInstallEventLogTest : public testing::Test {
protected:
SingleAppInstallEventLogTest() {}
SingleArcAppInstallEventLogTest() {}
// testing::Test:
void SetUp() override {
log_.reset(new SingleAppInstallEventLog(kPackageName));
log_.reset(new SingleArcAppInstallEventLog(kPackageName));
}
void VerifyHeader(bool incomplete) {
......@@ -50,24 +50,24 @@ class SingleAppInstallEventLogTest : public testing::Test {
base::File::FLAG_READ));
}
std::unique_ptr<SingleAppInstallEventLog> log_;
std::unique_ptr<SingleArcAppInstallEventLog> log_;
em::AppInstallReport report_;
std::unique_ptr<base::ScopedTempDir> temp_dir_;
std::unique_ptr<base::File> file_;
private:
DISALLOW_COPY_AND_ASSIGN(SingleAppInstallEventLogTest);
DISALLOW_COPY_AND_ASSIGN(SingleArcAppInstallEventLogTest);
};
// Verify that the package name is returned correctly.
TEST_F(SingleAppInstallEventLogTest, GetPackage) {
EXPECT_EQ(kPackageName, log_->package());
TEST_F(SingleArcAppInstallEventLogTest, GetPackage) {
EXPECT_EQ(kPackageName, log_->id());
}
// Do not add any log entries. Serialize the log. Verify that the serialization
// contains the the correct header data (package name, incomplete flag) and no
// log entries.
TEST_F(SingleAppInstallEventLogTest, SerializeEmpty) {
TEST_F(SingleArcAppInstallEventLogTest, SerializeEmpty) {
EXPECT_TRUE(log_->empty());
EXPECT_EQ(0, log_->size());
......@@ -77,7 +77,7 @@ TEST_F(SingleAppInstallEventLogTest, SerializeEmpty) {
}
// Add a log entry. Verify that the entry is serialized correctly.
TEST_F(SingleAppInstallEventLogTest, AddAndSerialize) {
TEST_F(SingleArcAppInstallEventLogTest, AddAndSerialize) {
em::AppInstallReportLogEvent event;
event.set_timestamp(kTimestamp);
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
......@@ -97,7 +97,7 @@ TEST_F(SingleAppInstallEventLogTest, AddAndSerialize) {
// Add 10 log entries. Verify that they are serialized correctly. Then, clear
// the serialized log entries and verify that the log becomes empty.
TEST_F(SingleAppInstallEventLogTest, SerializeAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, SerializeAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -126,7 +126,7 @@ TEST_F(SingleAppInstallEventLogTest, SerializeAndClear) {
// Add 10 log entries. Serialize the log. Add 10 more log entries. Clear the
// serialized log entries. Verify that the log now contains the last 10 entries.
TEST_F(SingleAppInstallEventLogTest, SerializeAddAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, SerializeAddAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < 10; ++i) {
......@@ -161,20 +161,20 @@ TEST_F(SingleAppInstallEventLogTest, SerializeAddAndClear) {
// that the serialization contains the most recent log entries and the
// incomplete flag is set. Then, clear the serialized log entries. Verify that
// the log becomes empty and the incomplete flag is unset.
TEST_F(SingleAppInstallEventLogTest, OverflowSerializeAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, OverflowSerializeAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->Serialize(&report_);
VerifyHeader(true /* incomplete */);
ASSERT_EQ(kLogCapacity, report_.logs_size());
for (int i = 0; i < kLogCapacity; ++i) {
ASSERT_EQ(SingleArcAppInstallEventLog::kLogCapacity, report_.logs_size());
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity; ++i) {
EXPECT_EQ(i + 1, report_.logs(i).timestamp());
}
......@@ -191,22 +191,22 @@ TEST_F(SingleAppInstallEventLogTest, OverflowSerializeAndClear) {
// Add more entries than the log has capacity for. Serialize the log. Add one
// more log entry. Clear the serialized log entries. Verify that the log now
// contains the most recent entry and the incomplete flag is unset.
TEST_F(SingleAppInstallEventLogTest, OverflowSerializeAddAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, OverflowSerializeAddAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->Serialize(&report_);
event.set_timestamp(kLogCapacity + 1);
event.set_timestamp(SingleArcAppInstallEventLog::kLogCapacity + 1);
log_->Add(event);
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->ClearSerialized();
EXPECT_FALSE(log_->empty());
......@@ -216,42 +216,44 @@ TEST_F(SingleAppInstallEventLogTest, OverflowSerializeAddAndClear) {
log_->Serialize(&report_);
VerifyHeader(false /* incomplete */);
ASSERT_EQ(1, report_.logs_size());
EXPECT_EQ(kLogCapacity + 1, report_.logs(0).timestamp());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity + 1,
report_.logs(0).timestamp());
}
// Add more entries than the log has capacity for. Serialize the log. Add
// exactly as many entries as the log has capacity for. Clear the serialized log
// entries. Verify that the log now contains the most recent entries and the
// incomplete flag is unset.
TEST_F(SingleAppInstallEventLogTest, OverflowSerializeFillAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, OverflowSerializeFillAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->Serialize(&report_);
for (int i = 0; i < kLogCapacity; ++i) {
event.set_timestamp(kLogCapacity + i);
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity; ++i) {
event.set_timestamp(SingleArcAppInstallEventLog::kLogCapacity + i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->ClearSerialized();
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
report_.Clear();
log_->Serialize(&report_);
VerifyHeader(false /* incomplete */);
ASSERT_EQ(kLogCapacity, report_.logs_size());
for (int i = 0; i < kLogCapacity; ++i) {
EXPECT_EQ(i + kLogCapacity, report_.logs(i).timestamp());
ASSERT_EQ(SingleArcAppInstallEventLog::kLogCapacity, report_.logs_size());
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity; ++i) {
EXPECT_EQ(i + SingleArcAppInstallEventLog::kLogCapacity,
report_.logs(i).timestamp());
}
}
......@@ -259,50 +261,51 @@ TEST_F(SingleAppInstallEventLogTest, OverflowSerializeFillAndClear) {
// entries than the log has capacity for. Clear the serialized log entries.
// Verify that the log now contains the most recent entries and the incomplete
// flag is set.
TEST_F(SingleAppInstallEventLogTest, OverflowSerializeOverflowAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, OverflowSerializeOverflowAndClear) {
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->Serialize(&report_);
for (int i = 0; i < kLogCapacity + 1; ++i) {
event.set_timestamp(kLogCapacity + i);
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(SingleArcAppInstallEventLog::kLogCapacity + i);
log_->Add(event);
}
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
log_->ClearSerialized();
EXPECT_FALSE(log_->empty());
EXPECT_EQ(kLogCapacity, log_->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log_->size());
report_.Clear();
log_->Serialize(&report_);
VerifyHeader(true /* incomplete */);
ASSERT_EQ(kLogCapacity, report_.logs_size());
for (int i = 0; i < kLogCapacity; ++i) {
EXPECT_EQ(i + kLogCapacity + 1, report_.logs(i).timestamp());
ASSERT_EQ(SingleArcAppInstallEventLog::kLogCapacity, report_.logs_size());
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity; ++i) {
EXPECT_EQ(i + SingleArcAppInstallEventLog::kLogCapacity + 1,
report_.logs(i).timestamp());
}
}
// Load log from a file that is not open. Verify that the operation fails.
TEST_F(SingleAppInstallEventLogTest, FailLoad) {
TEST_F(SingleArcAppInstallEventLogTest, FailLoad) {
base::File invalid_file;
std::unique_ptr<SingleAppInstallEventLog> log =
std::make_unique<SingleAppInstallEventLog>(kPackageName);
EXPECT_FALSE(SingleAppInstallEventLog::Load(&invalid_file, &log));
std::unique_ptr<SingleArcAppInstallEventLog> log =
std::make_unique<SingleArcAppInstallEventLog>(kPackageName);
EXPECT_FALSE(SingleArcAppInstallEventLog::Load(&invalid_file, &log));
EXPECT_FALSE(log);
}
// Add a log entry. Store the log to a file that is not open. Verify that the
// operation fails and the log is not modified.
TEST_F(SingleAppInstallEventLogTest, FailStore) {
TEST_F(SingleArcAppInstallEventLogTest, FailStore) {
em::AppInstallReportLogEvent event;
event.set_timestamp(0);
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
......@@ -312,7 +315,7 @@ TEST_F(SingleAppInstallEventLogTest, FailStore) {
base::File invalid_file;
EXPECT_FALSE(log_->Store(&invalid_file));
EXPECT_EQ(kPackageName, log_->package());
EXPECT_EQ(kPackageName, log_->id());
EXPECT_FALSE(log_->empty());
EXPECT_EQ(1, log_->size());
......@@ -324,16 +327,16 @@ TEST_F(SingleAppInstallEventLogTest, FailStore) {
// Store an empty log. Load the log. Verify that that the log contents are
// loaded correctly.
TEST_F(SingleAppInstallEventLogTest, StoreEmptyAndLoad) {
TEST_F(SingleArcAppInstallEventLogTest, StoreEmptyAndLoad) {
ASSERT_NO_FATAL_FAILURE(CreateFile());
log_->Store(file_.get());
file_->Seek(base::File::FROM_BEGIN, 0);
std::unique_ptr<SingleAppInstallEventLog> log;
EXPECT_TRUE(SingleAppInstallEventLog::Load(file_.get(), &log));
std::unique_ptr<SingleArcAppInstallEventLog> log;
EXPECT_TRUE(SingleArcAppInstallEventLog::Load(file_.get(), &log));
ASSERT_TRUE(log);
EXPECT_EQ(kPackageName, log->package());
EXPECT_EQ(kPackageName, log->id());
EXPECT_TRUE(log->empty());
EXPECT_EQ(0, log->size());
......@@ -344,7 +347,7 @@ TEST_F(SingleAppInstallEventLogTest, StoreEmptyAndLoad) {
// Populate and store a log. Load the log. Verify that that the log contents are
// loaded correctly.
TEST_F(SingleAppInstallEventLogTest, StoreAndLoad) {
TEST_F(SingleArcAppInstallEventLogTest, StoreAndLoad) {
ASSERT_NO_FATAL_FAILURE(CreateFile());
em::AppInstallReportLogEvent event;
......@@ -357,10 +360,10 @@ TEST_F(SingleAppInstallEventLogTest, StoreAndLoad) {
log_->Store(file_.get());
file_->Seek(base::File::FROM_BEGIN, 0);
std::unique_ptr<SingleAppInstallEventLog> log;
EXPECT_TRUE(SingleAppInstallEventLog::Load(file_.get(), &log));
std::unique_ptr<SingleArcAppInstallEventLog> log;
EXPECT_TRUE(SingleArcAppInstallEventLog::Load(file_.get(), &log));
ASSERT_TRUE(log);
EXPECT_EQ(kPackageName, log->package());
EXPECT_EQ(kPackageName, log->id());
EXPECT_FALSE(log->empty());
EXPECT_EQ(10, log->size());
......@@ -374,12 +377,12 @@ TEST_F(SingleAppInstallEventLogTest, StoreAndLoad) {
// Add more entries than the log has capacity for. Store the log. Load the log.
// Verify that the log is marked as incomplete.
TEST_F(SingleAppInstallEventLogTest, OverflowStoreAndLoad) {
TEST_F(SingleArcAppInstallEventLogTest, OverflowStoreAndLoad) {
ASSERT_NO_FATAL_FAILURE(CreateFile());
em::AppInstallReportLogEvent event;
event.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
for (int i = 0; i < kLogCapacity + 1; ++i) {
for (int i = 0; i < SingleArcAppInstallEventLog::kLogCapacity + 1; ++i) {
event.set_timestamp(i);
log_->Add(event);
}
......@@ -387,12 +390,12 @@ TEST_F(SingleAppInstallEventLogTest, OverflowStoreAndLoad) {
log_->Store(file_.get());
file_->Seek(base::File::FROM_BEGIN, 0);
std::unique_ptr<SingleAppInstallEventLog> log;
EXPECT_TRUE(SingleAppInstallEventLog::Load(file_.get(), &log));
std::unique_ptr<SingleArcAppInstallEventLog> log;
EXPECT_TRUE(SingleArcAppInstallEventLog::Load(file_.get(), &log));
ASSERT_TRUE(log);
EXPECT_EQ(kPackageName, log->package());
EXPECT_EQ(kPackageName, log->id());
EXPECT_FALSE(log->empty());
EXPECT_EQ(kLogCapacity, log->size());
EXPECT_EQ(SingleArcAppInstallEventLog::kLogCapacity, log->size());
log->Serialize(&report_);
VerifyHeader(true /* incomplete */);
......@@ -400,7 +403,7 @@ TEST_F(SingleAppInstallEventLogTest, OverflowStoreAndLoad) {
// Populate and serialize a log. Store the log. Load the log. Clear serialized
// entries in the loaded log. Verify that no entries are removed.
TEST_F(SingleAppInstallEventLogTest, SerializeStoreLoadAndClear) {
TEST_F(SingleArcAppInstallEventLogTest, SerializeStoreLoadAndClear) {
ASSERT_NO_FATAL_FAILURE(CreateFile());
em::AppInstallReportLogEvent event;
......@@ -415,10 +418,10 @@ TEST_F(SingleAppInstallEventLogTest, SerializeStoreLoadAndClear) {
log_->Store(file_.get());
file_->Seek(base::File::FROM_BEGIN, 0);
std::unique_ptr<SingleAppInstallEventLog> log;
EXPECT_TRUE(SingleAppInstallEventLog::Load(file_.get(), &log));
std::unique_ptr<SingleArcAppInstallEventLog> log;
EXPECT_TRUE(SingleArcAppInstallEventLog::Load(file_.get(), &log));
ASSERT_TRUE(log);
EXPECT_EQ(kPackageName, log->package());
EXPECT_EQ(kPackageName, log->id());
EXPECT_FALSE(log->empty());
EXPECT_EQ(10, log->size());
......@@ -438,7 +441,7 @@ TEST_F(SingleAppInstallEventLogTest, SerializeStoreLoadAndClear) {
// Add 20 log entries. Store the log. Truncate the file to the length of a log
// containing 10 log entries plus one byte. Load the log. Verify that the log
// contains the first 10 log entries and is marked as incomplete.
TEST_F(SingleAppInstallEventLogTest, LoadTruncated) {
TEST_F(SingleArcAppInstallEventLogTest, LoadTruncated) {
ASSERT_NO_FATAL_FAILURE(CreateFile());
em::AppInstallReportLogEvent event;
......@@ -461,10 +464,10 @@ TEST_F(SingleAppInstallEventLogTest, LoadTruncated) {
file_->Seek(base::File::FROM_BEGIN, 0);
file_->SetLength(size + 1);
std::unique_ptr<SingleAppInstallEventLog> log;
EXPECT_FALSE(SingleAppInstallEventLog::Load(file_.get(), &log));
std::unique_ptr<SingleArcAppInstallEventLog> log;
EXPECT_FALSE(SingleArcAppInstallEventLog::Load(file_.get(), &log));
ASSERT_TRUE(log);
EXPECT_EQ(kPackageName, log->package());
EXPECT_EQ(kPackageName, log->id());
EXPECT_FALSE(log->empty());
EXPECT_EQ(10, log->size());
......
// Copyright 2020 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_INSTALL_EVENT_LOG_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_INSTALL_EVENT_LOG_H_
#include <stddef.h>
#include <stdint.h>
#include <deque>
#include <memory>
#include <string>
#include "base/files/file.h"
namespace policy {
// An event log for install process of single app. App refers to extension or
// ARC++ app. The log can be stored on disk and serialized for upload to a
// server. The log is internally held in a round-robin buffer. An |incomplete_|
// 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. |T| specifies the event type.
template <typename T>
class SingleInstallEventLog {
public:
explicit SingleInstallEventLog(const std::string& id);
~SingleInstallEventLog();
const std::string& id() const { return id_; }
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 T& event);
// 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;
// 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();
static const int kLogCapacity = 1024;
static const int kMaxBufferSize = 65536;
protected:
// The app this event log pertains to.
const std::string id_;
// The buffer holding log entries.
std::deque<T> 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;
};
// Implementation details below here.
template <typename T>
const int SingleInstallEventLog<T>::kLogCapacity;
template <typename T>
const int SingleInstallEventLog<T>::kMaxBufferSize;
template <typename T>
SingleInstallEventLog<T>::SingleInstallEventLog(const std::string& id)
: id_(id) {}
template <typename T>
SingleInstallEventLog<T>::~SingleInstallEventLog() {}
template <typename T>
void SingleInstallEventLog<T>::Add(const T& event) {
events_.push_back(event);
if (events_.size() > kLogCapacity) {
incomplete_ = true;
if (serialized_entries_ > -1) {
--serialized_entries_;
}
events_.pop_front();
}
}
template <typename T>
bool SingleInstallEventLog<T>::Store(base::File* file) const {
if (!file->IsValid()) {
return false;
}
ssize_t size = id_.size();
if (file->WriteAtCurrentPos(reinterpret_cast<const char*>(&size),
sizeof(size)) != sizeof(size)) {
return false;
}
if (file->WriteAtCurrentPos(id_.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 T& 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;
}
template <typename T>
void SingleInstallEventLog<T>::ClearSerialized() {
if (serialized_entries_ == -1) {
return;
}
events_.erase(events_.begin(), events_.begin() + serialized_entries_);
serialized_entries_ = -1;
incomplete_ = false;
}
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_SINGLE_INSTALL_EVENT_LOG_H_
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