Commit 4f75e719 authored by Rachel Wong's avatar Rachel Wong Committed by Commit Bot

[settings logging] Log shared features.

This change implements logging of features that are shared by all quick
settings logging functions.

- Audio feature was previously only logged for a volume change,  but has
been moved to become a shared feature.
- There is also some reordering of the header file for readability
reasons.

Bug: 1014839
Change-Id: I4fc6cc9dc4d76acae5450894ec49258320b02d24
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2087300Reviewed-by: default avatarJia Meng <jiameng@chromium.org>
Commit-Queue: Rachel Wong <wrong@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748073}
parent 073c54bd
...@@ -1493,6 +1493,7 @@ component("ash") { ...@@ -1493,6 +1493,7 @@ component("ash") {
"//chromeos/strings", "//chromeos/strings",
"//chromeos/system", "//chromeos/system",
"//components/account_id", "//components/account_id",
"//components/country_codes",
"//components/device_event_log", "//components/device_event_log",
"//components/discardable_memory/service", "//components/discardable_memory/service",
"//components/exo", "//components/exo",
......
...@@ -5,11 +5,16 @@ ...@@ -5,11 +5,16 @@
#include "ash/system/machine_learning/user_settings_event_logger.h" #include "ash/system/machine_learning/user_settings_event_logger.h"
#include "ash/app_list/app_list_controller_impl.h" #include "ash/app_list/app_list_controller_impl.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/public/cpp/app_list/app_list_client.h" #include "ash/public/cpp/app_list/app_list_client.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/system/night_light/night_light_controller_impl.h" #include "ash/system/night_light/night_light_controller_impl.h"
#include "ash/system/power/power_status.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_recorder.h"
...@@ -47,7 +52,8 @@ UserSettingsEventLogger::UserSettingsEventLogger() ...@@ -47,7 +52,8 @@ UserSettingsEventLogger::UserSettingsEventLogger()
is_recently_presenting_(false), is_recently_presenting_(false),
is_recently_fullscreen_(false), is_recently_fullscreen_(false),
used_cellular_in_session_(false), used_cellular_in_session_(false),
is_playing_audio_(false) { is_playing_audio_(false),
clock_(base::DefaultClock::GetInstance()) {
Shell::Get()->AddShellObserver(this); Shell::Get()->AddShellObserver(this);
chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); chromeos::CrasAudioHandler::Get()->AddAudioObserver(this);
} }
...@@ -190,8 +196,6 @@ void UserSettingsEventLogger::OnVolumeTimerEnded() { ...@@ -190,8 +196,6 @@ void UserSettingsEventLogger::OnVolumeTimerEnded() {
event->set_previous_value(previous_volume_); event->set_previous_value(previous_volume_);
event->set_current_value(current_volume_); event->set_current_value(current_volume_);
settings_event.mutable_features()->set_is_playing_audio(is_playing_audio_);
PopulateSharedFeatures(&settings_event); PopulateSharedFeatures(&settings_event);
SendToUkmAndAppList(settings_event); SendToUkmAndAppList(settings_event);
} }
...@@ -270,8 +274,46 @@ void UserSettingsEventLogger::OnOutputStopped() { ...@@ -270,8 +274,46 @@ void UserSettingsEventLogger::OnOutputStopped() {
is_playing_audio_ = false; is_playing_audio_ = false;
} }
void UserSettingsEventLogger::PopulateSharedFeatures(UserSettingsEvent* event) { void UserSettingsEventLogger::SetClockForTesting(const base::Clock* clock) {
// TODO(crbug/1014839): Populate the shared contextual features. clock_ = clock;
}
void UserSettingsEventLogger::PopulateSharedFeatures(
UserSettingsEvent* settings_event) {
auto* features = settings_event->mutable_features();
// Set time features.
base::Time::Exploded now;
clock_->Now().LocalExplode(&now);
features->set_hour_of_day(now.hour);
features->set_day_of_week(
static_cast<UserSettingsEvent::Features::DayOfWeek>(now.day_of_week));
// Set power features.
if (PowerStatus::IsInitialized()) {
const auto* power_status = PowerStatus::Get();
features->set_battery_percentage(power_status->GetRoundedBatteryPercent());
features->set_is_charging(power_status->IsLinePowerConnected() ||
power_status->IsMainsChargerConnected() ||
power_status->IsUsbChargerConnected());
}
// Set activity features.
features->set_is_playing_audio(is_playing_audio_);
// TODO(crbug/1014839): Set the |is_playing_video| field.
// Set orientation features.
features->set_device_mode(
Shell::Get()->tablet_mode_controller()->InTabletMode()
? UserSettingsEvent::Features::TABLET_MODE
: UserSettingsEvent::Features::CLAMSHELL_MODE);
const auto orientation =
Shell::Get()->screen_orientation_controller()->GetCurrentOrientation();
if (IsLandscapeOrientation(orientation)) {
features->set_device_orientation(UserSettingsEvent::Features::LANDSCAPE);
} else if (IsPortraitOrientation(orientation)) {
features->set_device_orientation(UserSettingsEvent::Features::PORTRAIT);
}
} }
void UserSettingsEventLogger::SendToUkmAndAppList( void UserSettingsEventLogger::SendToUkmAndAppList(
...@@ -295,8 +337,21 @@ void UserSettingsEventLogger::SendToUkmAndAppList( ...@@ -295,8 +337,21 @@ void UserSettingsEventLogger::SendToUkmAndAppList(
if (event.has_accessibility_id()) if (event.has_accessibility_id())
ukm_event.SetAccessibilityId(event.accessibility_id()); ukm_event.SetAccessibilityId(event.accessibility_id());
if (features.has_hour_of_day())
ukm_event.SetHourOfDay(features.hour_of_day());
if (features.has_day_of_week())
ukm_event.SetDayOfWeek(features.day_of_week());
if (features.has_battery_percentage())
ukm_event.SetBatteryPercentage(features.battery_percentage());
if (features.has_is_charging())
ukm_event.SetIsCharging(features.is_charging());
if (features.has_is_playing_audio()) if (features.has_is_playing_audio())
ukm_event.SetIsPlayingAudio(features.is_playing_audio()); ukm_event.SetIsPlayingAudio(features.is_playing_audio());
if (features.has_device_mode())
ukm_event.SetDeviceMode(features.device_mode());
if (features.has_device_orientation())
ukm_event.SetDeviceOrientation(features.device_orientation());
if (features.has_is_recently_presenting()) if (features.has_is_recently_presenting())
ukm_event.SetIsRecentlyPresenting(features.is_recently_presenting()); ukm_event.SetIsRecentlyPresenting(features.is_recently_presenting());
if (features.has_is_recently_fullscreen()) if (features.has_is_recently_fullscreen())
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/system/bluetooth/tray_bluetooth_helper.h" #include "ash/system/bluetooth/tray_bluetooth_helper.h"
#include "ash/system/machine_learning/user_settings_event.pb.h" #include "ash/system/machine_learning/user_settings_event.pb.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/time/clock.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
...@@ -72,44 +73,49 @@ class ASH_EXPORT UserSettingsEventLogger ...@@ -72,44 +73,49 @@ class ASH_EXPORT UserSettingsEventLogger
void OnOutputStarted() override; void OnOutputStarted() override;
void OnOutputStopped() override; void OnOutputStopped() override;
void SetClockForTesting(const base::Clock* clock);
private: private:
friend class UserSettingsEventLoggerTest;
UserSettingsEventLogger(); UserSettingsEventLogger();
~UserSettingsEventLogger() override; ~UserSettingsEventLogger() override;
// Populates contextual information shared by all settings events. // Populates contextual information shared by all settings events.
void PopulateSharedFeatures(UserSettingsEvent* event); void PopulateSharedFeatures(UserSettingsEvent* settings_event);
// Sends the given event to UKM and AppListClient. // Sends the given event to UKM and AppListClient.
void SendToUkmAndAppList(const UserSettingsEvent& event); void SendToUkmAndAppList(const UserSettingsEvent& settings_event);
void OnVolumeTimerEnded(); void OnVolumeTimerEnded();
void OnBrightnessTimerEnded(); void OnBrightnessTimerEnded();
void OnPresentingTimerEnded(); void OnPresentingTimerEnded();
void OnFullscreenTimerEnded(); void OnFullscreenTimerEnded();
// When the user drags the brightness or volume slider, the logger will be // Timer to ensure that volume is only recorded after a pause.
// called multiple times at small time increments. These timers are used so
// that a UKM event is only logged after there has been a pause.
base::OneShotTimer volume_timer_; base::OneShotTimer volume_timer_;
base::OneShotTimer brightness_timer_;
// Levels before the corresponding timer was started.
int previous_volume_; int previous_volume_;
int previous_brightness_;
// Levels as of the most recent event.
int current_volume_; int current_volume_;
// Timer to ensure that brightness is only recorded after a pause.
base::OneShotTimer brightness_timer_;
int previous_brightness_;
int current_brightness_; int current_brightness_;
base::OneShotTimer presenting_timer_; base::OneShotTimer presenting_timer_;
base::OneShotTimer fullscreen_timer_;
int presenting_session_count_; int presenting_session_count_;
// Whether the device has been presenting in the last 5 minutes. // Whether the device has been presenting in the last 5 minutes.
bool is_recently_presenting_; bool is_recently_presenting_;
base::OneShotTimer fullscreen_timer_;
// Whether the device has been in fullscreen mode in the last 5 minutes. // Whether the device has been in fullscreen mode in the last 5 minutes.
bool is_recently_fullscreen_; bool is_recently_fullscreen_;
bool used_cellular_in_session_; bool used_cellular_in_session_;
bool is_playing_audio_; bool is_playing_audio_;
const base::Clock* clock_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
static UserSettingsEventLogger* instance_; static UserSettingsEventLogger* instance_;
......
...@@ -4,14 +4,22 @@ ...@@ -4,14 +4,22 @@
#include "ash/system/machine_learning/user_settings_event_logger.h" #include "ash/system/machine_learning/user_settings_event_logger.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/display/screen_orientation_controller_test_api.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/system/machine_learning/user_settings_event.pb.h" #include "ash/system/machine_learning/user_settings_event.pb.h"
#include "ash/system/night_light/night_light_controller_impl.h" #include "ash/system/night_light/night_light_controller_impl.h"
#include "ash/system/power/power_status.h"
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "components/ukm/test_ukm_recorder.h" #include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_builders.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/test/display_manager_test_api.h"
namespace ash { namespace ash {
namespace ml { namespace ml {
...@@ -26,6 +34,8 @@ using chromeos::network_config::mojom::NetworkTypeStateProperties; ...@@ -26,6 +34,8 @@ using chromeos::network_config::mojom::NetworkTypeStateProperties;
using chromeos::network_config::mojom::SecurityType; using chromeos::network_config::mojom::SecurityType;
using chromeos::network_config::mojom::WiFiStateProperties; using chromeos::network_config::mojom::WiFiStateProperties;
using chromeos::network_config::mojom::WiFiStatePropertiesPtr; using chromeos::network_config::mojom::WiFiStatePropertiesPtr;
using display::Display;
using power_manager::PowerSupplyProperties;
using ukm::TestUkmRecorder; using ukm::TestUkmRecorder;
NetworkStatePropertiesPtr CreateWifiNetwork(int signal_strength, NetworkStatePropertiesPtr CreateWifiNetwork(int signal_strength,
...@@ -121,6 +131,12 @@ class UserSettingsEventLoggerTest : public AshTestBase { ...@@ -121,6 +131,12 @@ class UserSettingsEventLoggerTest : public AshTestBase {
task_environment_->FastForwardBy(kSliderDelay); task_environment_->FastForwardBy(kSliderDelay);
} }
void LogSharedFeatures() {
UserSettingsEvent event;
logger_->PopulateSharedFeatures(&event);
logger_->SendToUkmAndAppList(event);
}
UserSettingsEventLogger* logger_; UserSettingsEventLogger* logger_;
private: private:
...@@ -313,15 +329,10 @@ TEST_F(UserSettingsEventLoggerTest, TestLogAccessibilityEvent) { ...@@ -313,15 +329,10 @@ TEST_F(UserSettingsEventLoggerTest, TestLogAccessibilityEvent) {
TEST_F(UserSettingsEventLoggerTest, TestLogVolumeFeatures) { TEST_F(UserSettingsEventLoggerTest, TestLogVolumeFeatures) {
LogVolumeAndWait(23, 98); LogVolumeAndWait(23, 98);
logger_->OnOutputStarted();
LogVolumeAndWait(0, 0);
logger_->OnOutputStopped();
LogVolumeAndWait(0, 0);
const auto& entries = GetUkmEntries(); const auto& entries = GetUkmEntries();
ASSERT_EQ(3ul, entries.size()); ASSERT_EQ(1ul, entries.size());
// Check that the first entry has all details recorded correctly.
const auto* entry = entries[0]; const auto* entry = entries[0];
TestUkmRecorder::ExpectEntryMetric(entry, "SettingId", TestUkmRecorder::ExpectEntryMetric(entry, "SettingId",
UserSettingsEvent::Event::VOLUME); UserSettingsEvent::Event::VOLUME);
...@@ -330,10 +341,6 @@ TEST_F(UserSettingsEventLoggerTest, TestLogVolumeFeatures) { ...@@ -330,10 +341,6 @@ TEST_F(UserSettingsEventLoggerTest, TestLogVolumeFeatures) {
TestUkmRecorder::ExpectEntryMetric(entry, "PreviousValue", 23); TestUkmRecorder::ExpectEntryMetric(entry, "PreviousValue", 23);
TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 98); TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 98);
TestUkmRecorder::ExpectEntryMetric(entry, "IsPlayingAudio", false); TestUkmRecorder::ExpectEntryMetric(entry, "IsPlayingAudio", false);
// Check that subsequent entries correctly record |is_playing_audio|.
TestUkmRecorder::ExpectEntryMetric(entries[1], "IsPlayingAudio", true);
TestUkmRecorder::ExpectEntryMetric(entries[2], "IsPlayingAudio", false);
} }
TEST_F(UserSettingsEventLoggerTest, TestVolumeDelay) { TEST_F(UserSettingsEventLoggerTest, TestVolumeDelay) {
...@@ -359,7 +366,7 @@ TEST_F(UserSettingsEventLoggerTest, TestVolumeDelay) { ...@@ -359,7 +366,7 @@ TEST_F(UserSettingsEventLoggerTest, TestVolumeDelay) {
TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 15); TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 15);
} }
TEST_F(UserSettingsEventLoggerTest, TestBrightnessFeatures) { TEST_F(UserSettingsEventLoggerTest, TestLogBrightnessFeatures) {
LogBrightnessAndWait(12, 29); LogBrightnessAndWait(12, 29);
// Enter fullscreen. // Enter fullscreen.
...@@ -416,5 +423,128 @@ TEST_F(UserSettingsEventLoggerTest, TestBrightnessDelay) { ...@@ -416,5 +423,128 @@ TEST_F(UserSettingsEventLoggerTest, TestBrightnessDelay) {
TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 15); TestUkmRecorder::ExpectEntryMetric(entry, "CurrentValue", 15);
} }
TEST_F(UserSettingsEventLoggerTest, TestLogDatetimeFeatures) {
base::SimpleTestClock test_clock;
logger_->SetClockForTesting(&test_clock);
base::Time fake_time;
ASSERT_TRUE(base::Time::FromString("Thu, 7 Nov 2019 14:58:00", &fake_time));
test_clock.SetNow(fake_time);
LogSharedFeatures();
ASSERT_TRUE(base::Time::FromString("Fri, 8 Nov 2019 04:24:00", &fake_time));
test_clock.SetNow(fake_time);
LogSharedFeatures();
const auto& entries = GetUkmEntries();
ASSERT_EQ(2ul, entries.size());
const auto* entry = entries[0];
TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 14);
TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek",
UserSettingsEvent::Features::THU);
entry = entries[1];
TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 4);
TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek",
UserSettingsEvent::Features::FRI);
}
TEST_F(UserSettingsEventLoggerTest, TestLogPowerFeatures) {
PowerSupplyProperties fake_power;
fake_power.set_battery_percent(56.0);
fake_power.set_external_power(PowerSupplyProperties::DISCONNECTED);
PowerStatus::Get()->SetProtoForTesting(fake_power);
LogSharedFeatures();
fake_power.set_external_power(PowerSupplyProperties::AC);
PowerStatus::Get()->SetProtoForTesting(fake_power);
LogSharedFeatures();
fake_power.set_external_power(PowerSupplyProperties::USB);
PowerStatus::Get()->SetProtoForTesting(fake_power);
LogSharedFeatures();
const auto& entries = GetUkmEntries();
ASSERT_EQ(3ul, entries.size());
auto* entry = entries[0];
TestUkmRecorder::ExpectEntryMetric(entry, "BatteryPercentage", 56);
TestUkmRecorder::ExpectEntryMetric(entry, "IsCharging", false);
TestUkmRecorder::ExpectEntryMetric(entries[1], "IsCharging", true);
TestUkmRecorder::ExpectEntryMetric(entries[2], "IsCharging", true);
}
TEST_F(UserSettingsEventLoggerTest, TestLogAudio) {
LogSharedFeatures();
logger_->OnOutputStarted();
LogSharedFeatures();
logger_->OnOutputStopped();
LogSharedFeatures();
const auto& entries = GetUkmEntries();
ASSERT_EQ(3ul, entries.size());
TestUkmRecorder::ExpectEntryMetric(entries[0], "IsPlayingAudio", false);
TestUkmRecorder::ExpectEntryMetric(entries[1], "IsPlayingAudio", true);
TestUkmRecorder::ExpectEntryMetric(entries[2], "IsPlayingAudio", false);
}
TEST_F(UserSettingsEventLoggerTest, TestLogTabletMode) {
auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
tablet_mode_controller->SetEnabledForTest(true);
LogSharedFeatures();
tablet_mode_controller->SetEnabledForTest(false);
LogSharedFeatures();
const auto& entries = GetUkmEntries();
ASSERT_EQ(2ul, entries.size());
TestUkmRecorder::ExpectEntryMetric(entries[0], "DeviceMode",
UserSettingsEvent::Features::TABLET_MODE);
TestUkmRecorder::ExpectEntryMetric(
entries[1], "DeviceMode", UserSettingsEvent::Features::CLAMSHELL_MODE);
}
TEST_F(UserSettingsEventLoggerTest, TestLogOrientation) {
display::test::ScopedSetInternalDisplayId set_internal_display(
Shell::Get()->display_manager(),
display::Screen::GetScreen()->GetPrimaryDisplay().id());
ScreenOrientationControllerTestApi orientation_test_api(
Shell::Get()->screen_orientation_controller());
orientation_test_api.SetDisplayRotation(Display::ROTATE_0,
Display::RotationSource::ACTIVE);
LogSharedFeatures();
orientation_test_api.SetDisplayRotation(Display::ROTATE_90,
Display::RotationSource::ACTIVE);
LogSharedFeatures();
orientation_test_api.SetDisplayRotation(Display::ROTATE_180,
Display::RotationSource::ACTIVE);
LogSharedFeatures();
orientation_test_api.SetDisplayRotation(Display::ROTATE_270,
Display::RotationSource::ACTIVE);
LogSharedFeatures();
const auto& entries = GetUkmEntries();
ASSERT_EQ(4ul, entries.size());
TestUkmRecorder::ExpectEntryMetric(entries[0], "DeviceOrientation",
UserSettingsEvent::Features::LANDSCAPE);
TestUkmRecorder::ExpectEntryMetric(entries[1], "DeviceOrientation",
UserSettingsEvent::Features::PORTRAIT);
TestUkmRecorder::ExpectEntryMetric(entries[2], "DeviceOrientation",
UserSettingsEvent::Features::LANDSCAPE);
TestUkmRecorder::ExpectEntryMetric(entries[3], "DeviceOrientation",
UserSettingsEvent::Features::PORTRAIT);
}
} // namespace ml } // namespace ml
} // namespace ash } // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment