1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 "ash/metrics/login_metrics_recorder.h"
6
7 #include "ash/login/ui/lock_screen.h"
8 #include "ash/session/session_controller_impl.h"
9 #include "ash/shell.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h"
12
13 namespace ash {
14
15 namespace {
16
LogUserClickOnLock(LoginMetricsRecorder::LockScreenUserClickTarget target)17 void LogUserClickOnLock(
18 LoginMetricsRecorder::LockScreenUserClickTarget target) {
19 UMA_HISTOGRAM_ENUMERATION(
20 "Ash.Login.Lock.UserClicks", target,
21 LoginMetricsRecorder::LockScreenUserClickTarget::kTargetCount);
22 }
23
LogUserClickOnLogin(LoginMetricsRecorder::LoginScreenUserClickTarget target)24 void LogUserClickOnLogin(
25 LoginMetricsRecorder::LoginScreenUserClickTarget target) {
26 UMA_HISTOGRAM_ENUMERATION(
27 "Ash.Login.Login.UserClicks", target,
28 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount);
29 }
30
LogUserClickInOobe(LoginMetricsRecorder::OobeUserClickTarget target)31 void LogUserClickInOobe(LoginMetricsRecorder::OobeUserClickTarget target) {
32 UMA_HISTOGRAM_ENUMERATION(
33 "Ash.Login.OOBE.UserClicks", target,
34 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount);
35 }
36
37 // Defines mapping of ShelfButtonClickTarget |original| to different UMA target
38 // in different session state.
39 struct ShelfButtonClickMapping {
40 LoginMetricsRecorder::ShelfButtonClickTarget original;
41 LoginMetricsRecorder::LockScreenUserClickTarget lock;
42 LoginMetricsRecorder::LoginScreenUserClickTarget login;
43 LoginMetricsRecorder::OobeUserClickTarget oobe;
44 };
45
46 // |kTargetCount| is used to mark the click target as unexpected.
47 const ShelfButtonClickMapping kShelfTargets[] = {
48 // |kShutDownButton|
49 {LoginMetricsRecorder::ShelfButtonClickTarget::kShutDownButton,
50 LoginMetricsRecorder::LockScreenUserClickTarget::kShutDownButton,
51 LoginMetricsRecorder::LoginScreenUserClickTarget::kShutDownButton,
52 LoginMetricsRecorder::OobeUserClickTarget::kShutDownButton},
53 // |kRestartButton|
54 {LoginMetricsRecorder::ShelfButtonClickTarget::kRestartButton,
55 LoginMetricsRecorder::LockScreenUserClickTarget::kRestartButton,
56 LoginMetricsRecorder::LoginScreenUserClickTarget::kRestartButton,
57 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
58 // |kSignOutButton|
59 {LoginMetricsRecorder::ShelfButtonClickTarget::kSignOutButton,
60 LoginMetricsRecorder::LockScreenUserClickTarget::kSignOutButton,
61 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
62 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
63 // |kBrowseAsGuestButton|
64 {LoginMetricsRecorder::ShelfButtonClickTarget::kBrowseAsGuestButton,
65 LoginMetricsRecorder::LockScreenUserClickTarget::kTargetCount,
66 LoginMetricsRecorder::LoginScreenUserClickTarget::kBrowseAsGuestButton,
67 LoginMetricsRecorder::OobeUserClickTarget::kBrowseAsGuestButton},
68 // |kAddUserButton|
69 {LoginMetricsRecorder::ShelfButtonClickTarget::kAddUserButton,
70 LoginMetricsRecorder::LockScreenUserClickTarget::kTargetCount,
71 LoginMetricsRecorder::LoginScreenUserClickTarget::kAddUserButton,
72 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
73 // |kCloseNoteButton|
74 {LoginMetricsRecorder::ShelfButtonClickTarget::kCloseNoteButton,
75 LoginMetricsRecorder::LockScreenUserClickTarget::kCloseNoteButton,
76 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
77 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
78 // |kParentAccessButton|
79 {LoginMetricsRecorder::ShelfButtonClickTarget::kParentAccessButton,
80 LoginMetricsRecorder::LockScreenUserClickTarget::kParentAccessButton,
81 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
82 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
83 // |kEnterpriseEnrollmentButton|
84 {LoginMetricsRecorder::ShelfButtonClickTarget::kEnterpriseEnrollmentButton,
85 LoginMetricsRecorder::LockScreenUserClickTarget::kTargetCount,
86 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
87 LoginMetricsRecorder::OobeUserClickTarget::kEnterpriseEnrollmentButton},
88 };
89
90 // Defines mapping of TrayClickTarget |original| to different UMA target in
91 // different session state.
92 struct TrayClickMapping {
93 LoginMetricsRecorder::TrayClickTarget original;
94 LoginMetricsRecorder::LockScreenUserClickTarget lock;
95 LoginMetricsRecorder::LoginScreenUserClickTarget login;
96 LoginMetricsRecorder::OobeUserClickTarget oobe;
97 };
98
99 // |kTargetCount| is used to mark the click target as unexpected.
100 const TrayClickMapping kTrayTargets[] = {
101 // |kSystemTray|
102 {LoginMetricsRecorder::TrayClickTarget::kSystemTray,
103 LoginMetricsRecorder::LockScreenUserClickTarget::kSystemTray,
104 LoginMetricsRecorder::LoginScreenUserClickTarget::kSystemTray,
105 LoginMetricsRecorder::OobeUserClickTarget::kSystemTray},
106 // |kVirtualKeyboardTray|
107 {LoginMetricsRecorder::TrayClickTarget::kVirtualKeyboardTray,
108 LoginMetricsRecorder::LockScreenUserClickTarget::kVirtualKeyboardTray,
109 LoginMetricsRecorder::LoginScreenUserClickTarget::kVirtualKeyboardTray,
110 LoginMetricsRecorder::OobeUserClickTarget::kVirtualKeyboardTray},
111 // |kImeTray|
112 {LoginMetricsRecorder::TrayClickTarget::kImeTray,
113 LoginMetricsRecorder::LockScreenUserClickTarget::kImeTray,
114 LoginMetricsRecorder::LoginScreenUserClickTarget::kImeTray,
115 LoginMetricsRecorder::OobeUserClickTarget::kImeTray},
116 // |kNotificationTray|
117 {LoginMetricsRecorder::TrayClickTarget::kNotificationTray,
118 LoginMetricsRecorder::LockScreenUserClickTarget::kNotificationTray,
119 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
120 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
121 // |kTrayActionNoteButton|
122 {LoginMetricsRecorder::TrayClickTarget::kTrayActionNoteButton,
123 LoginMetricsRecorder::LockScreenUserClickTarget::kTrayActionNoteButton,
124 LoginMetricsRecorder::LoginScreenUserClickTarget::kTargetCount,
125 LoginMetricsRecorder::OobeUserClickTarget::kTargetCount},
126 };
127
ShouldRecordMetrics()128 bool ShouldRecordMetrics() {
129 session_manager::SessionState session_state =
130 Shell::Get()->session_controller()->GetSessionState();
131 return session_state == session_manager::SessionState::LOGIN_PRIMARY ||
132 session_state == session_manager::SessionState::LOCKED ||
133 session_state == session_manager::SessionState::OOBE;
134 }
135
136 } // namespace
137
138 LoginMetricsRecorder::LoginMetricsRecorder() = default;
139 LoginMetricsRecorder::~LoginMetricsRecorder() = default;
140
RecordNumLoginAttempts(bool success,int * num_attempt)141 void LoginMetricsRecorder::RecordNumLoginAttempts(bool success,
142 int* num_attempt) {
143 if (success) {
144 UMA_HISTOGRAM_COUNTS_100("Ash.Login.Lock.NbPasswordAttempts.UntilSuccess",
145 *num_attempt);
146 } else if (*num_attempt > 0) {
147 UMA_HISTOGRAM_COUNTS_100("Ash.Login.Lock.NbPasswordAttempts.UntilFailure",
148 *num_attempt);
149 }
150
151 *num_attempt = 0;
152 }
153
RecordUserTrayClick(TrayClickTarget target)154 void LoginMetricsRecorder::RecordUserTrayClick(TrayClickTarget target) {
155 if (!ShouldRecordMetrics())
156 return;
157 auto state = Shell::Get()->session_controller()->GetSessionState();
158 for (const auto& el : kTrayTargets) {
159 if (el.original != target)
160 continue;
161 switch (state) {
162 case session_manager::SessionState::LOCKED:
163 DCHECK(el.lock != LockScreenUserClickTarget::kTargetCount)
164 << "Not expected tray click target: " << static_cast<int>(target)
165 << " for session state: " << static_cast<int>(state);
166 LogUserClickOnLock(el.lock);
167 return;
168 case session_manager::SessionState::LOGIN_PRIMARY:
169 DCHECK(el.login != LoginScreenUserClickTarget::kTargetCount)
170 << "Not expected tray click target: " << static_cast<int>(target)
171 << " for session state: " << static_cast<int>(state);
172 LogUserClickOnLogin(el.login);
173 return;
174 case session_manager::SessionState::OOBE:
175 DCHECK(el.oobe != OobeUserClickTarget::kTargetCount)
176 << "Not expected tray click target: " << static_cast<int>(target)
177 << " for session state: " << static_cast<int>(state);
178 LogUserClickInOobe(el.oobe);
179 return;
180 default:
181 NOTREACHED() << "Unexpected session state: " << static_cast<int>(state);
182 return;
183 }
184 }
185 NOTREACHED() << "Tray click target wasn't found in the |kTrayTargets|.";
186 }
187
RecordUserShelfButtonClick(ShelfButtonClickTarget target)188 void LoginMetricsRecorder::RecordUserShelfButtonClick(
189 ShelfButtonClickTarget target) {
190 if (!ShouldRecordMetrics())
191 return;
192 auto state = Shell::Get()->session_controller()->GetSessionState();
193 for (const auto& el : kShelfTargets) {
194 if (el.original != target)
195 continue;
196 switch (state) {
197 case session_manager::SessionState::LOCKED:
198 DCHECK(el.lock != LockScreenUserClickTarget::kTargetCount)
199 << "Not expected shelf click target: " << static_cast<int>(target)
200 << " for session state: " << static_cast<int>(state);
201 LogUserClickOnLock(el.lock);
202 return;
203 case session_manager::SessionState::LOGIN_PRIMARY:
204 DCHECK(el.login != LoginScreenUserClickTarget::kTargetCount)
205 << "Not expected shelf click target: " << static_cast<int>(target)
206 << " for session state: " << static_cast<int>(state);
207 LogUserClickOnLogin(el.login);
208 return;
209 case session_manager::SessionState::OOBE:
210 DCHECK(el.oobe != OobeUserClickTarget::kTargetCount)
211 << "Not expected shelf click target: " << static_cast<int>(target)
212 << " for session state: " << static_cast<int>(state);
213 LogUserClickInOobe(el.oobe);
214 return;
215 default:
216 NOTREACHED() << "Unexpected session state: " << static_cast<int>(state);
217 return;
218 }
219 }
220 NOTREACHED() << "Shelf click target wasn't found in the |kShelfTargets|.";
221 }
222
223 } // namespace ash
224