1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/drive_metrics_provider.h"
6
7 #include "base/base_paths.h"
8 #include "base/check_op.h"
9 #include "base/files/drive_info.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/location.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/path_service.h"
17 #include "base/task/task_traits.h"
18 #include "base/task/thread_pool.h"
19 #include "base/threading/scoped_blocking_call.h"
20
21 namespace metrics {
22
23 namespace {
RecordTriStateMetric(const char * name,std::optional<bool> sample)24 void RecordTriStateMetric(const char* name, std::optional<bool> sample) {
25 base::UmaHistogramEnumeration(
26 name, !sample.has_value()
27 ? DriveMetricsProvider::OptionalBoolRecord::kUnknown
28 : (*sample ? DriveMetricsProvider::OptionalBoolRecord::kTrue
29 : DriveMetricsProvider::OptionalBoolRecord::kFalse));
30 }
31 } // namespace
32
DriveMetricsProvider(int local_state_path_key)33 DriveMetricsProvider::DriveMetricsProvider(int local_state_path_key)
34 : local_state_path_key_(local_state_path_key) {}
35
36 DriveMetricsProvider::~DriveMetricsProvider() = default;
37
ProvideSystemProfileMetrics(metrics::SystemProfileProto * system_profile_proto)38 void DriveMetricsProvider::ProvideSystemProfileMetrics(
39 metrics::SystemProfileProto* system_profile_proto) {
40 auto* hardware = system_profile_proto->mutable_hardware();
41 FillDriveMetrics(metrics_.app_drive, hardware->mutable_app_drive());
42 FillDriveMetrics(metrics_.user_data_drive,
43 hardware->mutable_user_data_drive());
44 }
45
AsyncInit(base::OnceClosure done_callback)46 void DriveMetricsProvider::AsyncInit(base::OnceClosure done_callback) {
47 base::ThreadPool::PostTaskAndReplyWithResult(
48 FROM_HERE,
49 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
50 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
51 base::BindOnce(&DriveMetricsProvider::GetDriveMetricsOnBackgroundThread,
52 local_state_path_key_),
53 base::BindOnce(&DriveMetricsProvider::GotDriveMetrics,
54 weak_ptr_factory_.GetWeakPtr(), std::move(done_callback)));
55 }
56
57 DriveMetricsProvider::SeekPenaltyResponse::SeekPenaltyResponse() = default;
58
59 // static
60 DriveMetricsProvider::DriveMetrics
GetDriveMetricsOnBackgroundThread(int local_state_path_key)61 DriveMetricsProvider::GetDriveMetricsOnBackgroundThread(
62 int local_state_path_key) {
63 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
64 base::BlockingType::WILL_BLOCK);
65
66 DriveMetricsProvider::DriveMetrics metrics;
67 QuerySeekPenalty(base::FILE_EXE, &metrics.app_drive);
68 QuerySeekPenalty(local_state_path_key, &metrics.user_data_drive);
69 return metrics;
70 }
71
72 // static
QuerySeekPenalty(int path_service_key,DriveMetricsProvider::SeekPenaltyResponse * response)73 void DriveMetricsProvider::QuerySeekPenalty(
74 int path_service_key,
75 DriveMetricsProvider::SeekPenaltyResponse* response) {
76 DCHECK(response);
77
78 base::FilePath path;
79 if (!base::PathService::Get(path_service_key, &path))
80 return;
81
82 bool has_seek_penalty;
83 bool have_value = HasSeekPenalty(path, &has_seek_penalty);
84 if (have_value) {
85 response->has_seek_penalty = has_seek_penalty;
86 }
87 std::optional<base::DriveInfo> drive_info = base::GetFileDriveInfo(path);
88 if (drive_info.has_value()) {
89 response->has_seek_penalty_base = drive_info->has_seek_penalty;
90 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
91 response->is_removable = drive_info->is_removable;
92 response->is_usb = drive_info->is_usb;
93 #endif
94 }
95 }
96
GotDriveMetrics(base::OnceClosure done_callback,const DriveMetricsProvider::DriveMetrics & metrics)97 void DriveMetricsProvider::GotDriveMetrics(
98 base::OnceClosure done_callback,
99 const DriveMetricsProvider::DriveMetrics& metrics) {
100 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101 metrics_ = metrics;
102 std::move(done_callback).Run();
103 }
104
FillDriveMetrics(const DriveMetricsProvider::SeekPenaltyResponse & response,metrics::SystemProfileProto::Hardware::Drive * drive)105 void DriveMetricsProvider::FillDriveMetrics(
106 const DriveMetricsProvider::SeekPenaltyResponse& response,
107 metrics::SystemProfileProto::Hardware::Drive* drive) {
108 if (response.has_seek_penalty.has_value()) {
109 drive->set_has_seek_penalty(*response.has_seek_penalty);
110 }
111
112 RecordTriStateMetric("UMA.SeekPenaltyResult.Provider",
113 response.has_seek_penalty);
114 RecordTriStateMetric("UMA.SeekPenaltyResult.Base",
115 response.has_seek_penalty_base);
116 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
117 RecordTriStateMetric("UMA.DriveIsRemovableResult", response.is_removable);
118 RecordTriStateMetric("UMA.DriveIsUSBResult", response.is_usb);
119 #endif
120 }
121
122 } // namespace metrics
123