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
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_RULES_REGISTRY_H__
#define EXTENSIONS_BROWSER_API_DECLARATIVE_RULES_REGISTRY_H__
#include <stddef.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/one_shot_event.h"
#include "base/time/time.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/api/events.h"
#include "extensions/common/extension_id.h"
namespace content {
class BrowserContext;
}
namespace base {
class Value;
} // namespace base
namespace extensions {
class Extension;
class RulesCacheDelegate;
// A base class for RulesRegistries that takes care of storing the
// api::events::Rule objects. It contains all the methods that need to run
// on the registry thread; methods that need to run on the UI thread are
// separated in the RulesCacheDelegate object.
class RulesRegistry : public base::RefCountedThreadSafe<RulesRegistry> {
public:
enum Defaults { DEFAULT_PRIORITY = 100 };
// After the RulesCacheDelegate object (the part of the registry which runs on
// the UI thread) is created, a pointer to it is passed to |*ui_part|.
// In tests, `browser_context` and `ui_part` can be NULL (at the same time).
// In that case the storage functionality disabled (no RulesCacheDelegate
// object created).
RulesRegistry(content::BrowserContext* browser_context,
const std::string& event_name,
RulesCacheDelegate* cache_delegate,
int id);
RulesRegistry(const RulesRegistry&) = delete;
RulesRegistry& operator=(const RulesRegistry&) = delete;
const base::OneShotEvent& ready() const { return ready_; }
// RulesRegistry implementation:
// Registers `rules` in this RulesRegistry. If a concrete RuleRegistry does
// not support some of the rules, it may ignore them.
//
// `rules` is a list of Rule instances following the definition of the
// declarative extension APIs. It is guaranteed that each rule in `rules` has
// a unique name within the scope of `extension_id` that has not been
// registered before, unless it has been removed again.
//
// Returns an empty string if the function is successful or an error message
// otherwise. If the function is successful, and if the `rules_out` parameter
// is non-null, pointers to the added rules are returned.
//
// IMPORTANT: This function is atomic. Either all rules that are deemed
// relevant are added or none.
std::string AddRules(
const ExtensionId& extension_id,
std::vector<api::events::Rule> rules_in,
std::vector<const api::events::Rule*>* rules_out = nullptr);
// Unregisters all rules listed in `rule_identifiers` and owned by
// `extension_id` from this RulesRegistry.
// Some or all IDs in `rule_identifiers` may not be stored in this
// RulesRegistry and are ignored.
//
// Returns an empty string if the function is successful or an error
// message otherwise.
//
// IMPORTANT: This function is atomic. Either all rules that are deemed
// relevant are removed or none.
std::string RemoveRules(const ExtensionId& extension_id,
const std::vector<std::string>& rule_identifiers);
// Same as RemoveAllRules but acts on all rules owned by `extension_id`.
std::string RemoveAllRules(const ExtensionId& extension_id);
// Returns all rules listed in `rule_identifiers` and owned by `extension_id`
// registered in this RuleRegistry. Entries in `rule_identifiers` that
// are unknown are ignored.
//
// The returned rules are stored in `out`.
void GetRules(const ExtensionId& extension_id,
const std::vector<std::string>& rule_identifiers,
std::vector<const api::events::Rule*>* out);
// Same as GetRules but returns all rules owned by `extension_id`.
void GetAllRules(const ExtensionId& extension_id,
std::vector<const api::events::Rule*>* out);
// Called to notify the RulesRegistry that the registry service is being
// shut down.
void OnShutdown();
// Called to notify the RulesRegistry that the extension availability has
// changed, so that the registry can update which rules are active.
void OnExtensionUnloaded(const Extension* extension);
void OnExtensionUninstalled(const Extension* extension);
void OnExtensionLoaded(const Extension* extension);
// Returns the number of entries in used_rule_identifiers_ for leak detection.
// Every ExtensionId counts as one entry, even if it contains no rules.
size_t GetNumberOfUsedRuleIdentifiersForTesting() const;
// Returns the RulesCacheDelegate. This is used for testing.
RulesCacheDelegate* rules_cache_delegate_for_testing() const {
return cache_delegate_.get();
}
// Returns the context where the rules registry lives.
content::BrowserContext* browser_context() const { return browser_context_; }
// The name of the event with which rules are registered.
const std::string& event_name() const { return event_name_; }
// The unique identifier for this RulesRegistry object.
int id() const { return id_; }
protected:
virtual ~RulesRegistry();
// These functions need to apply the rules to the browser, while the base
// class will handle defaulting empty fields before calling *Impl, and will
// automatically cache the rules and re-call *Impl on browser startup.
virtual std::string AddRulesImpl(
const ExtensionId& extension_id,
const std::vector<const api::events::Rule*>& rules) = 0;
virtual std::string RemoveRulesImpl(
const ExtensionId& extension_id,
const std::vector<std::string>& rule_identifiers) = 0;
virtual std::string RemoveAllRulesImpl(const ExtensionId& extension_id) = 0;
private:
friend class base::RefCountedThreadSafe<RulesRegistry>;
friend class RulesCacheDelegate;
using RuleId = std::string;
using RulesDictionaryKey = std::pair<ExtensionId, RuleId>;
// NOTE: The property of stability of iterators of a map during insertion is
// relied upon here. If this type needs to change, beware that this will
// severely complicate returning valid pointers to callers of member functions
// of this class.
using RulesDictionary = std::map<RulesDictionaryKey, api::events::Rule>;
enum ProcessChangedRulesState {
// ProcessChangedRules can never be called, `cache_delegate_` is NULL.
NEVER_PROCESS,
// A task to call ProcessChangedRules is scheduled for future execution.
SCHEDULED_FOR_PROCESSING,
// No task to call ProcessChangedRules is scheduled yet, but it is possible
// to schedule one.
NOT_SCHEDULED_FOR_PROCESSING
};
using ProcessStateMap = std::map<ExtensionId, ProcessChangedRulesState>;
base::WeakPtr<RulesRegistry> GetWeakPtr() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return weak_ptr_factory_.GetWeakPtr();
}
// Internal implementation of the AddRules interface which adds the rules to
// the `destination` RulesDictionary. If the function is successful, and if
// the `rules_out` parameter is non-null, pointers to the added rules are
// returned.
std::string AddRulesInternal(
const ExtensionId& extension_id,
std::vector<api::events::Rule> rules_in,
RulesDictionary* destination,
std::vector<const api::events::Rule*>* rules_out);
// The precondition for calling this method is that all rules have unique IDs.
// AddRules establishes this precondition and calls into this method.
// Stored rules already meet this precondition and so they avoid calling
// CheckAndFillInOptionalRules for improved performance.
//
// Returns an empty string if the function is successful or an error
// message otherwise. If the function is successful, and if the
// `rules_out` parameter is non-null, pointers to the added rules are
// returned.
std::string AddRulesNoFill(const ExtensionId& extension_id,
std::vector<api::events::Rule> rules_in,
RulesDictionary* destination,
std::vector<const api::events::Rule*>* rules_out);
// Same as GetRules but returns all rules owned by `extension_id` for a given
// `rules` dictionary.
void GetRules(const ExtensionId& extension_id,
RulesDictionary* rules,
std::vector<const api::events::Rule*>* out);
// Common processing after extension's rules have changed.
void ProcessChangedRules(const ExtensionId& extension_id);
// Calls ProcessChangedRules if
// |process_changed_rules_requested_(extension_id)| ==
// NOT_SCHEDULED_FOR_PROCESSING.
void MaybeProcessChangedRules(const ExtensionId& extension_id);
// This method implements the functionality of RemoveAllRules, except for not
// calling MaybeProcessChangedRules. That way updating the rules store and
// extension prefs is avoided. This method is called when an extension is
// uninstalled, that way there is no clash with the preferences being wiped.
// Set `remove_manifest_rules` to true if `manifest_rules_` should be cleared
// along with `rules_`.
std::string RemoveAllRulesNoStoreUpdate(const ExtensionId& extension_id,
bool remove_manifest_rules);
void MarkReady();
// Deserialize the rules from the given Value object and add them to the
// RulesRegistry.
void DeserializeAndAddRules(const ExtensionId& extension_id,
std::optional<base::Value> rules);
// Reports an internal error with the specified params to the extensions
// client.
void ReportInternalError(const ExtensionId& extension_id,
const std::string& error);
// The context to which this rules registry belongs.
raw_ptr<content::BrowserContext> browser_context_;
// The name of the event with which rules are registered.
const std::string event_name_;
// The key that identifies the context in which these rules apply.
int id_;
RulesDictionary rules_;
RulesDictionary manifest_rules_;
// Signaled when we have finished reading from storage for all extensions that
// are loaded on startup.
base::OneShotEvent ready_;
ProcessStateMap process_changed_rules_requested_;
// Returns whether any existing rule is registered with identifier `rule_id`
// for extension `extension_id`.
bool IsUniqueId(const ExtensionId& extension_id,
const std::string& rule_id) const;
// Creates an ID that is unique within the scope of`extension_id`.
std::string GenerateUniqueId(const ExtensionId& extension_id);
// Verifies that all `rules` have unique IDs or initializes them with
// unique IDs if they don't have one. In case of duplicate IDs, this function
// returns a non-empty error message.
std::string CheckAndFillInOptionalRules(
const ExtensionId& extension_id,
std::vector<api::events::Rule>* rules);
// Initializes the priority fields in case they have not been set.
void FillInOptionalPriorities(std::vector<api::events::Rule>* rules);
// Removes all `identifiers` of `extension_id` from `used_rule_identifiers_`.
void RemoveUsedRuleIdentifiers(const ExtensionId& extension_id,
const std::vector<std::string>& identifiers);
// Same as RemoveUsedRuleIdentifiers but operates on all rules of
// `extension_id`.
void RemoveAllUsedRuleIdentifiers(const ExtensionId& extension_id);
using RuleIdentifier = std::string;
std::map<ExtensionId, std::set<RuleIdentifier>> used_rule_identifiers_;
int last_generated_rule_identifier_id_;
// `cache_delegate_` is owned by the registry service. If `cache_delegate_` is
// NULL, then the storage functionality is disabled (this is used in tests).
// This registry cannot own `cache_delegate_` because during the time after
// rules registry service shuts down on UI thread, and the registry is
// destroyed on its thread, the use of the `cache_delegate_` would not be
// safe. The registry only ever associates with one RulesCacheDelegate
// instance.
base::WeakPtr<RulesCacheDelegate> cache_delegate_;
base::WeakPtrFactory<RulesRegistry> weak_ptr_factory_{this};
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_RULES_REGISTRY_H__
|