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