// 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 "ash/metrics/login_unlock_throughput_recorder.h" #include "ash/public/cpp/metrics_util.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/bind.h" #include "base/metrics/histogram_functions.h" #include "chromeos/login/login_state/login_state.h" #include "chromeos/metrics/login_event_recorder.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/total_animation_throughput_reporter.h" namespace ash { namespace { std::string GetDeviceModeSuffix() { return Shell::Get()->tablet_mode_controller()->InTabletMode() ? "TabletMode" : "ClamshellMode"; } void RecordMetrics(const base::TimeTicks& start, const cc::FrameSequenceMetrics::CustomReportData& data, const char* smoothness_name, const char* jank_name, const char* duration_name) { DCHECK(data.frames_expected); // Report could happen during Shell shutdown. Early out in that case. if (!Shell::HasInstance() || !Shell::Get()->tablet_mode_controller()) return; int duration_ms = (base::TimeTicks::Now() - start).InMilliseconds(); int smoothness, jank; smoothness = metrics_util::CalculateSmoothness(data); jank = metrics_util::CalculateJank(data); std::string suffix = GetDeviceModeSuffix(); base::UmaHistogramPercentage(smoothness_name + suffix, smoothness); base::UmaHistogramPercentage(jank_name + suffix, jank); // TODO(crbug.com/1143898): Deprecate this metrics once the login/unlock // performance issue is resolved. base::UmaHistogramCustomTimes(duration_name + suffix, base::Milliseconds(duration_ms), base::Milliseconds(100), base::Seconds(5), 50); } void ReportLogin(base::TimeTicks start, const cc::FrameSequenceMetrics::CustomReportData& data) { if (!data.frames_expected) { LOG(WARNING) << "Zero frames expected in login animation throughput data"; return; } chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker( "LoginAnimationEnd", /*send_to_uma=*/false, /*write_to_file=*/false); chromeos::LoginEventRecorder::Get()->RunScheduledWriteLoginTimes(); RecordMetrics(start, data, "Ash.LoginAnimation.Smoothness.", "Ash.LoginAnimation.Jank.", "Ash.LoginAnimation.Duration."); } void ReportUnlock(base::TimeTicks start, const cc::FrameSequenceMetrics::CustomReportData& data) { if (!data.frames_expected) { LOG(WARNING) << "Zero frames expected in unlock animation throughput data"; return; } RecordMetrics(start, data, "Ash.UnlockAnimation.Smoothness.", "Ash.UnlockAnimation.Jank.", "Ash.UnlockAnimation.Duration."); } } // namespace LoginUnlockThroughputRecorder::LoginUnlockThroughputRecorder() { Shell::Get()->session_controller()->AddObserver(this); chromeos::LoginState::Get()->AddObserver(this); } LoginUnlockThroughputRecorder::~LoginUnlockThroughputRecorder() { Shell::Get()->session_controller()->RemoveObserver(this); chromeos::LoginState::Get()->RemoveObserver(this); } void LoginUnlockThroughputRecorder::OnLockStateChanged(bool locked) { auto logged_in_user = chromeos::LoginState::Get()->GetLoggedInUserType(); if (!locked && (logged_in_user == chromeos::LoginState::LOGGED_IN_USER_OWNER || logged_in_user == chromeos::LoginState::LOGGED_IN_USER_REGULAR)) { auto* primary_root = Shell::GetPrimaryRootWindow(); new ui::TotalAnimationThroughputReporter( primary_root->GetHost()->compositor(), base::BindOnce(&ReportUnlock, base::TimeTicks::Now()), /*self_destruct=*/true); } } void LoginUnlockThroughputRecorder::LoggedInStateChanged() { auto* login_state = chromeos::LoginState::Get(); auto logged_in_user = login_state->GetLoggedInUserType(); if (login_state->IsUserLoggedIn() && (logged_in_user == chromeos::LoginState::LOGGED_IN_USER_OWNER || logged_in_user == chromeos::LoginState::LOGGED_IN_USER_REGULAR)) { ui_recorder_.OnUserLoggedIn(); auto* primary_root = Shell::GetPrimaryRootWindow(); new ui::TotalAnimationThroughputReporter( primary_root->GetHost()->compositor(), base::BindOnce(&LoginUnlockThroughputRecorder::OnLoginAnimationFinish, weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()), /*self_destruct=*/true); } } void LoginUnlockThroughputRecorder::OnLoginAnimationFinish( base::TimeTicks start, const cc::FrameSequenceMetrics::CustomReportData& data) { ui_recorder_.OnPostLoginAnimationFinish(); ReportLogin(start, data); } } // namespace ash