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 "chrome/browser/chromeos/login/enterprise_user_session_metrics.h"
6 
7 #include <algorithm>
8 
9 #include "base/check.h"
10 #include "base/metrics/histogram_functions.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/notreached.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/browser_process_platform_part.h"
15 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
16 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
17 #include "chrome/common/pref_names.h"
18 #include "chromeos/login/auth/user_context.h"
19 #include "components/prefs/pref_registry_simple.h"
20 #include "components/prefs/pref_service.h"
21 
22 namespace {
23 
24 // Returns true if the device is enterprise managed, false otherwise.
IsEnterpriseManaged()25 bool IsEnterpriseManaged() {
26   return g_browser_process->platform_part()
27       ->browser_policy_connector_chromeos()
28       ->IsEnterpriseManaged();
29 }
30 
31 // Returns the duration in minutes, capped at `max_duration` and rounded down to
32 // the nearest `bucket_size` minutes.
GetMinutesToReport(base::TimeDelta duration,int bucket_size,base::TimeDelta max_duration)33 int GetMinutesToReport(base::TimeDelta duration,
34                        int bucket_size,
35                        base::TimeDelta max_duration) {
36   int minutes = std::min(duration.InMinutes(), max_duration.InMinutes());
37   return minutes / bucket_size * bucket_size;
38 }
39 
40 }  // namespace
41 
42 namespace chromeos {
43 namespace enterprise_user_session_metrics {
44 
RegisterPrefs(PrefRegistrySimple * registry)45 void RegisterPrefs(PrefRegistrySimple* registry) {
46   registry->RegisterIntegerPref(prefs::kLastSessionType, 0);
47   registry->RegisterInt64Pref(prefs::kLastSessionLength, 0);
48 }
49 
RecordSignInEvent(SignInEventType sign_in_event_type)50 void RecordSignInEvent(SignInEventType sign_in_event_type) {
51   DCHECK(IsEnterpriseManaged());
52 
53   UMA_HISTOGRAM_ENUMERATION(
54       "Enterprise.UserSession.Logins", static_cast<int>(sign_in_event_type),
55       static_cast<int>(SignInEventType::SIGN_IN_EVENT_COUNT));
56 }
57 
RecordSignInEvent(const UserContext & user_context,bool is_auto_login)58 void RecordSignInEvent(const UserContext& user_context, bool is_auto_login) {
59   DCHECK(IsEnterpriseManaged());
60 
61   const user_manager::UserType session_type = user_context.GetUserType();
62   if (session_type == user_manager::USER_TYPE_REGULAR) {
63     RecordSignInEvent(SignInEventType::REGULAR_USER);
64   } else if (session_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
65     RecordSignInEvent(is_auto_login ? SignInEventType::AUTOMATIC_PUBLIC_SESSION
66                                     : SignInEventType::MANUAL_PUBLIC_SESSION);
67   }
68 
69   // Kiosk sign-ins are handled separately in AppLaunchController and other
70   // session types are ignored for now.
71 }
72 
StoreSessionLength(user_manager::UserType session_type,const base::TimeDelta & session_length)73 void StoreSessionLength(user_manager::UserType session_type,
74                         const base::TimeDelta& session_length) {
75   DCHECK(IsEnterpriseManaged());
76 
77   if (session_type != user_manager::USER_TYPE_REGULAR &&
78       session_type != user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
79     // No session length metric for other session types.
80     return;
81   }
82 
83   PrefService* local_state = g_browser_process->local_state();
84   local_state->SetInteger(prefs::kLastSessionType, session_type);
85   local_state->SetInt64(prefs::kLastSessionLength,
86                         session_length.ToInternalValue());
87   local_state->CommitPendingWrite();
88 }
89 
RecordStoredSessionLength()90 void RecordStoredSessionLength() {
91   DCHECK(IsEnterpriseManaged());
92 
93   PrefService* local_state = g_browser_process->local_state();
94   if (!local_state->HasPrefPath(prefs::kLastSessionType) ||
95       !local_state->HasPrefPath(prefs::kLastSessionLength)) {
96     return;
97   }
98 
99   const user_manager::UserType session_type =
100       static_cast<user_manager::UserType>(
101           local_state->GetInteger(prefs::kLastSessionType));
102   const base::TimeDelta session_length = base::TimeDelta::FromInternalValue(
103       local_state->GetInt64(prefs::kLastSessionLength));
104 
105   local_state->ClearPref(prefs::kLastSessionType);
106   local_state->ClearPref(prefs::kLastSessionLength);
107 
108   if (session_length.is_zero())
109     return;
110 
111   std::string metric_name;
112   if (session_type == user_manager::USER_TYPE_REGULAR) {
113     metric_name = "Enterprise.RegularUserSession.SessionLength";
114   } else if (session_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
115     metric_name = "Enterprise.PublicSession.SessionLength";
116   } else {
117     // NOTREACHED() since session length for other session types should not
118     // be recorded.
119     NOTREACHED();
120     return;
121   }
122 
123   // Report session duration for the first 24 hours, split into 144 buckets
124   // (i.e. every 10 minute). Note that sparse histogram is used here. It is
125   // important to limit the number of buckets to something reasonable.
126   base::UmaHistogramSparse(
127       metric_name,
128       GetMinutesToReport(session_length, 10, base::TimeDelta::FromHours(24)));
129 
130   if (chromeos::DemoSession::IsDeviceInDemoMode()) {
131     // Demo mode sessions will have shorter durations. Report session length
132     // rounded down to the nearest minute, up to two hours.
133     base::UmaHistogramSparse(
134         "DemoMode.SessionLength",
135         GetMinutesToReport(session_length, 1, base::TimeDelta::FromHours(2)));
136   }
137 }
138 
139 }  // namespace enterprise_user_session_metrics
140 }  // namespace chromeos
141