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_
|