Skip to content

Commit

Permalink
settings: Add metric to track the number of devices used in last 28 days
Browse files Browse the repository at this point in the history
Records a metric everytime an external mouse, keyboard, or touchpad is
plugged in to track how many devices of each type are used over the last
28 days.

Fixed: b/339906064
Change-Id: I2bc903aecf5bcc845a8759e8e71155f8341194f1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5531857
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Commit-Queue: David Padlipsky <dpad@google.com>
Cr-Commit-Position: refs/heads/main@{#1299647}
  • Loading branch information
dpadlipsky authored and Chromium LUCI CQ committed May 11, 2024
1 parent 58d4780 commit 6893822
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,60 @@ std::optional<ui::KeyboardDevice> FindKeyboardWithId(int device_id) {
return *iter;
}

uint32_t CountNumberOfDevicesUsedInLast28Days(std::string_view pref_name) {
constexpr base::TimeDelta k28Days = base::Days(28);

PrefService* pref_service =
Shell::Get()->session_controller()->GetActivePrefService();
CHECK(pref_service);

uint32_t num_devices_used = 0;
const base::Value::Dict& devices_dict = pref_service->GetDict(pref_name);
for (const auto device_entry : devices_dict) {
const auto* device = device_entry.second.GetIfDict();
if (!device) {
continue;
}

const auto* last_updated_value = device->Find(prefs::kLastUpdatedKey);
if (!last_updated_value) {
continue;
}

const auto last_updated_time = base::ValueToTime(*last_updated_value);
if (!last_updated_time) {
continue;
}

if (base::Time::Now() - *last_updated_time <= k28Days) {
num_devices_used++;
}
}

return num_devices_used;
}

void RecordNumberOfMiceUsedInLast28Days() {
base::UmaHistogramCounts100(
"ChromeOS.Settings.Device.Mouse.External.NumConnectedLast28Days",
CountNumberOfDevicesUsedInLast28Days(
prefs::kMouseDeviceSettingsDictPref));
}

void RecordNumberOfKeyboardsUsedInLast28Days() {
base::UmaHistogramCounts100(
"ChromeOS.Settings.Device.Keyboard.External.NumConnectedLast28Days",
CountNumberOfDevicesUsedInLast28Days(
prefs::kKeyboardDeviceSettingsDictPref));
}

void RecordNumberOfTouchpadsUsedInLast28Days() {
base::UmaHistogramCounts100(
"ChromeOS.Settings.Device.Touchpad.External.NumConnectedLast28Days",
CountNumberOfDevicesUsedInLast28Days(
prefs::kTouchpadDeviceSettingsDictPref));
}

} // namespace

InputDeviceSettingsMetricsManager::InputDeviceSettingsMetricsManager() =
Expand All @@ -456,6 +510,12 @@ InputDeviceSettingsMetricsManager::~InputDeviceSettingsMetricsManager() =

void InputDeviceSettingsMetricsManager::RecordKeyboardInitialMetrics(
const mojom::Keyboard& keyboard) {
// Record this metric every time a mouse is plugged/unplugged to account for
// if a user session lasts for >28 days.
if (keyboard.is_external) {
RecordNumberOfKeyboardsUsedInLast28Days();
}

// Only record the metrics once for each keyboard.
const auto account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
Expand Down Expand Up @@ -620,6 +680,10 @@ void InputDeviceSettingsMetricsManager::RecordKeyboardNumberOfKeysReset(

void InputDeviceSettingsMetricsManager::RecordMouseInitialMetrics(
const mojom::Mouse& mouse) {
// Record this metric every time a mouse is plugged/unplugged to account for
// if a user session lasts for >28 days.
RecordNumberOfMiceUsedInLast28Days();

// Only record the metrics once for each mouse.
const auto account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
Expand Down Expand Up @@ -798,6 +862,12 @@ void InputDeviceSettingsMetricsManager::RecordPointingStickChangedMetrics(

void InputDeviceSettingsMetricsManager::RecordTouchpadInitialMetrics(
const mojom::Touchpad& touchpad) {
// Record this metric every time a mouse is plugged/unplugged to account for
// if a user session lasts for >28 days.
if (touchpad.is_external) {
RecordNumberOfTouchpadsUsedInLast28Days();
}

// Only record the metrics once for each Touchpad.
const auto account_id =
Shell::Get()->session_controller()->GetActiveAccountId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
#include "ash/system/input_device_settings/input_device_settings_pref_names.h"
#include "ash/system/input_device_settings/settings_updated_metrics_info.h"
#include "ash/test/ash_test_base.h"
#include "base/json/values_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/values.h"
#include "device/udev_linux/fake_udev_loader.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/ash/mojom/extended_fkeys_modifier.mojom-shared.h"
Expand Down Expand Up @@ -1288,6 +1291,121 @@ TEST_F(InputDeviceSettingsMetricsManagerTest,
/*expected_count=*/1u);
}

TEST_F(InputDeviceSettingsMetricsManagerTest, RecordNumMiceUsedInLast28Days) {
mojom::Mouse mouse;
mouse.device_key = kExternalMouseId;
mouse.settings = mojom::MouseSettings::New();

base::Value::Dict test_pref_dict;

// Add 5 devices in the window we care about.
for (int i = 1; i <= 5; i++) {
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(4 * i)));
test_pref_dict.Set("in_window_" + base::NumberToString(i),
std::move(device_dict));
}

// Add a device that is outside the window we want to measure.
{
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(29)));
test_pref_dict.Set("out_of_window", std::move(device_dict));
}

PrefService* pref_service =
Shell::Get()->session_controller()->GetActivePrefService();
pref_service->SetDict(prefs::kMouseDeviceSettingsDictPref,
std::move(test_pref_dict));

base::HistogramTester histogram_tester;

manager_->RecordMouseInitialMetrics(mouse);
histogram_tester.ExpectUniqueSample(
"ChromeOS.Settings.Device.Mouse.External.NumConnectedLast28Days", 5, 1);
}

