File: externally_managed_app_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 (309 lines) | stat: -rw-r--r-- 12,471 bytes parent folder | download | duplicates (5)
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
// 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 CHROME_BROWSER_WEB_APPLICATIONS_EXTERNALLY_MANAGED_APP_MANAGER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_EXTERNALLY_MANAGED_APP_MANAGER_H_

#include <iosfwd>
#include <map>
#include <memory>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/web_applications/external_install_options.h"
#include "components/webapps/common/web_app_id.h"
#include "url/gurl.h"

class GURL;
class Profile;

namespace base {
class Value;
}

namespace webapps {
enum class InstallResultCode;
enum class UninstallResultCode;
class WebAppUrlLoader;
}

namespace content {
class WebContents;
}  // namespace content

namespace web_app {

class AllAppsLock;
class ExternallyManagedAppRegistrationTaskBase;
class WebAppDataRetriever;
class WebAppProvider;

enum class RegistrationResultCode { kSuccess, kAlreadyRegistered, kTimeout };

struct ExternallyManagedAppManagerInstallResult {
  ExternallyManagedAppManagerInstallResult();
  explicit ExternallyManagedAppManagerInstallResult(
      webapps::InstallResultCode code,
      std::optional<webapps::AppId> app_id = std::nullopt,
      bool did_uninstall_and_replace = false);
  ExternallyManagedAppManagerInstallResult(
      const ExternallyManagedAppManagerInstallResult&);
  ~ExternallyManagedAppManagerInstallResult();

  bool operator==(const ExternallyManagedAppManagerInstallResult& other) const;

  webapps::InstallResultCode code;
  std::optional<webapps::AppId> app_id;
  bool did_uninstall_and_replace = false;
  // When adding fields, please update the `==` and `<<` operators to include
  // the new field.
};

// ExternallyManagedAppManager installs, uninstalls, and updates apps that are
// externally managed. This means that they are not installed by the user, but
// instead through a different system (enterprise installs, device default
// installs, etc). See ExternalInstallSource for all of the different externally
// managed app types. Typically there is one "manager" class per externally
// managed app type that figures out the list of apps to have installed, and
// that class will call SynchronizeApps for a given external install type.
//
// Implementations of this class should perform each set of operations serially
// in the order in which they arrive. For example, if an uninstall request gets
// queued while an update request for the same app is pending, implementations
// should wait for the update request to finish before uninstalling the app.
//
// This class also supports installing a "placeholder" app by the
// |install_placeholder| in ExternalInstallOptions. This placeholder app is
// installed if the install url given fails to fully load so a manifest cannot
// be resolved, and a placeholder app is installed instead. Every time the user
// navigates a page, if that page is ever a URL that a placeholder app is
// 'holding' (as the app failed to load originally), then the install is
// re-initiated, and if successful, the placeholder app is removed.
class ExternallyManagedAppManager {
 public:
  // Test class to drop requests instead of enqueueing them for installation.
  // TODO(crbug.com/408163317): Do not use, this is an implementation detail and
  // will be removed later.
  class ScopedDropRequestsForTesting {
   public:
    ScopedDropRequestsForTesting();
    ScopedDropRequestsForTesting(const ScopedDropRequestsForTesting&) = delete;
    ScopedDropRequestsForTesting& operator=(
        const ScopedDropRequestsForTesting&) = delete;
    ~ScopedDropRequestsForTesting();
  };

  using InstallResult = ExternallyManagedAppManagerInstallResult;

  using OnceInstallCallback =
      base::OnceCallback<void(const GURL& install_url, InstallResult result)>;
  using RepeatingInstallCallback =
      base::RepeatingCallback<void(const GURL& install_url,
                                   InstallResult result)>;
  using RegistrationCallback =
      base::RepeatingCallback<void(const GURL& launch_url,
                                   RegistrationResultCode code)>;
  using UninstallCallback =
      base::RepeatingCallback<void(const GURL& install_url,
                                   webapps::UninstallResultCode)>;
  using SynchronizeCallback = base::OnceCallback<void(
      std::map<GURL /*install_url*/, InstallResult> install_results,
      std::map<GURL /*install_url*/, webapps::UninstallResultCode>
          uninstall_results)>;

