1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_POLICY_REPORTING_INSTALL_EVENT_LOG_MANAGER_H_
#define CHROME_BROWSER_ASH_POLICY_REPORTING_INSTALL_EVENT_LOG_MANAGER_H_
#include <memory>
#include <set>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
class Profile;
namespace base {
class FilePath;
class SequencedTaskRunner;
} // namespace base
namespace policy {
// Ties together collection, storage and upload of app install event logs. The
// app refers to extension or ARC++ app.
// 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
// been successfully uploaded to the server and on logout.
//
// Uploads to the server are scheduled as follows:
// * The first upload happens fifteen minutes after |this| is instantiated. This
// ensures that initial activity in short-lived, ephemeral sessions is not
// lost.
// * Subsequent uploads are scheduled three hours after the last successful
// upload and suspended if the log becomes empty.
// * If the log is getting full, the next upload is expedited from three hours
// to fifteen minutes delay.
class InstallEventLogManagerBase {
public:
// Helper that returns a |base::SequencedTaskRunner| for background operations
// on an event log. All background operations relating to a given log file,
// whether by an |InstallEventLogManagerBase| or any other class, must use the
// same |base::SequencedTaskRunner| returned by a |LogTaskRunnerWrapper|
// instance to ensure correct serialization.
class LogTaskRunnerWrapper {
public:
LogTaskRunnerWrapper();
virtual ~LogTaskRunnerWrapper();
// Returns a |base::SequencedTaskRunner| that executes tasks in order and
// runs any pending tasks on shutdown (to ensure the log is stored to disk).
// Virtual for testing.
virtual scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
private:
scoped_refptr<base::SequencedTaskRunner> task_runner_;
};
// All accesses to the |profile|'s app install event log file must use
// the same |log_task_runner_wrapper| to ensure correct I/O serialization.
InstallEventLogManagerBase(LogTaskRunnerWrapper* log_task_runner_wrapper,
Profile* profile);
~InstallEventLogManagerBase();
// The current size of the log, returned by each operation on the log store.
struct LogSize {
// The total number of log entries, across all apps.
int total_size;
// The maximum number of log entries for a single app.
int max_size;
};
// Once created, |InstallLog| runs in the background and must be accessed and
// eventually destroyed via |log_task_runner_|. |T| specifies the event type
// and |C| specifies the type of type of event log class.
template <typename T, class C>
class InstallLog {
public:
InstallLog();
InstallLog(const InstallLog<T, C>& install_log) = delete;
InstallLog<T, C> operator=(const InstallLog<T, C>& install_log) = delete;
virtual ~InstallLog();
// Loads the log from disk or creates an empty log if the log file does not
// exist. Must be called before any other methods, including the destructor.
LogSize Init(const base::FilePath& file_path);
// Adds an identical log entry for each app in |ids|.
LogSize Add(const std::set<std::string>& ids, const T& event);
// Stores the log to disk.
void Store();
// Clears log entries that were previously serialized and stores the
// resulting log to disk.
LogSize ClearSerializedAndStore();
protected:
// Returns the current size of the log.
LogSize GetSize() const;
// The actual log store.
std::unique_ptr<C> log_;
// Ensures that methods are not called from the wrong thread.
SEQUENCE_CHECKER(sequence_checker_);
};
// Helper class that manages the storing and uploading of logs.
class LogUpload {
public:
LogUpload();
virtual ~LogUpload() = 0;
// Callback invoked by |InstallLog::Init()|. Schedules the first log upload.
void OnLogInit(const LogSize& log_size);
// Callback invoked by all other operations on |InstallLog| that may change
// its contents. (Re-)schedules log upload and log storage to disk.
void OnLogChange(const LogSize& log_size);
// Stores the log to disk.
virtual void StoreLog() = 0;
// Ensure that an upload is either already requested or scheduled for the
// future. If |expedited| is |true|, ensures that a scheduled upload lies no
// more than fifteen minutes in the future.
void EnsureUpload(bool expedited);
// Requests that uploader upload the log to the server.
void RequestUpload();
virtual void RequestUploadForUploader() = 0;
template <typename T, typename C>
void OnSerializeLogDone(T callback, std::unique_ptr<C> log);
// The current size of the log.
LogSize log_size_;
// Any change to the log contents causes a task to be scheduled that will
// store the log contents to disk five seconds later. Changes during this
// five second window will be picked up by the scheduled store and do not
// require another store to be scheduled.
bool store_scheduled_ = false;
// Whether an upload request has been sent to the uploader already. If
// so, no further uploads are scheduled until the current request is
// successful. The uploader retries indefinitely on errors.
bool upload_requested_ = false;
// Whether an upload has been scheduled for some time in the future.
bool upload_scheduled_ = false;
// Whether a scheduled upload is expedited (fifteen minute delay) instead of
// regular (three hour delay).
bool expedited_upload_scheduled_ = false;
// After successful upload, uploaded log entries are cleared and the log is
// stored to disk. If a store task is scheduled, this factory's weak
// pointers are invalidated to cancel it and avoid unnecessary I/O.
base::WeakPtrFactory<LogUpload> store_weak_factory_{this};
// Invalidated to cancel a pending upload when the log becomes empty after
// upload or an expedited upload is needed instead of a previously scheduled
// regular upload.
base::WeakPtrFactory<LogUpload> upload_weak_factory_{this};
// Used by log store owner to access |this|. Invalidated when |this| is
// destroyed as log store owner outlives it.
base::WeakPtrFactory<LogUpload> log_weak_factory_{this};
};
// Task runner via which log store owner is accessed.
const scoped_refptr<base::SequencedTaskRunner> log_task_runner_;
};
// Implementation details.
template <typename T, class C>
InstallEventLogManagerBase::InstallLog<T, C>::InstallLog() {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
template <typename T, class C>
InstallEventLogManagerBase::InstallLog<T, C>::~InstallLog() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->Store();
}
template <typename T, class C>
InstallEventLogManagerBase::LogSize
InstallEventLogManagerBase::InstallLog<T, C>::Init(
const base::FilePath& file_path) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!log_);
log_ = std::make_unique<C>(file_path);
return GetSize();
}
template <typename T, class C>
InstallEventLogManagerBase::LogSize
InstallEventLogManagerBase::InstallLog<T, C>::Add(
const std::set<std::string>& ids,
const T& event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
for (const auto& id : ids) {
log_->Add(id, event);
}
return GetSize();
}
template <typename T, class C>
void InstallEventLogManagerBase::InstallLog<T, C>::Store() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->Store();
}
template <typename T, class C>
InstallEventLogManagerBase::LogSize
InstallEventLogManagerBase::InstallLog<T, C>::ClearSerializedAndStore() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->ClearSerialized();
log_->Store();
return GetSize();
}
template <typename T, class C>
InstallEventLogManagerBase::LogSize
InstallEventLogManagerBase::InstallLog<T, C>::GetSize() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
LogSize size;
size.total_size = log_->total_size();
size.max_size = log_->max_size();
return size;
}
template <typename T, typename C>
void InstallEventLogManagerBase::LogUpload::OnSerializeLogDone(
T callback,
std::unique_ptr<C> log) {
std::move(callback).Run(log.get());
}
} // namespace policy
#endif // CHROME_BROWSER_ASH_POLICY_REPORTING_INSTALL_EVENT_LOG_MANAGER_H_
|