File: manifest_update_manager.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 (206 lines) | stat: -rw-r--r-- 7,803 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
// Copyright 2019 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_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_

#include <map>
#include <memory>
#include <optional>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/web_applications/manifest_update_utils.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_manager_observer.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "components/webapps/common/web_app_id.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/ash/experiences/system_web_apps/types/system_web_app_delegate_map.h"
#endif

namespace content {
class WebContents;
}

namespace web_app {

class WebAppProvider;

// Documentation: docs/webapps/manifest_update_process.md
//
// Checks for updates to a web app's manifest and triggers a reinstall if the
// current installation is out of date.
//
// Update checks are throttled per app (see MaybeConsumeUpdateCheck()) to avoid
// excessive updating on pathological sites.
//
// Each update check is performed by a |ManifestUpdateCommand|, see that class
// for details about what happens during a check.
//
// TODO(crbug.com/40611449): Replace MaybeUpdate() with a background check
// instead of being triggered by page loads.
class ManifestUpdateManager final : public WebAppInstallManagerObserver {
 public:
  class ScopedBypassWindowCloseWaitingForTesting {
   public:
    ScopedBypassWindowCloseWaitingForTesting();
    ScopedBypassWindowCloseWaitingForTesting(
        const ScopedBypassWindowCloseWaitingForTesting&) = delete;
    ScopedBypassWindowCloseWaitingForTesting& operator=(
        const ScopedBypassWindowCloseWaitingForTesting&) = delete;
    ~ScopedBypassWindowCloseWaitingForTesting();
  };

  using UpdatePendingCallback = base::OnceCallback<void(const GURL& url)>;
  // Sets a |callback| for testing code to get notified when a manifest update
  // is needed and there is a PWA window preventing the update from proceeding.
  // Only called once, iff the update process determines that waiting is needed.
  static void SetUpdatePendingCallbackForTesting(
      UpdatePendingCallback callback);

  using ResultCallback =
      base::OnceCallback<void(const GURL& url, ManifestUpdateResult result)>;
  static void SetResultCallbackForTesting(ResultCallback callback);

  ManifestUpdateManager();
  ~ManifestUpdateManager() override;

#if BUILDFLAG(IS_CHROMEOS)
  void SetSystemWebAppDelegateMap(
      const ash::SystemWebAppDelegateMap* system_web_apps_delegate_map);
#endif

  void SetProvider(base::PassKey<WebAppProvider>, WebAppProvider& provider);
  void Start();
  void Shutdown();

  void MaybeUpdate(const GURL& url,
                   const std::optional<webapps::AppId>& app_id,
                   content::WebContents* web_contents);
  bool IsUpdateConsumed(const webapps::AppId& app_id, base::Time check_time);
  bool IsUpdateCommandPending(const webapps::AppId& app_id);

  // WebAppInstallManagerObserver:
  void OnWebAppWillBeUninstalled(const webapps::AppId& app_id) override;
  void OnWebAppInstallManagerDestroyed() override;

  void set_time_override_for_testing(base::Time time_override) {
    time_override_for_testing_ = time_override;
  }

  void hang_update_checks_for_testing() {
    hang_update_checks_for_testing_ = true;
  }

  void ResetManifestThrottleForTesting(const webapps::AppId& app_id);
  // Return whether there are pending updates waiting for the page load to
  // finish.
  bool HasUpdatesPendingLoadFinishForTesting();
  void SetLoadFinishedCallbackForTesting(
      base::OnceClosure load_finished_callback);

  bool IsAppPendingPageAndManifestUrlLoadForTesting(
      const webapps::AppId& app_id);

 private:
  // This class is used to either observe the url loading or web_contents
  // destruction before manifest update tasks can be scheduled. Once any
  // of those events have been fired, observing is stopped.
  class PreUpdateWebContentsObserver;

  // Store information regarding the entire manifest update in different stages.
  // The following steps are followed for the update:
  // 1. The UpdateStage is initialized by passing an observer, who waits till
  // page loading has finished. During the lifetime of the observer,
  // the update_task stays uninitialized.
  // 2. The update_task is initialized as soon as the observer fires a
  // DidFinishLoad and the observer is destructed. This ensures that at any
  // point, either the observer or the update_task exists, but not both. This
  // helps reason about the entire process at different stages of its
  // functionality. This class is owned by the ManifestUpdateManager, and is
  // guaranteed to hold an observer OR an update_task always, but never both.
  struct UpdateStage {
    UpdateStage(const GURL& url,
                std::unique_ptr<PreUpdateWebContentsObserver> observer);
    ~UpdateStage();

    GURL url;
    enum Stage {
      kWaitingForPageLoadAndManifestUrl = 0,
      kCheckingManifestDiff = 1,
    } stage = kWaitingForPageLoadAndManifestUrl;
    std::unique_ptr<PreUpdateWebContentsObserver> observer;
  };

  void StartCheckAfterPageAndManifestUrlLoad(
      const webapps::AppId& app_id,
      base::Time check_time,
      base::WeakPtr<content::WebContents> web_contents);

  void OnManifestCheckAwaitAppWindowClose(
      base::WeakPtr<content::WebContents> contents,
      const GURL& url,
      const webapps::AppId& app_id,
      ManifestUpdateCheckResult check_result,
      std::unique_ptr<WebAppInstallInfo> install_info);

  bool MaybeConsumeUpdateCheck(const GURL& origin,
                               const webapps::AppId& app_id,
                               base::Time check_time);

  std::optional<base::Time> GetLastUpdateCheckTime(
      const webapps::AppId& app_id) const;

  void SetLastUpdateCheckTime(const GURL& origin,
                              const webapps::AppId& app_id,
                              base::Time time);

  void OnUpdateStopped(base::WeakPtr<content::WebContents> web_contents,
                       const GURL& url,
                       const webapps::AppId& app_id,
                       ManifestUpdateResult result);

  void NotifyResult(const GURL& url,
                    const std::optional<webapps::AppId>& app_id,
                    ManifestUpdateResult result);

  static bool& BypassWindowCloseWaitingForTesting();

#if BUILDFLAG(IS_CHROMEOS)
  raw_ptr<const ash::SystemWebAppDelegateMap, DanglingUntriaged>
      system_web_apps_delegate_map_ = nullptr;
#endif
  raw_ptr<WebAppProvider> provider_ = nullptr;

  base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
      install_manager_observation_{this};

  std::map<webapps::AppId, UpdateStage> update_stages_;
  base::flat_map<webapps::AppId, base::Time> last_update_check_;

  std::optional<base::Time> time_override_for_testing_;

  bool started_ = false;
  bool hang_update_checks_for_testing_ = false;

  base::OnceClosure load_finished_callback_;

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

}  // namespace web_app

#endif  // CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_