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
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_education/common/session/user_education_session_manager.h"
#include <utility>
#include "base/callback_list.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/user_metrics.h"
#include "base/time/time.h"
#include "components/user_education/common/session/user_education_idle_observer.h"
#include "components/user_education/common/session/user_education_idle_policy.h"
#include "components/user_education/common/user_education_features.h"
#include "components/user_education/common/user_education_storage_service.h"
namespace user_education {
UserEducationSessionManager::UserEducationSessionManager() = default;
UserEducationSessionManager::~UserEducationSessionManager() = default;
void UserEducationSessionManager::Init(
UserEducationStorageService* storage_service,
std::unique_ptr<UserEducationIdleObserver> idle_observer,
std::unique_ptr<UserEducationIdlePolicy> idle_policy) {
storage_service_ = storage_service;
idle_policy_ = std::move(idle_policy);
idle_policy_->Init(this, storage_service_.get());
// Assume the application is active at application start; this avoids making
// additional system calls during startup.
UpdateLastActiveTime(storage_service_->GetCurrentTime());
// Start observing state.
SetIdleObserver(std::move(idle_observer));
}
void UserEducationSessionManager::MaybeUpdateSessionState() {
if (!storage_service_) {
return;
}
// Determine if a new session could be started.
const auto old_state = storage_service_->ReadSessionData();
const auto now = storage_service_->GetCurrentTime();
if (!idle_policy_->IsNewSession(old_state.start_time,
old_state.most_recent_active_time, now)) {
return;
}
const auto last_active = idle_observer_->MaybeGetNewLastActiveTime();
if (last_active) {
UpdateLastActiveTime(*last_active);
}
}
base::CallbackListSubscription
UserEducationSessionManager::AddNewSessionCallback(
base::RepeatingClosure new_session_callback) {
return new_session_callbacks_.Add(std::move(new_session_callback));
}
bool UserEducationSessionManager::GetNewSessionSinceStartup() const {
return new_session_since_startup_;
}
void UserEducationSessionManager::OnNewSession(
const base::Time old_start_time,
const base::Time old_active_time,
const base::Time new_active_time) {
new_session_since_startup_ = true;
base::RecordAction(
base::UserMetricsAction("UserEducation.Session.ActivePeriodStart"));
// Now starting new session. The Active Period of the old session
// is the difference between old session times.
RecordActivePeriodDuration(old_active_time - old_start_time);
// The now-elapsed Idle Period is difference between now and the
// previous most_recent_active_time.
RecordIdlePeriodDuration(new_active_time - old_active_time);
// Notify any listeners of the new session.
new_session_callbacks_.Notify();
}
void UserEducationSessionManager::OnLastActiveTimeUpdating(base::Time) {}
void UserEducationSessionManager::SetIdleObserver(
std::unique_ptr<UserEducationIdleObserver> new_observer) {
idle_observer_ = std::move(new_observer);
idle_observer_->Init(storage_service_.get());
idle_observer_subscription_ = idle_observer_->AddUpdateCallback(
base::BindRepeating(&UserEducationSessionManager::UpdateLastActiveTime,
base::Unretained(this)));
idle_observer_->StartObserving();
}
void UserEducationSessionManager::RecordActivePeriodDuration(
base::TimeDelta duration) {
// Increments of 1 minute under 1 hour.
base::UmaHistogramCustomCounts(
"UserEducation.Session.ActivePeriodDuration.Min.Under1Hour",
duration.InMinutes(), /*min=*/1,
/*exclusive_max=*/60,
/*buckets=*/60);
// Increments of 15 minutes under 24 hours.
base::UmaHistogramCustomCounts(
"UserEducation.Session.ActivePeriodDuration.Min.Under24Hours",
duration.InMinutes(), /*min=*/1,
/*exclusive_max=*/60 * 24 /* minutes per 24 hours */,
/*buckets=*/24 * 4 /* per 15 minutes */);
}
void UserEducationSessionManager::RecordIdlePeriodDuration(
base::TimeDelta duration) {
// Increments of 15 minutes under 24 hours.
base::UmaHistogramCustomCounts(
"UserEducation.Session.IdlePeriodDuration.Min.Under24Hours",
duration.InMinutes(), /*min=*/1,
/*exclusive_max=*/60 * 24 /* minutes per 24 hours */,
/*buckets=*/24 * 4 /* per 15 minute */);
// Increments of ~13 hours under 28 days.
base::UmaHistogramCustomCounts(
"UserEducation.Session.IdlePeriodDuration.Hr.Under28Days",
duration.InHours(), /*min=*/1,
/*exclusive_max=*/24 * 28 /* hours per 28 days */,
/*buckets=*/50);
}
void UserEducationSessionManager::UpdateLastActiveTime(
base::Time new_active_time) {
CHECK(idle_policy_);
OnLastActiveTimeUpdating(new_active_time);
auto session_data = storage_service_->ReadSessionData();
const auto old_start_time = session_data.start_time;
const auto old_active_time = session_data.most_recent_active_time;
session_data.most_recent_active_time = new_active_time;
const bool is_new_session = idle_policy_->IsNewSession(
old_start_time, old_active_time, new_active_time);
if (is_new_session) {
session_data.start_time = new_active_time;
++session_data.session_number;
}
// Save the session data before calling OnNewSession, since some listeners
// will be relying on the data being current.
storage_service_->SaveSessionData(session_data);
if (is_new_session) {
OnNewSession(old_start_time, old_active_time, new_active_time);
}
}
} // namespace user_education
|