| // 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); |
| } |
| } |