File: force_installed_tracker.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 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 (240 lines) | stat: -rw-r--r-- 9,413 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
// 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_EXTENSIONS_FORCED_EXTENSIONS_FORCE_INSTALLED_TRACKER_H_
#define CHROME_BROWSER_EXTENSIONS_FORCED_EXTENSIONS_FORCE_INSTALLED_TRACKER_H_

#include <map>

#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h"
#include "components/policy/core/common/policy_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/updater/extension_downloader_delegate.h"
#include "extensions/common/extension.h"

class PrefService;
class Profile;

namespace content {
class BrowserContext;
}

namespace extensions {

// Used to track status of force-installed extensions for the profile: are they
// successfully loaded, failed to install, or neither happened yet.
// ExtensionService owns this class and outlives it.
class ForceInstalledTracker : public ExtensionRegistryObserver,
                              public InstallStageTracker::Observer,
                              public policy::PolicyService::Observer {
 public:
  class Observer : public base::CheckedObserver {
   public:
    // Called after every force-installed extension is loaded (not yet
    // installed) or reported as failure.
    //
    // Called exactly once, during startup (may take several minutes). Use
    // IsDoneLoading() to know if it has already been called. If there are no
    // force-installed extensions configured, this method still gets called.
    virtual void OnForceInstalledExtensionsLoaded() {}

    // Same as OnForceInstalledExtensionsLoaded(), but after they're ready
    // instead of loaded.
    //
    // Called exactly once, during startup (may take several minutes). Use
    // IsReady() to know if it has already been called. If there are no
    // force-installed extensions configured, this method still gets called.
    virtual void OnForceInstalledExtensionsReady() {}

    // Called when a force-installed extension with id `extension_id` fails to
    // install with failure reason `reason`.
    //
    // Can be called multiple times, one for each failed extension install.
    virtual void OnForceInstalledExtensionFailed(
        const ExtensionId& extension_id,
        InstallStageTracker::FailureReason reason,
        bool is_from_store) {}

    // Called when cache status is retrieved from InstallationStageTracker.
    virtual void OnExtensionDownloadCacheStatusRetrieved(
        const ExtensionId& id,
        ExtensionDownloaderDelegate::CacheStatus cache_status) {}
  };

  ForceInstalledTracker(ExtensionRegistry* registry, Profile* profile);

  ~ForceInstalledTracker() override;

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

  // Returns true if all extensions loaded/failed loading.
  bool IsDoneLoading() const;

  // Returns true if all extensions installed/failed installing.
  bool IsReady() const;

  // Returns true if all extensions installed/failed installing and there is
  // at least one such extension.
  bool IsComplete() const;

  // Adds observers to this object, to get notified when installation is
  // finished.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // ExtensionRegistryObserver overrides:
  void OnExtensionLoaded(content::BrowserContext* browser_context,
                         const Extension* extension) override;
  void OnExtensionReady(content::BrowserContext* browser_context,
                        const Extension* extension) override;
  void OnShutdown(ExtensionRegistry*) override;

  // InstallStageTracker::Observer overrides:
  void OnExtensionInstallationFailed(
      const ExtensionId& extension_id,
      InstallStageTracker::FailureReason reason) override;
  void OnExtensionDownloadCacheStatusRetrieved(
      const ExtensionId& id,
      ExtensionDownloaderDelegate::CacheStatus cache_status) override;

  // policy::PolicyService::Observer overrides:
  void OnPolicyUpdated(const policy::PolicyNamespace& ns,
                       const policy::PolicyMap& previous,
                       const policy::PolicyMap& current) override;

  void OnPolicyServiceInitialized(policy::PolicyDomain domain) override;

  enum class ExtensionStatus {
    // Extension appears in force-install list, but it not installed yet.
    kPending,

    // Extension was successfully loaded.
    kLoaded,

    // Extension is ready. This happens after loading.
    kReady,

    // Extension installation failure was reported.
    kFailed
  };

  // Helper struct with supplementary info for extensions from force-install
  // list.
  struct ExtensionInfo {
    // Current status of the extension: loaded, failed, or still installing.
    ExtensionStatus status;

    // Additional info: whether extension is from Chrome Web Store, or
    // self-hosted.
    bool is_from_store;
  };

  const std::map<ExtensionId, ExtensionInfo>& extensions() const {
    return extensions_;
  }

  // Returns true only in case of some well-known admin side misconfigurations
  // which are easy to detect. Can return false for misconfigurations which are
  // hard to distinguish with other errors.
  bool IsMisconfiguration(
      const InstallStageTracker::InstallationData& installation_data,
      const ExtensionId& id) const;

  static bool IsExtensionFetchedFromCache(
      const std::optional<ExtensionDownloaderDelegate::CacheStatus>& status);

 private:
  policy::PolicyService* policy_service();

  // Fires OnForceInstallationFinished() on observers, then changes `status_` to
  // kComplete.
  void MaybeNotifyObservers();

  // Increments (or decrements) `load_pending_count_` and
  // `install_pending_count_` by `delta`, depending on `status`.
  void UpdateCounters(ExtensionStatus status, int delta);

  // Modifies `extensions_` and bounded counter by adding extension
  // to the collection.
  void AddExtensionInfo(const ExtensionId& extension_id,
                        ExtensionStatus status,
                        bool is_from_store);

  // Modifies `extensions_` and bounded counter by changing status
  // of one extension.
  void ChangeExtensionStatus(const ExtensionId& extension_id,
                             ExtensionStatus status);

  // Proceeds and returns true if `kInstallForceList` pref is not empty.
  bool ProceedIfForcedExtensionsPrefReady();
  // Loads list of force-installed extensions if available. Only called once.
  void OnForcedExtensionsPrefReady();

  void OnInstallForcelistChanged();

  raw_ptr<const ExtensionManagement> extension_management_;

  // Unowned, but guaranteed to outlive this object.
  raw_ptr<ExtensionRegistry> registry_;
  raw_ptr<Profile> profile_;
  raw_ptr<PrefService> pref_service_;

  // Collection of all extensions we are interested in here. Don't update
  // directly, use AddExtensionInfo/RemoveExtensionInfo/ChangeExtensionStatus
  // methods, as `pending_extension_counter_` has to be in sync with contents of
  // this collection.
  std::map<ExtensionId, ExtensionInfo> extensions_;

  // Number of extensions in `extensions_` with status `PENDING`.
  size_t load_pending_count_ = 0;
  // Number of extensions in `extensions_` with status `PENDING` or `LOADED`.
  // (ie. could be loaded, but not ready yet).
  size_t ready_pending_count_ = 0;

  // Stores the current state of this tracker, to know when it's complete, and
  // to perform sanity DCHECK()s.
  enum Status {
    // Waiting for PolicyService to finish initializing. Listening for
    // OnPolicyServiceInitialized().
    kWaitingForPolicyService,
    // At the startup the `kInstallForceList` preference might be empty, meaning
    // that no extensions are yet specified to be force installed.
    // Waiting for `kInstallForceList` to be populated.
    kWaitingForInstallForcelistPref,
    // Waiting for one or more extensions to finish loading. Listening for
    // `ExtensionRegistryObserver` events.
    kWaitingForExtensionLoads,
    // Waiting for one or more extensions to finish loading. Listening for
    // `ExtensionRegistryObserver` events. Extensions have already finished
    // loading; we're still waiting for the "ready" state. IsDoneLoading()
    // returns true, but IsReady() returns false.
    kWaitingForExtensionReady,
    // All extensions have finished installing (successfully or not); observers
    // have been called exactly once, and IsDoneLoading() and IsReady()
    // both return true.
    kComplete,
  };
  Status status_ = kWaitingForPolicyService;
  bool forced_extensions_pref_ready_ = false;
  PrefChangeRegistrar pref_change_registrar_;

  base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
      registry_observation_{this};
  base::ScopedObservation<InstallStageTracker, InstallStageTracker::Observer>
      collector_observation_{this};

  base::ObserverList<Observer> observers_;
};

}  // namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_FORCED_EXTENSIONS_FORCE_INSTALLED_TRACKER_H_