blob: 6443409fc90990cbd35bcc23a8bd24072b92be07 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/download/internal/background_service/logger_impl.h"
#include <memory>
#include "base/i18n/time_formatting.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "components/download/internal/background_service/driver_entry.h"
#include "components/download/internal/background_service/entry.h"
#include "components/download/internal/background_service/log_source.h"
#include "components/download/public/background_service/clients.h"
#include "components/download/public/background_service/download_params.h"
namespace download {
namespace {
std::string ControllerStateToString(Controller::State state) {
switch (state) {
case Controller::State::CREATED:
return "CREATED";
case Controller::State::INITIALIZING:
return "INITIALIZING";
case Controller::State::READY:
return "READY";
case Controller::State::RECOVERING:
return "RECOVERING";
case Controller::State::UNAVAILABLE: // Intentional fallthrough.
default:
return "UNAVAILABLE";
}
}
std::string OptBoolToString(std::optional<bool> value) {
if (value.has_value())
return value.value() ? "OK" : "BAD";
return "UNKNOWN";
}
std::string EntryStateToString(Entry::State state) {
switch (state) {
case Entry::State::NEW:
return "NEW";
case Entry::State::AVAILABLE:
return "AVAILABLE";
case Entry::State::ACTIVE:
return "ACTIVE";
case Entry::State::PAUSED:
return "PAUSED";
case Entry::State::COMPLETE:
return "COMPLETE";
default:
NOTREACHED();
}
}
std::string DriverEntryStateToString(DriverEntry::State state) {
switch (state) {
case DriverEntry::State::IN_PROGRESS:
return "IN_PROGRESS";
case DriverEntry::State::COMPLETE:
return "COMPLETE";
case DriverEntry::State::CANCELLED:
return "CANCELLED";
case DriverEntry::State::INTERRUPTED:
return "INTERRUPTED";
default:
NOTREACHED();
}
}
std::string CompletionTypeToString(CompletionType type) {
switch (type) {
case CompletionType::SUCCEED:
return "SUCCEED";
case CompletionType::FAIL:
return "FAIL";
case CompletionType::ABORT:
return "ABORT";
case CompletionType::TIMEOUT:
return "TIMEOUT";
case CompletionType::UNKNOWN:
return "UNKNOWN";
case CompletionType::CANCEL:
return "CANCEL";
case CompletionType::OUT_OF_RETRIES:
return "OUT_OF_RETRIES";
case CompletionType::OUT_OF_RESUMPTIONS:
return "OUT_OF_RESUMPTIONS";
default:
NOTREACHED();
}
}
std::string StartResultToString(DownloadParams::StartResult result) {
switch (result) {
case DownloadParams::StartResult::ACCEPTED:
return "ACCEPTED";
case DownloadParams::StartResult::BACKOFF:
return "BACKOFF";
case DownloadParams::StartResult::UNEXPECTED_CLIENT:
return "UNEXPECTED_CLIENT";
case DownloadParams::StartResult::UNEXPECTED_GUID:
return "UNEXPECTED_GUID";
case DownloadParams::StartResult::CLIENT_CANCELLED:
return "CLIENT_CANCELLED";
case DownloadParams::StartResult::INTERNAL_ERROR:
return "INTERNAL_ERROR";
default:
NOTREACHED();
}
}
base::Value::Dict DriverEntryToValue(const DriverEntry& entry) {
base::Value::Dict serialized_entry;
serialized_entry.Set("state", DriverEntryStateToString(entry.state));
serialized_entry.Set("paused", entry.paused);
serialized_entry.Set("done", entry.done);
return serialized_entry;
}
base::Value::Dict EntryToValue(
const Entry& entry,
const std::optional<DriverEntry>& driver,
const std::optional<CompletionType>& completion_type) {
base::Value::Dict serialized_entry;
serialized_entry.Set("client",
BackgroundDownloadClientToString(entry.client));
serialized_entry.Set("state", EntryStateToString(entry.state));
serialized_entry.Set("guid", entry.guid);
// Convert the URL to a proper logging format.
GURL::Replacements replacements;
replacements.ClearQuery();
serialized_entry.Set(
"url", entry.request_params.url.ReplaceComponents(replacements).spec());
serialized_entry.Set("file_path", entry.target_file_path.MaybeAsASCII());
if (driver.has_value()) {
serialized_entry.Set("bytes_downloaded",
static_cast<double>(driver->bytes_downloaded));
serialized_entry.Set("driver", DriverEntryToValue(driver.value()));
serialized_entry.Set("time_downloaded",
base::TimeFormatHTTP(driver->completion_time));
} else {
serialized_entry.Set("bytes_downloaded",
static_cast<double>(entry.bytes_downloaded));
serialized_entry.Set("time_downloaded",
base::TimeFormatHTTP(entry.completion_time));
}
if (completion_type.has_value()) {
serialized_entry.Set("result",
CompletionTypeToString(completion_type.value()));
} else if (entry.state == Entry::State::COMPLETE) {
serialized_entry.Set("result",
CompletionTypeToString(CompletionType::SUCCEED));
}
return serialized_entry;
}
} // namespace
LoggerImpl::LoggerImpl() : log_source_(nullptr) {}
LoggerImpl::~LoggerImpl() = default;
void LoggerImpl::SetLogSource(LogSource* log_source) {
log_source_ = log_source;
}
void LoggerImpl::AddObserver(Observer* observer) {
DCHECK(!observers_.HasObserver(observer));
observers_.AddObserver(observer);
}
void LoggerImpl::RemoveObserver(Observer* observer) {
DCHECK(observers_.HasObserver(observer));
observers_.RemoveObserver(observer);
}
base::Value::Dict LoggerImpl::GetServiceStatus() {
base::Value::Dict service_status;
if (!log_source_)
return service_status;
Controller::State state = log_source_->GetControllerState();
const StartupStatus& status = log_source_->GetStartupStatus();
service_status.Set("serviceState", ControllerStateToString(state));
service_status.Set("modelStatus", OptBoolToString(status.model_ok));
service_status.Set("driverStatus", OptBoolToString(status.driver_ok));
service_status.Set("fileMonitorStatus",
OptBoolToString(status.file_monitor_ok));
return service_status;
}
base::Value::List LoggerImpl::GetServiceDownloads() {
base::Value::List serialized_entries;
if (!log_source_)
return serialized_entries;
auto entries = log_source_->GetServiceDownloads();
for (auto& entry : entries) {
serialized_entries.Append(
EntryToValue(*entry.first, entry.second, std::nullopt));
}
return serialized_entries;
}
void LoggerImpl::OnServiceStatusChanged() {
if (observers_.empty())
return;
base::Value::Dict service_status = GetServiceStatus();
for (auto& observer : observers_)
observer.OnServiceStatusChanged(service_status);
}
void LoggerImpl::OnServiceDownloadsAvailable() {
if (observers_.empty())
return;
base::Value::List service_downloads = GetServiceDownloads();
for (auto& observer : observers_)
observer.OnServiceDownloadsAvailable(service_downloads);
}
void LoggerImpl::OnServiceDownloadChanged(const std::string& guid) {
if (observers_.empty())
return;
auto entry_details = log_source_->GetServiceDownload(guid);
if (!entry_details.has_value())
return;
auto entry = EntryToValue(*(entry_details->first), entry_details->second,
std::nullopt);
for (auto& observer : observers_)
observer.OnServiceDownloadChanged(entry);
}
void LoggerImpl::OnServiceDownloadFailed(CompletionType completion_type,
const Entry& entry) {
DCHECK_NE(CompletionType::SUCCEED, completion_type);
if (observers_.empty())
return;
auto serialized_entry = EntryToValue(entry, std::nullopt, completion_type);
for (auto& observer : observers_)
observer.OnServiceDownloadFailed(serialized_entry);
}
void LoggerImpl::OnServiceRequestMade(
DownloadClient client,
const std::string& guid,
DownloadParams::StartResult start_result) {
if (observers_.empty())
return;
base::Value::Dict serialized_request;
serialized_request.Set("client", BackgroundDownloadClientToString(client));
serialized_request.Set("guid", guid);
serialized_request.Set("result", StartResultToString(start_result));
for (auto& observer : observers_)
observer.OnServiceRequestMade(serialized_request);
}
} // namespace download