1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_METRICS_DEMO_SESSION_METRICS_RECORDER_H_
#define ASH_METRICS_DEMO_SESSION_METRICS_RECORDER_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "ash/ash_export.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chromeos/ui/base/app_types.h"
#include "ui/aura/window_observer.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/base/user_activity/user_activity_observer.h"
#include "ui/events/event_handler.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"
namespace base {
class RepeatingTimer;
} // namespace base
namespace ash {
// A metrics recorder for demo sessions that samples the active window's app or
// window type. Only used when the device is in Demo Mode.
class ASH_EXPORT DemoSessionMetricsRecorder
: public ui::UserActivityObserver,
public wm::ActivationChangeObserver,
public ui::EventHandler {
public:
// These apps are preinstalled in Demo Mode. This list is not exhaustive, and
// includes first- and third-party Chrome and ARC apps.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class DemoModeApp {
kBrowser = 0,
kOtherChromeApp = 1,
kOtherArcApp = 2,
kOtherWindow = 3,
kHighlights = 4, // Auto-launched Demo Mode app highlighting CrOS features.
kAsphalt8 = 5, // Android racing game demo app.
kCamera = 6,
kFiles = 7,
kGetHelp = 8,
kGoogleKeepChromeApp = 9,
kGooglePhotos = 10,
kGoogleSheetsAndroidApp = 11,
kGoogleSlidesAndroidApp = 12,
kInfinitePainter = 13, // Android painting app.
kMyScriptNebo = 14, // Android note-taking app.
kPlayStore = 15,
kSquid = 16, // Android note-taking app.
kWebStore = 17,
kYouTube = 18,
kScreensaver = 19, // Demo Mode screensaver app.
kAsphalt9 = 20, // Android racing game demo app.
kStardewValley = 21, // Android farming game demo app.
kKinemaster = 22, // Android video editing software demo app. nocheck
kGoogleKeepAndroidApp = 23,
kAutoCAD = 24, // Android 2D/3D drawing software demo app.
kPixlr = 25, // Android photo editing software demo app.
kCalculator = 26, // Essential apps calculator.
kCalendar = 27,
kGoogleDocsChromeApp = 28,
kGoogleSheetsChromeApp = 29,
kGoogleSlidesChromeApp = 30,
kYoutubePwa = 31,
kGoogleDocsPwa = 32,
kGoogleMeetPwa = 33,
kGoogleSheetsPwa = 34,
kSpotify = 35,
kBeFunky = 36,
kClipchamp = 37,
kGeForceNow = 38,
kZoom = 39,
kSumo = 40,
kAdobeSpark = 41,
kMinecraft = 42,
kGemini = 43,
// Add future entries above this comment, in sync with enums.xml.
// Update kMaxValue to the last value.
kMaxValue = kGemini,
};
enum class ExitSessionFrom {
kShelf = 0,
kSystemTray = 1,
kSystemTrayPowerButton = 2,
};
// The types of the result of the demo account setup or cleanup request.
// This enum is tied directly to a UMA enum
// `DemoModeSignedInAccountRequestResult`, and should always reflect it (do
// not change one without changing the other). Entries should never be
// modified or reordered. Entries can only be removed by deprecating it and
// its value should never be reused. New ones should be added to the end
// (right before the max value).
enum class DemoAccountRequestResultCode {
kSuccess = 0, // Demo account request success.
kResponseParsingError = 1, // Malformat Http response.
kInvalidCreds = 2, // Missing required credential for login.
kEmptyResponse = 3, // Empty Http response.
kNetworkError = 4, // Network error.
kRequestFailed = 5, // Server side error or out of quota.
kCloudPolicyNotConnected =
6, // Unable to obtain the DM Token and the Client ID due to the cloud
// policy not connected.
kEmptyDMToken = 7, // The DM Token on the device is empty.
kEmptyClientID = 8, // The Client ID on the device is empty.
kQuotaExhaustedRetriable =
9, // Server quota exhausted, might be max QPS reached.
kQuotaExhaustedNotRetriable =
10, // Server quota exhausted, device might be blocked.
kMaxValue = kQuotaExhaustedNotRetriable,
};
// Types of the current demo session.
//
// It is worth noting that here is not perfectly accurate on the word
// "current", because functions in `[demo_login_controller.cc]
// LoginDemoAccount()` are asyc calls and they may fail with no failure
// handlers. It may not reflect the actual current session type on failure,
// but instead, it's more like an "upcoming" session type, also because it's
// set before entering the session.
//
// However, when you get its value in `DemoSessionMetricsRecorder`, it is
// reflecting the current session type as we're currently in the session.
enum class SessionType {
// Classic managed guest session.
kClassicMGS = 0,
// Signed-in demo session.
kSignedInDemoSession = 1,
// Fallback managed guest session due to the sign-in failure.
kFallbackMGS = 2,
};
static constexpr char kUserClicksAndPressesMetric[] =
"DemoMode.UserClicksAndPresses";
static void RecordExitSessionAction(ExitSessionFrom recorded_from);
// Getter of this class' instance.
static DemoSessionMetricsRecorder* Get();
// Records the result of the demo account setup request.
static void ReportDemoAccountSetupResult(
DemoAccountRequestResultCode result_code);
// Records the result of the demo account cleanup request.
static void ReportDemoAccountCleanupResult(
DemoAccountRequestResultCode result_code);
// It is used by Demo Mode only, and called by DemoLoginController before
// entering the session, to set the upcoming session type.
static void SetCurrentSessionType(SessionType session_type);
// Get the type of the current demo session.
static SessionType GetCurrentSessionTypeForTesting();
// Records cloud policy connections timeout.
static void RecordCloudPolicyConnectionTimeout();
// The recorder will create a normal timer by default. Tests should provide a
// mock timer to control sampling periods.
explicit DemoSessionMetricsRecorder(
std::unique_ptr<base::RepeatingTimer> timer = nullptr);
DemoSessionMetricsRecorder(const DemoSessionMetricsRecorder&) = delete;
DemoSessionMetricsRecorder& operator=(const DemoSessionMetricsRecorder&) =
delete;
~DemoSessionMetricsRecorder() override;
// ui::UserActivityObserver:
void OnUserActivity(const ui::Event* event) override;
// wm::ActivationChangeObserver:
void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
// Records the duration of time the user spent interacting with the current
// demo mode signed-in shopper session, measured from first user activity to
// last user activity.
void ReportShopperSessionDwellTime();
// Called by DemoModeWindowCloser::OnInstanceUpdate:
// Passing `app_id_or_package` instead of `aura::Window` here because app
// information set in window property might now be ready on app creation.
void OnAppCreation(const std::string& app_id_or_package,
const bool is_arc_app);
void OnAppDestruction(const std::string& app_id_or_package,
const bool is_arc_app);
private:
// Starts the timer for periodic sampling.
void StartRecording();
// Records the active window's app type or, if the user has been inactive for
// too long, pauses sampling and wipes samples from the inactive period.
void TakeSampleOrPause();
// Emits histograms for recorded samples.
void ReportSamples();
// Records |app| as being seen while sampling all active apps.
void RecordActiveAppSample(DemoModeApp app);
// Indicates whether the specified app_id should be recorded for
// the unique-apps-launched stat.
bool ShouldRecordAppLaunch(const std::string& app_id);
// Records the specified app's launch, subject to the
// restrictions of ShouldRecordAppLaunch().
void RecordAppLaunch(const std::string& id, chromeos::AppType app_type);
// Emits various histograms for unique apps launched.
void ReportUniqueAppsLaunched();
// Records the duration of time the user spent interacting with the current
// demo session, measured from first user activity to last user activity.
void ReportDwellTime();
// Records the number of times the user clicks mouse/trackpad and presses
// screen in the demo session.
void ReportUserClickesAndPresses();
// Stores samples as they are collected. Report to UMA if we see user
// activity soon after. Guaranteed not to grow too large.
std::vector<DemoModeApp> unreported_samples_;
// Indicates whether the unique-app-launch stats recording has been enabled.
bool unique_apps_launched_recording_enabled_ = false;
// Tracks the ids of apps that have been launched in Demo Mode.
base::flat_set<std::string> unique_apps_launched_;
// Used for subscribing to window activation events.
raw_ptr<wm::ActivationClient> activation_client_ = nullptr;
// How many periods have elapsed since the last user activity.
int periods_since_activity_ = 0;
// Indicates number of user clicks mouse/trackpad and presses screen with
// demo mode in the current session.
int user_clicks_and_presses_ = 0;
base::TimeTicks first_user_activity_;
base::TimeTicks last_user_activity_;
base::TimeTicks shopper_session_first_user_activity_;
std::unique_ptr<base::RepeatingTimer> timer_;
base::ScopedObservation<ui::UserActivityDetector, ui::UserActivityObserver>
observation_{this};
class ActiveAppArcPackageNameObserver;
class UniqueAppsLaunchedArcPackageNameObserver;
std::unique_ptr<UniqueAppsLaunchedArcPackageNameObserver>
unique_apps_arc_package_name_observer_;
std::unique_ptr<ActiveAppArcPackageNameObserver>
active_app_arc_package_name_observer_;
// Tracks the app start time for app defined in `kAppsHistogramSuffix`.
std::map<DemoModeApp, base::TimeTicks> apps_start_time_;
};
} // namespace ash
#endif // ASH_METRICS_DEMO_SESSION_METRICS_RECORDER_H_
|