blob: cc871a3ba11fa57bb4ee93d3b06931a222f68f5f [file] [log] [blame]
// 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/metrics/cros_healthd_metrics_provider.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "third_party/metrics_proto/system_profile.pb.h"
using metrics::SystemProfileProto;
namespace {
constexpr base::TimeDelta kServiceDiscoveryTimeout =
base::TimeDelta::FromSeconds(5);
} // namespace
CrosHealthdMetricsProvider::CrosHealthdMetricsProvider() = default;
CrosHealthdMetricsProvider::~CrosHealthdMetricsProvider() = default;
base::TimeDelta CrosHealthdMetricsProvider::GetTimeout() {
return kServiceDiscoveryTimeout;
}
void CrosHealthdMetricsProvider::AsyncInit(base::OnceClosure done_callback) {
const std::vector<chromeos::cros_healthd::mojom::ProbeCategoryEnum>
categories_to_probe = {chromeos::cros_healthd::mojom::ProbeCategoryEnum::
kNonRemovableBlockDevices};
DCHECK(init_callback_.is_null());
init_callback_ = std::move(done_callback);
initialized_ = false;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&CrosHealthdMetricsProvider::OnProbeTimeout,
weak_ptr_factory_.GetWeakPtr()),
GetTimeout());
GetService()->ProbeTelemetryInfo(
categories_to_probe,
base::BindOnce(&CrosHealthdMetricsProvider::OnProbeDone,
weak_ptr_factory_.GetWeakPtr()));
}
bool CrosHealthdMetricsProvider::IsInitialized() {
return initialized_;
}
void CrosHealthdMetricsProvider::OnProbeTimeout() {
base::ScopedClosureRunner runner(std::move(init_callback_));
DVLOG(1) << "cros_healthd: endpoint is not found.";
// Invalidate OnProbeDone callback.
weak_ptr_factory_.InvalidateWeakPtrs();
devices_.clear();
initialized_ = false;
}
void CrosHealthdMetricsProvider::OnProbeDone(
chromeos::cros_healthd::mojom::TelemetryInfoPtr ptr) {
base::ScopedClosureRunner runner(std::move(init_callback_));
// Invalidate OnProbeTimeout callback.
weak_ptr_factory_.InvalidateWeakPtrs();
devices_.clear();
initialized_ = true;
if (ptr.is_null()) {
DVLOG(1) << "cros_healthd: Empty response";
return;
}
const auto& block_device_result = ptr->block_device_result;
if (block_device_result.is_null()) {
DVLOG(1) << "cros_healthd: No block device info";
return;
}
auto tag = block_device_result->which();
if (tag == chromeos::cros_healthd::mojom::NonRemovableBlockDeviceResult::Tag::
ERROR) {
DVLOG(1) << "cros_healthd: Error getting block device info: "
<< block_device_result->get_error()->msg;
return;
}
DCHECK_EQ(tag, chromeos::cros_healthd::mojom::NonRemovableBlockDeviceResult::
Tag::BLOCK_DEVICE_INFO);
for (const auto& storage : block_device_result->get_block_device_info()) {
SystemProfileProto::Hardware::InternalStorageDevice dev;
const auto& vendor_id = storage->vendor_id;
const auto& product_id = storage->product_id;
const auto& revision = storage->revision;
const auto& fw_version = storage->firmware_version;
const auto& type = storage->type;
if (base::StartsWith(type, "block:nvme",
base::CompareCase::INSENSITIVE_ASCII)) {
DCHECK(vendor_id->is_nvme_subsystem_vendor());
DCHECK(product_id->is_nvme_subsystem_device());
DCHECK(revision->is_nvme_pcie_rev());
DCHECK(fw_version->is_nvme_firmware_rev());
dev.set_type(
SystemProfileProto::Hardware::InternalStorageDevice::TYPE_NVME);
dev.set_vendor_id(vendor_id->get_nvme_subsystem_vendor());
dev.set_product_id(product_id->get_nvme_subsystem_device());
dev.set_revision(revision->get_nvme_pcie_rev());
dev.set_firmware_version(fw_version->get_nvme_firmware_rev());
} else if (base::StartsWith(type, "block:mmc",
base::CompareCase::INSENSITIVE_ASCII)) {
DCHECK(vendor_id->is_emmc_oemid());
DCHECK(product_id->is_emmc_pnm());
DCHECK(revision->is_emmc_prv());
DCHECK(fw_version->is_emmc_fwrev());
dev.set_type(
SystemProfileProto::Hardware::InternalStorageDevice::TYPE_EMMC);
dev.set_vendor_id(vendor_id->get_emmc_oemid());
dev.set_product_id(product_id->get_emmc_pnm());
dev.set_revision(revision->get_emmc_prv());
dev.set_firmware_version(fw_version->get_emmc_fwrev());
} else {
// Skip reporting entries for the unknown types.
continue;
}
switch (storage->purpose) {
case chromeos::cros_healthd::mojom::StorageDevicePurpose::kUnknown:
dev.set_purpose(SystemProfileProto::Hardware::InternalStorageDevice::
PURPOSE_UNKNOWN);
break;
case chromeos::cros_healthd::mojom::StorageDevicePurpose::kBootDevice:
dev.set_purpose(
SystemProfileProto::Hardware::InternalStorageDevice::PURPOSE_BOOT);
break;
case chromeos::cros_healthd::mojom::StorageDevicePurpose::kSwapDevice:
dev.set_purpose(
SystemProfileProto::Hardware::InternalStorageDevice::PURPOSE_SWAP);
break;
}
dev.set_model(storage->name);
dev.set_size_mb(storage->size / 1e6);
devices_.push_back(dev);
}
}
chromeos::cros_healthd::mojom::CrosHealthdProbeService*
CrosHealthdMetricsProvider::GetService() {
if (!service_ || !service_.is_connected()) {
chromeos::cros_healthd::ServiceConnection::GetInstance()->GetProbeService(
service_.BindNewPipeAndPassReceiver());
service_.set_disconnect_handler(
base::BindOnce(&CrosHealthdMetricsProvider::OnDisconnect,
weak_ptr_factory_.GetWeakPtr()));
}
return service_.get();
}
void CrosHealthdMetricsProvider::OnDisconnect() {
service_.reset();
}
void CrosHealthdMetricsProvider::ProvideSystemProfileMetrics(
metrics::SystemProfileProto* system_profile_proto) {
if (!initialized_)
return;
auto* mutable_hardware_proto = system_profile_proto->mutable_hardware();
mutable_hardware_proto->clear_internal_storage_devices();
for (const auto& device_info_mojo : devices_) {
auto* device_info_uma =
mutable_hardware_proto->add_internal_storage_devices();
device_info_uma->MergeFrom(device_info_mojo);
}
}