TEST_F(InputDeviceSettingsMetricsManagerTest,
RecordNumKeyboardsUsedInLast28Days) {
mojom::Keyboard keyboard;
keyboard.device_key = kExternalMouseId;
keyboard.is_external = true;
keyboard.settings = mojom::KeyboardSettings::New();
keyboard.settings->six_pack_key_remappings = mojom::SixPackKeyInfo::New();

base::Value::Dict test_pref_dict;

// Add 5 devices in the window we care about.
for (int i = 1; i <= 5; i++) {
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(4 * i)));
test_pref_dict.Set("in_window_" + base::NumberToString(i),
std::move(device_dict));
}

// Add a device that is outside the window we want to measure.
{
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(29)));
test_pref_dict.Set("out_of_window", std::move(device_dict));
}

PrefService* pref_service =
Shell::Get()->session_controller()->GetActivePrefService();
pref_service->SetDict(prefs::kKeyboardDeviceSettingsDictPref,
std::move(test_pref_dict));

base::HistogramTester histogram_tester;

manager_->RecordKeyboardInitialMetrics(keyboard);
histogram_tester.ExpectUniqueSample(
"ChromeOS.Settings.Device.Keyboard.External.NumConnectedLast28Days", 5,
1);
}

TEST_F(InputDeviceSettingsMetricsManagerTest,
RecordNumTouchpadsUsedInLast28Days) {
mojom::Touchpad touchpad;
touchpad.device_key = kExternalTouchpadId;
touchpad.is_external = true;
touchpad.settings = mojom::TouchpadSettings::New();

base::Value::Dict test_pref_dict;

// Add 5 devices in the window we care about.
for (int i = 1; i <= 5; i++) {
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(4 * i)));
test_pref_dict.Set("in_window_" + base::NumberToString(i),
std::move(device_dict));
}

// Add a device that is outside the window we want to measure.
{
base::Value::Dict device_dict;
device_dict.Set(prefs::kLastUpdatedKey,
base::TimeToValue(base::Time::Now() - base::Days(29)));
test_pref_dict.Set("out_of_window", std::move(device_dict));
}

PrefService* pref_service =
Shell::Get()->session_controller()->GetActivePrefService();
pref_service->SetDict(prefs::kTouchpadDeviceSettingsDictPref,
std::move(test_pref_dict));

base::HistogramTester histogram_tester;

manager_->RecordTouchpadInitialMetrics(touchpad);
histogram_tester.ExpectUniqueSample(
"ChromeOS.Settings.Device.Touchpad.External.NumConnectedLast28Days", 5,
1);
}

class SettingsUpdatedTimePeriodMetricsTest
: public InputDeviceSettingsMetricsManagerTest,
public testing::WithParamInterface<
Expand Down
16 changes: 16 additions & 0 deletions tools/metrics/histograms/metadata/chromeos/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3647,6 +3647,22 @@ They are used for the ChromeOS.CertProvisioning.* histograms to distinguish
</token>
</histogram>

<histogram
name="ChromeOS.Settings.Device.{Peripheral}.External.NumConnectedLast28Days"
units="devices" expires_after="2025-03-22">
<owner>dpad@google.com</owner>
<owner>cros-peripherals@google.com</owner>
<summary>
Records the number of {Peripheral} devices seen in the last 28 days.
Recorded everytime a user connects an external {Peripheral}.
</summary>
<token key="Peripheral">
<variant name="Keyboard"/>
<variant name="Mouse"/>
<variant name="Touchpad"/>
</token>
</histogram>

<histogram
name="ChromeOS.Settings.Device.{Peripheral}.{PeripheralSetting}.Changed"
enum="Boolean" expires_after="2025-03-22">
Expand Down

0 comments on commit 6893822

Please sign in to comment.