File: website_metrics.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (318 lines) | stat: -rw-r--r-- 12,268 bytes parent folder | download | duplicates (6)
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_APPS_APP_SERVICE_METRICS_WEBSITE_METRICS_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_METRICS_WEBSITE_METRICS_H_

#include <map>
#include <optional>

#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_multi_source_observation.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/webapps/browser/banners/app_banner_manager.h"
#include "content/public/browser/page.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"
#include "url/gurl.h"

class Browser;
class Profile;

namespace webapps {
enum class InstallableWebAppCheckResult;
struct WebAppBannerData;
}  // namespace webapps

namespace apps {

class WebsiteMetricsBrowserTest;
class TestWebsiteMetrics;

extern const char kWebsiteUsageTime[];
extern const char kRunningTimeKey[];
extern const char kUrlContentKey[];
extern const char kPromotableKey[];

// WebsiteMetrics monitors creation/deletion of Browser and its
// TabStripModel to record the website usage time metrics.
class WebsiteMetrics : public BrowserListObserver,
                       public TabStripModelObserver,
                       public aura::WindowObserver,
                       public wm::ActivationChangeObserver,
                       public history::HistoryServiceObserver {
 public:
  // Observer that is notified on certain website events like URL opened, URL
  // closed, etc. Observers are expected to register themselves on session
  // initialization so they do not miss out on events that happen before they
  // are registered.
  class Observer : public base::CheckedObserver {
   public:
    Observer() = default;
    Observer(const Observer&) = delete;
    Observer& operator=(const Observer&) = delete;
    ~Observer() override = default;

    // Invoked when a new URL is opened with specified `WebContents`. We also
    // return the URL that was opened in case there are further updates to
    // `WebContents` forcing a new URL opened event that will follow as a
    // separate notification.
    virtual void OnUrlOpened(const GURL& url_opened,
                             ::content::WebContents* web_contents) {}

    // Invoked when a URL is closed with specified `WebContents`. `WebContents`
    // could reflect current URL in case of content navigation, so we also
    // return the URL that was closed.
    virtual void OnUrlClosed(const GURL& url_closed,
                             ::content::WebContents* web_contents) {}

    // Invoked when URL usage metrics are being recorded (per URL that was used,
    // on a 5 minute interval). `running_time` represents the foreground usage
    // time in the last 5 minute interval. We do not track usage per
    // `WebContents` today. There is a possibility of losing out on initial
    // usage metric records if there are delays in observer registration.
    virtual void OnUrlUsage(const GURL& url, base::TimeDelta running_time) {}

    // Invoked when the `WebsiteMetrics` component (being observed) is being
    // destroyed.
    virtual void OnWebsiteMetricsDestroyed() {}
  };

  WebsiteMetrics(Profile* profile, int user_type_by_device_type);

  WebsiteMetrics(const WebsiteMetrics&) = delete;
  WebsiteMetrics& operator=(const WebsiteMetrics&) = delete;

  ~WebsiteMetrics() override;

  // BrowserListObserver overrides:
  void OnBrowserAdded(Browser* browser) override;

  // TabStripModelObserver overrides:
  void OnTabStripModelChanged(
      TabStripModel* tab_strip_model,
      const TabStripModelChange& change,
      const TabStripSelectionChange& selection) override;

  // wm::ActivationChangeObserver overrides:
  void OnWindowActivated(ActivationReason reason,
                         aura::Window* gained_active,
                         aura::Window* lost_active) override;

  // aura::WindowObserver:
  void OnWindowDestroying(aura::Window* window) override;

  // history::HistoryServiceObserver:
  void OnHistoryDeletions(history::HistoryService* history_service,
                          const history::DeletionInfo& deletion_info) override;
  void HistoryServiceBeingDeleted(
      history::HistoryService* history_service) override;

  // Save the usage time records to the local user perf.
  void OnFiveMinutes();

  // Records the usage time UKM each 2 hours.
  void OnTwoHours();

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

 private:
  friend class WebsiteMetricsBrowserTest;
  friend class TestWebsiteMetrics;

  // This class monitors the activated WebContent for the activated browser
  // window and notifies a navigation to the WebsiteMetrics.
  class ActiveTabWebContentsObserver
      : public content::WebContentsObserver,
        public webapps::AppBannerManager::Observer {
   public:
    ActiveTabWebContentsObserver(content::WebContents* contents,
                                 WebsiteMetrics* owner);

    ActiveTabWebContentsObserver(const ActiveTabWebContentsObserver&) = delete;
    ActiveTabWebContentsObserver& operator=(
        const ActiveTabWebContentsObserver&) = delete;

    ~ActiveTabWebContentsObserver() override;

    void OnPrimaryPageChanged();

    // content::WebContentsObserver
    void PrimaryPageChanged(content::Page& page) override;
    void WebContentsDestroyed() override;

    // webapps::AppBannerManager::Observer:
    void OnInstallableWebAppStatusUpdated(
        webapps::InstallableWebAppCheckResult result,
        const std::optional<webapps::WebAppBannerData>& data) override;

   private:
    raw_ptr<WebsiteMetrics> owner_;
    base::ScopedObservation<webapps::AppBannerManager,
                            webapps::AppBannerManager::Observer>
        app_banner_manager_observer_{this};
  };

  struct UrlInfo {
    UrlInfo() = default;
    explicit UrlInfo(const base::Value& value);
    ukm::SourceId source_id = ukm::kInvalidSourceId;
    base::TimeTicks start_time;
    // Running time in the past 5 minutes without noise.
    base::TimeDelta running_time_in_five_minutes;
    // Sum `running_time_in_five_minutes` with noise in the past 2 hours:
    // time1 * noise1 + time2 * noise2 + time3 * noise3....
    base::TimeDelta running_time_in_two_hours;

    bool is_activated = false;
    bool promotable = false;

    // Converts the struct UsageTime to base::Value::Dict, e.g.:
    // {
    //    "time": "3600",
    //    "url_content": "scope",
    //    "promotable": "false",
    // }
    base::Value::Dict ConvertToDict() const;
  };

  // Observes the root window's activation client for the OnWindowActivated
  // callback.
  void MaybeObserveWindowActivationClient(aura::Window* window);

  // Removes observing the root window's activation client when the last browser
  // window is closed.
  void MaybeRemoveObserveWindowActivationClient(aura::Window* window);

  void OnTabStripModelChangeInsert(aura::Window* window,
                                   TabStripModel* tab_strip_model,
                                   const TabStripModelChange::Insert& insert,
                                   const TabStripSelectionChange& selection);
  void OnTabStripModelChangeRemove(aura::Window* window,
                                   TabStripModel* tab_strip_model,
                                   const TabStripModelChange::Remove& remove,
                                   const TabStripSelectionChange& selection);
  void OnTabStripModelChangeReplace(
      const TabStripModelChange::Replace& replace);
  void OnActiveTabChanged(aura::Window* window,
                          content::WebContents* old_contents,
                          content::WebContents* new_contents);
  void OnTabClosed(content::WebContents* web_contents);

  // Called by |WebsiteMetrics::ActiveTabWebContentsObserver|.
  virtual void OnWebContentsUpdated(content::WebContents* web_contents);
  virtual void OnInstallableWebAppStatusUpdated(
      content::WebContents* web_contents,
      webapps::InstallableWebAppCheckResult result,
      const std::optional<webapps::WebAppBannerData>& data);

  // Adds the url info to `url_infos_`.
  void AddUrlInfo(const GURL& url,
                  ukm::SourceId source_id,
                  const base::TimeTicks& start_time,
                  bool is_activated,
                  bool promotable);

  // Modifies `url_infos_` to set whether the website can be promoted to PWA,
  // when the website manifest is updated.
  void UpdateUrlInfo(const GURL& old_url, bool promotable);

  void SetWindowActivated(aura::Window* window);

  void SetWindowInActivated(aura::Window* window);

  void SetTabActivated(content::WebContents* web_contents);

  void SetTabInActivated(content::WebContents* web_contents);

  // Saves the website usage time in `url_infos_` to the user pref each 5
  // minutes.
  void SaveUsageTime();

  // Records the website usage time metrics each 2 hours.
  void RecordUsageTime();

  // Records the usage time UKM saved in the user pref at the first 5 minutes
  // after the user logs in.
  void RecordUsageTimeFromPref();

  void EmitUkm(ukm::SourceId source_id,
               int64_t usage_time,
               bool promotable,
               bool is_from_last_login);

  const raw_ptr<Profile> profile_;

  BrowserTabStripTracker browser_tab_strip_tracker_;

  // The map from the window to the active tab contents.
  base::flat_map<aura::Window*, raw_ptr<content::WebContents, CtnExperimental>>
      window_to_web_contents_;

  // The map from the root window's activation client to windows.
  std::map<wm::ActivationClient*,
           std::set<raw_ptr<aura::Window, SetExperimental>>>
      activation_client_to_windows_;

  std::map<content::WebContents*, std::unique_ptr<ActiveTabWebContentsObserver>>
      webcontents_to_observer_map_;

  // The map from the web_contents to the ukm key url. When the url for web
  // contents is updated in OnWebContentsUpdated, we can get the previous url
  // from this map to calculate the usage time for the previous url.
  //
  // If the url is used for an app, it won't be added to the map, because the
  // app metrics can record the usage time metrics.
  //
  // If the website has a manifest, we might use the scope or the start url as
  // the ukm key url. Otherwise, the visible url is used as the ukm key url.
  std::map<content::WebContents*, GURL> webcontents_to_ukm_key_;

  // Saves the usage info for the activated urls in activated windows for the
  // UKM records. `url_infos_` is cleared after recording the UKM each 2 hours.
  std::map<GURL, UrlInfo> url_infos_;

  int user_type_by_device_type_ = 0;

  bool should_record_ukm_from_pref_ = true;

  base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
      observed_windows_{this};

  // For Lacros browser windows, there could be multiple root windows for
  // browser windows, and multiple ActivationClients.
  base::ScopedMultiSourceObservation<wm::ActivationClient,
                                     wm::ActivationChangeObserver>
      activation_client_observations_{this};

  base::ScopedObservation<history::HistoryService,
                          history::HistoryServiceObserver>
      history_observation_{this};

  base::ObserverList<Observer> observers_;

  base::WeakPtrFactory<WebsiteMetrics> weak_factory_{this};
};

}  // namespace apps

#endif  // CHROME_BROWSER_APPS_APP_SERVICE_METRICS_WEBSITE_METRICS_H_