  explicit ExternallyManagedAppManager(Profile* profile);
  ExternallyManagedAppManager(const ExternallyManagedAppManager&) = delete;
  ExternallyManagedAppManager& operator=(const ExternallyManagedAppManager&) =
      delete;
  virtual ~ExternallyManagedAppManager();

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

  // Queues an installation operation with the highest priority. Essentially
  // installing the app immediately if there are no ongoing operations or
  // installing the app right after the current operation finishes. Runs its
  // callback with the URL in |install_options| and with the id of the installed
  // app or an empty string if the installation fails.
  //
  // Fails if the same operation has been queued before. Should only be used in
  // response to a user action e.g. the user clicked an install button.
  virtual void InstallNow(ExternalInstallOptions install_options,
                          OnceInstallCallback callback);

  // Queues an installation operation the end of current tasks. Runs its
  // callback with the URL in |install_options| and with the id of the installed
  // app or an empty string if the installation fails.
  //
  // Fails if the same operation has been queued before.
  virtual void Install(ExternalInstallOptions install_options,
                       OnceInstallCallback callback);

  // Installs an app for each ExternalInstallOptions in
  // |desired_apps_install_options| and uninstalls any apps in
  // GetInstalledAppUrls(install_source) that are not in
  // |desired_apps_install_options|'s URLs.
  //
  // All apps in |desired_apps_install_options| should have |install_source| as
  // their source.
  //
  // Once all installs/uninstalls are complete, |callback| will be run with the
  // success/failure status of the synchronization.
  //
  // Note that this returns after queueing work (installation and
  // uninstallation) to be done. It does not wait until that work is complete.
  void SynchronizeInstalledApps(
      std::vector<ExternalInstallOptions> desired_apps_install_options,
      ExternalInstallSource install_source,
      SynchronizeCallback callback);

  void SetRegistrationCallbackForTesting(RegistrationCallback callback);
  void ClearRegistrationCallbackForTesting();
  void SetRegistrationsCompleteCallbackForTesting(base::OnceClosure callback);
  void ClearSynchronizeRequestsForTesting();

  void Shutdown();

  // TODO(http://b/283521737): Remove this and use WebContentsManager.
  void SetUrlLoaderForTesting(
      std::unique_ptr<webapps::WebAppUrlLoader> url_loader);
  // TODO(http://b/283521737): Remove this and use WebContentsManager.
  void SetDataRetrieverFactoryForTesting(
      base::RepeatingCallback<std::unique_ptr<WebAppDataRetriever>()> factory);

 protected:
  virtual void ReleaseWebContents();

  virtual std::unique_ptr<ExternallyManagedAppRegistrationTaskBase>
  CreateRegistration(GURL install_url,
                     const base::TimeDelta registration_timeout);

  virtual void OnRegistrationFinished(const GURL& launch_url,
                                      RegistrationResultCode result);

  Profile* profile() { return profile_; }

  raw_ptr<WebAppProvider> provider_ = nullptr;

 private:
  struct ExternalInstallMetadata;

  struct SynchronizeRequest {
    SynchronizeRequest(SynchronizeCallback callback,
                       std::vector<ExternalInstallOptions> pending_installs,
                       int remaining_uninstall_requests);
    SynchronizeRequest(const SynchronizeRequest&) = delete;
    SynchronizeRequest& operator=(const SynchronizeRequest&) = delete;
    ~SynchronizeRequest();

    SynchronizeRequest& operator=(SynchronizeRequest&&);
    SynchronizeRequest(SynchronizeRequest&& other);

    SynchronizeCallback callback;
    int remaining_install_requests;
    std::vector<ExternalInstallOptions> pending_installs;
    int remaining_uninstall_requests;
    std::map<GURL, InstallResult> install_results;
    std::map<GURL, webapps::UninstallResultCode> uninstall_results;
  };

