guest_os_engagement_metrics.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2019 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. #include "components/guest_os/guest_os_engagement_metrics.h"
  5. #include <string>
  6. #include <utility>
  7. #include "base/logging.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/system/sys_info.h"
  10. #include "base/time/default_clock.h"
  11. #include "base/time/default_tick_clock.h"
  12. #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
  13. #include "chromeos/dbus/power_manager/idle.pb.h"
  14. #include "components/exo/wm_helper.h"
  15. #include "components/guest_os/guest_os_prefs.h"
  16. #include "components/prefs/pref_service.h"
  17. #include "components/session_manager/core/session_manager.h"
  18. namespace guest_os {
  19. namespace {
  20. constexpr base::TimeDelta kUpdateEngagementTimePeriod = base::Minutes(1);
  21. constexpr base::TimeDelta kSaveEngagementTimeToPrefsPeriod = base::Minutes(30);
  22. int GetDayId(const base::Clock* clock) {
  23. return clock->Now().LocalMidnight().since_origin().InDays();
  24. }
  25. } // namespace
  26. GuestOsEngagementMetrics::GuestOsEngagementMetrics(
  27. PrefService* pref_service,
  28. WindowMatcher window_matcher,
  29. const std::string& pref_prefix,
  30. const std::string& uma_name)
  31. : GuestOsEngagementMetrics(pref_service,
  32. window_matcher,
  33. pref_prefix,
  34. uma_name,
  35. base::DefaultClock::GetInstance(),
  36. base::DefaultTickClock::GetInstance()) {}
  37. // Private, for testing use only
  38. GuestOsEngagementMetrics::GuestOsEngagementMetrics(
  39. PrefService* pref_service,
  40. WindowMatcher window_matcher,
  41. const std::string& pref_prefix,
  42. const std::string& uma_name,
  43. const base::Clock* clock,
  44. const base::TickClock* tick_clock)
  45. : pref_service_(pref_service),
  46. window_matcher_(window_matcher),
  47. pref_prefix_(pref_prefix),
  48. uma_name_(uma_name),
  49. clock_(clock),
  50. tick_clock_(tick_clock),
  51. last_update_ticks_(tick_clock_->NowTicks()) {
  52. // WMHelper, SessionManager and PowerManagerClient may not exist in tests.
  53. if (exo::WMHelper::HasInstance())
  54. exo::WMHelper::GetInstance()->AddActivationObserver(this);
  55. if (session_manager::SessionManager::Get()) {
  56. session_active_ =
  57. (session_manager::SessionManager::Get()->session_state() ==
  58. session_manager::SessionState::ACTIVE);
  59. session_manager::SessionManager::Get()->AddObserver(this);
  60. }
  61. if (chromeos::PowerManagerClient::Get())
  62. chromeos::PowerManagerClient::Get()->AddObserver(this);
  63. DCHECK(pref_service_);
  64. RestoreEngagementTimeFromPrefs();
  65. update_engagement_time_timer_.Start(
  66. FROM_HERE, kUpdateEngagementTimePeriod, this,
  67. &GuestOsEngagementMetrics::UpdateEngagementTime);
  68. save_engagement_time_to_prefs_timer_.Start(
  69. FROM_HERE, kSaveEngagementTimeToPrefsPeriod, this,
  70. &GuestOsEngagementMetrics::SaveEngagementTimeToPrefs);
  71. }
  72. GuestOsEngagementMetrics::~GuestOsEngagementMetrics() {
  73. save_engagement_time_to_prefs_timer_.Stop();
  74. update_engagement_time_timer_.Stop();
  75. UpdateEngagementTime();
  76. SaveEngagementTimeToPrefs();
  77. // Observers for WMHelper, SessionManager and PowerManagerClient may not
  78. // have been added in tests.
  79. if (chromeos::PowerManagerClient::Get())
  80. chromeos::PowerManagerClient::Get()->RemoveObserver(this);
  81. if (session_manager::SessionManager::Get())
  82. session_manager::SessionManager::Get()->RemoveObserver(this);
  83. // If WMHelper is already destroyed, do nothing.
  84. // TODO(crbug.com/748380): Fix shutdown order.
  85. if (exo::WMHelper::HasInstance())
  86. exo::WMHelper::GetInstance()->RemoveActivationObserver(this);
  87. }
  88. void GuestOsEngagementMetrics::SetBackgroundActive(bool background_active) {
  89. if (background_active_ == background_active)
  90. return;
  91. UpdateEngagementTime();
  92. background_active_ = background_active;
  93. }
  94. void GuestOsEngagementMetrics::OnWindowActivated(
  95. wm::ActivationChangeObserver::ActivationReason reason,
  96. aura::Window* gained_active,
  97. aura::Window* lost_active) {
  98. UpdateEngagementTime();
  99. matched_window_active_ = gained_active && window_matcher_.Run(gained_active);
  100. }
  101. void GuestOsEngagementMetrics::OnSessionStateChanged() {
  102. UpdateEngagementTime();
  103. session_active_ = session_manager::SessionManager::Get()->session_state() ==
  104. session_manager::SessionState::ACTIVE;
  105. }
  106. void GuestOsEngagementMetrics::ScreenIdleStateChanged(
  107. const power_manager::ScreenIdleState& proto) {
  108. UpdateEngagementTime();
  109. screen_dimmed_ = proto.dimmed();
  110. }
  111. void GuestOsEngagementMetrics::RestoreEngagementTimeFromPrefs() {
  112. // Restore accumulated results only if they were recorded on the same OS
  113. // version.
  114. if (pref_service_->GetString(pref_prefix_ +
  115. prefs::kEngagementTimeOsVersion) ==
  116. base::SysInfo::OperatingSystemVersion()) {
  117. day_id_ =
  118. pref_service_->GetInteger(pref_prefix_ + prefs::kEngagementTimeDayId);
  119. engagement_time_total_ =
  120. pref_service_->GetTimeDelta(pref_prefix_ + prefs::kEngagementTimeTotal);
  121. engagement_time_foreground_ = pref_service_->GetTimeDelta(
  122. pref_prefix_ + prefs::kEngagementTimeForeground);
  123. engagement_time_background_ = pref_service_->GetTimeDelta(
  124. pref_prefix_ + prefs::kEngagementTimeBackground);
  125. } else {
  126. ResetEngagementTimePrefs();
  127. }
  128. RecordEngagementTimeToUmaIfNeeded();
  129. }
  130. void GuestOsEngagementMetrics::SaveEngagementTimeToPrefs() {
  131. DCHECK(pref_service_);
  132. pref_service_->SetString(pref_prefix_ + prefs::kEngagementTimeOsVersion,
  133. base::SysInfo::OperatingSystemVersion());
  134. pref_service_->SetInteger(pref_prefix_ + prefs::kEngagementTimeDayId,
  135. day_id_);
  136. pref_service_->SetTimeDelta(pref_prefix_ + prefs::kEngagementTimeTotal,
  137. engagement_time_total_);
  138. pref_service_->SetTimeDelta(pref_prefix_ + prefs::kEngagementTimeForeground,
  139. engagement_time_foreground_);
  140. pref_service_->SetTimeDelta(pref_prefix_ + prefs::kEngagementTimeBackground,
  141. engagement_time_background_);
  142. }
  143. void GuestOsEngagementMetrics::UpdateEngagementTime() {
  144. VLOG(2) << "last state: screen_dimmed=" << screen_dimmed_
  145. << " session_active=" << session_active_
  146. << " background_active=" << background_active_
  147. << " matched_window_active=" << matched_window_active_;
  148. base::TimeTicks now = tick_clock_->NowTicks();
  149. base::TimeDelta elapsed = now - last_update_ticks_;
  150. if (ShouldAccumulateEngagementTotalTime()) {
  151. VLOG(2) << "accumulate to total time " << elapsed;
  152. engagement_time_total_ += elapsed;
  153. if (ShouldAccumulateEngagementForegroundTime()) {
  154. VLOG(2) << "accumulate to foreground time " << elapsed;
  155. engagement_time_foreground_ += elapsed;
  156. } else if (ShouldAccumulateEngagementBackgroundTime()) {
  157. VLOG(2) << "accumulate to background time " << elapsed;
  158. engagement_time_background_ += elapsed;
  159. }
  160. }
  161. last_update_ticks_ = now;
  162. RecordEngagementTimeToUmaIfNeeded();
  163. }
  164. void GuestOsEngagementMetrics::RecordEngagementTimeToUmaIfNeeded() {
  165. if (!ShouldRecordEngagementTimeToUma())
  166. return;
  167. VLOG(2) << "day changed, recording engagement time to UMA";
  168. UmaHistogramCustomTimes(uma_name_ + ".EngagementTime.Total",
  169. engagement_time_total_, base::Seconds(1),
  170. base::Days(1) + kUpdateEngagementTimePeriod, 50);
  171. UmaHistogramCustomTimes(
  172. uma_name_ + ".EngagementTime." + uma_name_ + "Total",
  173. engagement_time_foreground_ + engagement_time_background_,
  174. base::Seconds(1), base::Days(1) + kUpdateEngagementTimePeriod, 50);
  175. UmaHistogramCustomTimes(uma_name_ + ".EngagementTime.Foreground",
  176. engagement_time_foreground_, base::Seconds(1),
  177. base::Days(1) + kUpdateEngagementTimePeriod, 50);
  178. UmaHistogramCustomTimes(uma_name_ + ".EngagementTime.Background",
  179. engagement_time_background_, base::Seconds(1),
  180. base::Days(1) + kUpdateEngagementTimePeriod, 50);
  181. ResetEngagementTimePrefs();
  182. }
  183. void GuestOsEngagementMetrics::ResetEngagementTimePrefs() {
  184. day_id_ = GetDayId(clock_);
  185. engagement_time_total_ = base::TimeDelta();
  186. engagement_time_foreground_ = base::TimeDelta();
  187. engagement_time_background_ = base::TimeDelta();
  188. SaveEngagementTimeToPrefs();
  189. }
  190. bool GuestOsEngagementMetrics::ShouldAccumulateEngagementTotalTime() const {
  191. return session_active_ && !screen_dimmed_;
  192. }
  193. bool GuestOsEngagementMetrics::ShouldAccumulateEngagementForegroundTime()
  194. const {
  195. return matched_window_active_;
  196. }
  197. bool GuestOsEngagementMetrics::ShouldAccumulateEngagementBackgroundTime()
  198. const {
  199. return background_active_;
  200. }
  201. bool GuestOsEngagementMetrics::ShouldRecordEngagementTimeToUma() const {
  202. return day_id_ != GetDayId(clock_);
  203. }
  204. std::unique_ptr<GuestOsEngagementMetrics>
  205. GuestOsEngagementMetrics::GetEngagementMetricsForTesting(
  206. PrefService* pref_service,
  207. WindowMatcher window_matcher,
  208. const std::string& pref_prefix,
  209. const std::string& uma_name,
  210. const base::Clock* clock,
  211. const base::TickClock* tick_clock) {
  212. GuestOsEngagementMetrics* metrics = new GuestOsEngagementMetrics(
  213. pref_service, window_matcher, pref_prefix, uma_name, clock, tick_clock);
  214. // WrapUnique is needed because the constructor is private.
  215. return base::WrapUnique(metrics);
  216. }
  217. } // namespace guest_os