blob: 790283cf15d9fc8b5d9a5a21aa8a8d66f7a9aeb3 [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_manager.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#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/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy {
namespace {
// The log file, stored in the user's profile directory.
constexpr base::FilePath::CharType kLogFileName[] =
FILE_PATH_LITERAL("app_push_install_log");
// Delay after which a change to the log contents is stored to disk. Further
// changes during this time window are picked up by the same store operation.
constexpr base::TimeDelta kStoreDelay = base::TimeDelta::FromSeconds(5);
// Interval between subsequent uploads to the server, if the log is not empty.
constexpr base::TimeDelta kUploadInterval = base::TimeDelta::FromHours(3);
// Delay of an expedited upload to the server, used for the first upload after
// the |AppInstallEventLogManager| is constructed and whenever the log is
// getting full.
constexpr base::TimeDelta kExpeditedUploadDelay =
base::TimeDelta::FromMinutes(15);
// An expedited upload is scheduled whenever the total number of log entries
// exceeds |kTotalSizeExpeditedUploadThreshold| or the number of log entries for
// any single app exceeds |kMaxSizeExpeditedUploadThreshold|.
constexpr int kTotalSizeExpeditedUploadThreshold = 2048;
constexpr int kMaxSizeExpeditedUploadThreshold = 512;
// Returns the path to the app push-install event log file for |profile|.
base::FilePath GetLogFilePath(const Profile& profile) {
return profile.GetPath().Append(kLogFileName);
}
} // namespace
AppInstallEventLogManager::LogTaskRunnerWrapper::LogTaskRunnerWrapper() =
default;
AppInstallEventLogManager::LogTaskRunnerWrapper::~LogTaskRunnerWrapper() =
default;
scoped_refptr<base::SequencedTaskRunner>
AppInstallEventLogManager::LogTaskRunnerWrapper::GetTaskRunner() {
if (!task_runner_) {
task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
}
return task_runner_;
}
AppInstallEventLogManager::AppInstallEventLogManager(
LogTaskRunnerWrapper* log_task_runner_wrapper,
AppInstallEventLogUploader* uploader,
Profile* profile)
: log_task_runner_(log_task_runner_wrapper->GetTaskRunner()),
uploader_(uploader) {
uploader_->SetDelegate(this);
log_ = std::make_unique<Log>();
base::PostTaskAndReplyWithResult(
log_task_runner_.get(), FROM_HERE,
base::BindOnce(&Log::Init, base::Unretained(log_.get()),
GetLogFilePath(*profile)),
base::BindOnce(&AppInstallEventLogManager::OnLogInit,
log_weak_factory_.GetWeakPtr()));
logger_ = std::make_unique<AppInstallEventLogger>(this, profile);
}
AppInstallEventLogManager::~AppInstallEventLogManager() {
logger_.reset();
uploader_->SetDelegate(nullptr);
log_task_runner_->DeleteSoon(FROM_HERE, std::move(log_));
}
// static
void AppInstallEventLogManager::Clear(
LogTaskRunnerWrapper* log_task_runner_wrapper,
Profile* profile) {
AppInstallEventLogger::Clear(profile);
log_task_runner_wrapper->GetTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(
[](const base::FilePath& log_file_path) {
base::DeleteFile(log_file_path, false /* recursive */);
},
GetLogFilePath(*profile)));
}
void AppInstallEventLogManager::Add(const std::set<std::string>& packages,
const em::AppInstallReportLogEvent& event) {
if (packages.empty()) {
return;
}
base::PostTaskAndReplyWithResult(
log_task_runner_.get(), FROM_HERE,
base::BindOnce(&Log::Add, base::Unretained(log_.get()), packages, event),
base::BindOnce(&AppInstallEventLogManager::OnLogChange,
log_weak_factory_.GetWeakPtr()));
}
void AppInstallEventLogManager::GetAndroidId(
AppInstallEventLogger::Delegate::AndroidIdCallback callback) const {
arc::GetAndroidId(std::move(callback));
}
void AppInstallEventLogManager::SerializeForUpload(
AppInstallEventLogUploader::Delegate::SerializationCallback callback) {
base::PostTaskAndReplyWithResult(
log_task_runner_.get(), FROM_HERE,
base::BindOnce(&AppInstallEventLogManager::Log::Serialize,
base::Unretained(log_.get())),
base::BindOnce(&AppInstallEventLogManager::OnSerializeLogDone,
log_weak_factory_.GetWeakPtr(), std::move(callback)));
}
void AppInstallEventLogManager::OnUploadSuccess() {
if (store_scheduled_) {
store_scheduled_ = false;
store_weak_factory_.InvalidateWeakPtrs();
}
upload_requested_ = false;
base::PostTaskAndReplyWithResult(
log_task_runner_.get(), FROM_HERE,
base::BindOnce(&AppInstallEventLogManager::Log::ClearSerializedAndStore,
base::Unretained(log_.get())),
base::BindOnce(&AppInstallEventLogManager::OnLogChange,
log_weak_factory_.GetWeakPtr()));
}
AppInstallEventLogManager::Log::Log() {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
AppInstallEventLogManager::Log::~Log() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->Store();
}
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);
return GetSize();
}
AppInstallEventLogManager::LogSize AppInstallEventLogManager::Log::Add(
const std::set<std::string>& packages,
const em::AppInstallReportLogEvent& event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
for (const auto& package : packages) {
log_->Add(package, event);
}
return GetSize();
}
void AppInstallEventLogManager::Log::Store() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->Store();
}
std::unique_ptr<em::AppInstallReportRequest>
AppInstallEventLogManager::Log::Serialize() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
auto serialized_log = std::make_unique<em::AppInstallReportRequest>();
log_->Serialize(serialized_log.get());
return serialized_log;
}
AppInstallEventLogManager::LogSize
AppInstallEventLogManager::Log::ClearSerializedAndStore() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(log_);
log_->ClearSerialized();
log_->Store();
return GetSize();
}
AppInstallEventLogManager::LogSize AppInstallEventLogManager::Log::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;
}
void AppInstallEventLogManager::OnLogInit(const LogSize& log_size) {
OnLogChange(log_size);
EnsureUpload(true /* expedited */);
}
void AppInstallEventLogManager::OnLogChange(const LogSize& log_size) {
log_size_ = log_size;
if (!log_size.total_size) {
if (upload_scheduled_) {
upload_scheduled_ = false;
expedited_upload_scheduled_ = false;
upload_weak_factory_.InvalidateWeakPtrs();
}
return;
}
if (!store_scheduled_) {
store_scheduled_ = true;
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AppInstallEventLogManager::StoreLog,
store_weak_factory_.GetWeakPtr()),
kStoreDelay);
}
EnsureUpload(log_size.total_size > kTotalSizeExpeditedUploadThreshold ||
log_size.max_size >
kMaxSizeExpeditedUploadThreshold /* expedited*/);
}
void AppInstallEventLogManager::OnSerializeLogDone(
AppInstallEventLogUploader::Delegate::SerializationCallback callback,
std::unique_ptr<em::AppInstallReportRequest> log) {
std::move(callback).Run(log.get());
}
void AppInstallEventLogManager::StoreLog() {
CHECK(log_);
store_scheduled_ = false;
log_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&Log::Store, base::Unretained(log_.get())));
}
void AppInstallEventLogManager::EnsureUpload(bool expedited) {
if (upload_requested_ ||
(upload_scheduled_ && (expedited_upload_scheduled_ || !expedited))) {
return;
}
if (upload_scheduled_) {
upload_weak_factory_.InvalidateWeakPtrs();
}
upload_scheduled_ = true;
expedited_upload_scheduled_ = expedited;
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AppInstallEventLogManager::RequestUpload,
upload_weak_factory_.GetWeakPtr()),
expedited ? kExpeditedUploadDelay : kUploadInterval);
}
void AppInstallEventLogManager::RequestUpload() {
upload_scheduled_ = false;
expedited_upload_scheduled_ = false;
if (!log_size_.total_size) {
return;
}
upload_requested_ = true;
uploader_->RequestUpload();
}
} // namespace policy