910e62b5创建于 1月15日历史提交
// Copyright 2013 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_CACHE_DELEGATE_H__
#define EXTENSIONS_BROWSER_API_DECLARATIVE_RULES_CACHE_DELEGATE_H__

#include <memory>
#include <set>
#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/values.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/extension_id.h"

namespace content {
class BrowserContext;
}

namespace extensions {

class ExtensionRegistry;
class RulesRegistry;

// RulesCacheDelegate implements the part of the RulesRegistry which works on
// the UI thread. It should only be used on the UI thread.
// If `log_storage_init_delay` is set, the delay caused by loading and
// registering rules on initialization will be logged with UMA.
class RulesCacheDelegate {
 public:
  class Observer {
   public:
    // Called when `UpdateRules` is called on the `RulesCacheDelegate`.
    virtual void OnUpdateRules() = 0;

   protected:
    virtual ~Observer() {}
  };

  // Determines the type of a cache, indicating whether or not its rules are
  // persisted to storage.
  enum class Type {
    // An ephemeral RulesCacheDelegate never persists to storage when
    // |UpdateRules()| is called. It merely tracks rule state on the UI thread.
    kEphemeral,

    // Persistent RulesCacheDelegate writes the new rule set into storage every
    // time |UpdateRules()| is called, in addition to tracking rule state on the
    // UI thread.
    kPersistent,
  };

  explicit RulesCacheDelegate(Type type);

  virtual ~RulesCacheDelegate();

  Type type() const { return type_; }

  // Returns a key for the state store. The associated preference is a boolean
  // indicating whether there are some declarative rules stored in the rule
  // store.
  static std::string GetRulesStoredKey(const std::string& event_name,
                                       bool incognito);

  // Initialize the storage functionality.
  void Init(RulesRegistry* registry);

  void UpdateRules(const ExtensionId& extension_id, base::Value::List value);

  // Indicates whether or not this registry has any registered rules cached.
  bool HasRules() const;

  // Adds or removes an observer.
  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  base::WeakPtr<RulesCacheDelegate> GetWeakPtr() {
    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    return weak_ptr_factory_.GetWeakPtr();
  }

 private:
  FRIEND_TEST_ALL_PREFIXES(RulesRegistryWithCacheTest,
                           DeclarativeRulesStored);
  FRIEND_TEST_ALL_PREFIXES(RulesRegistryWithCacheTest,
                           RulesStoredFlagMultipleRegistries);

  const Type type_;

  static const char kRulesStoredKey[];

  // Check if we are done reading all data from storage on startup, and notify
  // the RulesRegistry on its thread if so. The notification is delivered
  // exactly once.
  void CheckIfReady();

  // Schedules retrieving rules for already loaded extensions where
  // appropriate.
  void ReadRulesForInstalledExtensions();

  // Read/write a list of rules serialized to Values.
  void ReadFromStorage(const ExtensionId& extension_id);
  void ReadFromStorageCallback(const ExtensionId& extension_id,
                               std::optional<base::Value> value);

  // Check the preferences whether the extension with `extension_id` has some
  // rules stored on disk. If this information is not in the preferences, true
  // is returned as a safe default value.
  bool GetDeclarativeRulesStored(const ExtensionId& extension_id) const;
  // Modify the preference to `rules_stored`.
  void SetDeclarativeRulesStored(const ExtensionId& extension_id,
                                 bool rules_stored);

  raw_ptr<content::BrowserContext> browser_context_;

  // Indicates whether the ruleset is non-empty. Valid for both `kEphemeral` and
  // `kPersistent` cache types.
  bool has_nonempty_ruleset_ = false;

  // The key under which rules are stored. Only used for `kPersistent` caches.
  std::string storage_key_;

  // The key under which we store whether the rules have been stored. Only used
  // for `kPersistent` caches.
  std::string rules_stored_key_;

  // A set of extension IDs that have rules we are reading from storage.
  std::set<std::string> waiting_for_extensions_;

  // Weak pointer to post tasks to the owning rules registry.
  base::WeakPtr<RulesRegistry> registry_;

  // The thread `registry_` lives on.
  content::BrowserThread::ID rules_registry_thread_;

  // We notified the RulesRegistry that the rules are loaded.
  bool notified_registry_;

  base::ObserverList<Observer>::Unchecked observers_;

  raw_ptr<const ExtensionRegistry> extension_registry_ = nullptr;

  // Use this factory to generate weak pointers bound to the UI thread.
  base::WeakPtrFactory<RulesCacheDelegate> weak_ptr_factory_{this};
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_API_DECLARATIVE_RULES_CACHE_DELEGATE_H__