  // Adds a task to the queue of operations for each ExternalInstallOptions in
  // |install_options_list|. Runs |callback| with the URL of the corresponding
  // ExternalInstallOptions in |install_options_list| and with the id of the
  // installed app or an empty string if the installation fails. Runs |callback|
  // for every completed installation - whether or not the installation actually
  // succeeded.
  void InstallApps(std::vector<ExternalInstallOptions> install_options_list,
                   const RepeatingInstallCallback& callback);

  // Adds a task to the queue of operations for each GURL in
  // |uninstall_urls|. Runs |callback| with the URL of the corresponding
  // app in |uninstall_urls| and with a bool indicating whether or not the
  // uninstall succeeded. Runs |callback| for every completed uninstallation -
  // whether or not the uninstallation actually succeeded.
  void UninstallApps(std::vector<GURL> uninstall_urls,
                     ExternalInstallSource install_source,
                     const UninstallCallback& callback);

  void SynchronizeInstalledAppsOnLockAcquired(
      std::vector<ExternalInstallOptions> desired_apps_install_options,
      ExternalInstallSource install_source,
      SynchronizeCallback callback,
      AllAppsLock& lock,
      base::Value::Dict& debug_value);

  void InstallForSynchronizeCallback(
      ExternalInstallSource source,
      const GURL& install_url,
      ExternallyManagedAppManager::InstallResult result);
  void UninstallForSynchronizeCallback(ExternalInstallSource source,
                                       const GURL& install_url,
                                       webapps::UninstallResultCode code);
  void ContinueSynchronization(ExternalInstallSource source);
  void CompleteSynchronization(ExternalInstallSource source);

  void PostMaybeStartNext();

  void MaybeStartNext();
  void MaybeStartNextOnLockAcquired(AllAppsLock& lock,
                                    base::Value::Dict& debug_value);

  void StartInstallationTask(
      std::unique_ptr<ExternalInstallMetadata> external_install_metadata,
      std::optional<webapps::AppId> installed_placeholder_app_id);

  bool RunNextRegistration();

  void CreateWebContentsIfNecessary();

  void OnInstalled(ExternallyManagedAppManager::InstallResult result);

  void MaybeEnqueueServiceWorkerRegistration(
      const ExternalInstallOptions& install_options);

  bool IsShuttingDown();

  base::OnceClosure registrations_complete_callback_;

  const raw_ptr<Profile> profile_;

  bool is_in_shutdown_ = false;

  base::flat_map<ExternalInstallSource, SynchronizeRequest>
      synchronize_requests_;

  // unique_ptr so that it can be replaced in tests.
  std::unique_ptr<webapps::WebAppUrlLoader> url_loader_;
  // Allows tests to set the data retriever for install tasks.
  base::RepeatingCallback<std::unique_ptr<WebAppDataRetriever>()>
      data_retriever_factory_;

  std::unique_ptr<content::WebContents> web_contents_;

  std::unique_ptr<ExternalInstallMetadata> current_install_metadata_;

  base::circular_deque<std::unique_ptr<ExternalInstallMetadata>>
      pending_installs_metadata_;

  std::unique_ptr<ExternallyManagedAppRegistrationTaskBase>
      current_registration_;

  using UrlAndTimeout = std::tuple<GURL, const base::TimeDelta>;
  base::circular_deque<UrlAndTimeout> pending_registrations_;

  RegistrationCallback registration_callback_;

  base::WeakPtrFactory<ExternallyManagedAppManager> weak_ptr_factory_{this};
};

// For logging and testing purposes.
std::ostream& operator<<(
    std::ostream& out,
    const ExternallyManagedAppManager::InstallResult& install_result);

}  // namespace web_app

#endif  // CHROME_BROWSER_WEB_APPLICATIONS_EXTERNALLY_MANAGED_APP_MANAGER_H_