chromium/chrome/browser/ash/policy/reporting/arc_app_install_event_log_manager.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/policy/reporting/arc_app_install_event_log_manager.h"

#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/ash/app_list/arc/arc_app_utils.h"
#include "chrome/browser/profiles/profile.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");

// 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

ArcAppInstallEventLogManager::ArcAppInstallEventLogManager(
    LogTaskRunnerWrapper* log_task_runner_wrapper,
    ArcAppInstallEventLogUploader* uploader,
    Profile* profile)
    : InstallEventLogManagerBase(log_task_runner_wrapper, profile),
      uploader_(uploader) {
  uploader_->SetDelegate(this);
  log_ = std::make_unique<ArcLog>();
  app_log_upload_ = std::make_unique<AppLogUpload>(this);
  log_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&ArcLog::Init, base::Unretained(log_.get()),
                     GetLogFilePath(*profile)),
      base::BindOnce(&ArcAppInstallEventLogManager::AppLogUpload::OnLogInit,
                     app_log_upload_->log_weak_factory_.GetWeakPtr()));
  logger_ = std::make_unique<ArcAppInstallEventLogger>(this, profile);
}

ArcAppInstallEventLogManager::~ArcAppInstallEventLogManager() {
  logger_.reset();
  // Destroy |app_log_upload_| after |logger_| otherwise it is possible
  // that when we add new logs created through |logger_| cause the crash as
  // |app_log_upload_| will be destroyed already.
  app_log_upload_.reset();
  uploader_->SetDelegate(nullptr);
  log_task_runner_->DeleteSoon(FROM_HERE, std::move(log_));
}

// static
void ArcAppInstallEventLogManager::Clear(
    LogTaskRunnerWrapper* log_task_runner_wrapper,
    Profile* profile) {
  ArcAppInstallEventLogger::Clear(profile);
  log_task_runner_wrapper->GetTaskRunner()->PostTask(
      FROM_HERE, base::GetDeleteFileCallback(GetLogFilePath(*profile)));
}

void ArcAppInstallEventLogManager::Add(
    const std::set<std::string>& packages,
    const em::AppInstallReportLogEvent& event) {
  if (packages.empty()) {
    return;
  }
  // If --arc-install-event-chrome-log-for-tests is present, write event logs to
  // Chrome log (/var/log/chrome). LOG(ERROR) ensures that logs are written.
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          ash::switches::kArcInstallEventChromeLogForTests)) {
    for (std::string package : packages)
      LOG(ERROR) << "Add ARC install event: " << package << ", "
                 << event.event_type();
  }

  log_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&ArcLog::Add, base::Unretained(log_.get()), packages,
                     event),
      base::BindOnce(&ArcAppInstallEventLogManager::AppLogUpload::OnLogChange,
                     app_log_upload_->log_weak_factory_.GetWeakPtr()));
}

void ArcAppInstallEventLogManager::GetAndroidId(
    ArcAppInstallEventLogger::Delegate::AndroidIdCallback callback) const {
  arc::GetAndroidId(std::move(callback));
}

void ArcAppInstallEventLogManager::SerializeForUpload(
    ArcAppInstallEventLogUploader::Delegate::SerializationCallback callback) {
  log_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&ArcAppInstallEventLogManager::ArcLog::Serialize,
                     base::Unretained(log_.get())),
      base::BindOnce(
          &ArcAppInstallEventLogManager::LogUpload::OnSerializeLogDone<
              ArcAppInstallEventLogUploader::Delegate::SerializationCallback,
              em::AppInstallReportRequest>,
          app_log_upload_->log_weak_factory_.GetWeakPtr(),
          std::move(callback)));
}

void ArcAppInstallEventLogManager::OnUploadSuccess() {
  if (app_log_upload_->store_scheduled_) {
    app_log_upload_->store_scheduled_ = false;
    app_log_upload_->store_weak_factory_.InvalidateWeakPtrs();
  }
  app_log_upload_->upload_requested_ = false;

  log_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(
          &ArcAppInstallEventLogManager::ArcLog::ClearSerializedAndStore,
          base::Unretained(log_.get())),
      base::BindOnce(&ArcAppInstallEventLogManager::AppLogUpload::OnLogChange,
                     app_log_upload_->log_weak_factory_.GetWeakPtr()));
}

ArcAppInstallEventLogManager::ArcLog::ArcLog() : InstallLog() {
  DETACH_FROM_SEQUENCE(sequence_checker_);
}

ArcAppInstallEventLogManager::ArcLog::~ArcLog() {}

std::unique_ptr<em::AppInstallReportRequest>
ArcAppInstallEventLogManager::ArcLog::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;
}

ArcAppInstallEventLogManager::AppLogUpload::AppLogUpload(
    ArcAppInstallEventLogManager* owner)
    : owner_(owner) {}
ArcAppInstallEventLogManager::AppLogUpload::~AppLogUpload() = default;

void ArcAppInstallEventLogManager::AppLogUpload::StoreLog() {
  CHECK(owner_->log_);
  store_scheduled_ = false;
  owner_->log_task_runner_->PostTask(
      FROM_HERE,
      base::BindOnce(&ArcLog::Store, base::Unretained(owner_->log_.get())));
}

void ArcAppInstallEventLogManager::AppLogUpload::RequestUploadForUploader() {
  owner_->uploader_->RequestUpload();
}

}  // namespace policy