// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_ #define EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_ #include #include #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/scoped_observer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "extensions/common/host_id.h" #include "extensions/common/user_script.h" namespace base { class SharedMemory; } namespace content { class BrowserContext; class RenderProcessHost; } namespace extensions { // Manages one "logical unit" of user scripts in shared memory by constructing a // new shared memory region when the set of scripts changes. Also notifies // renderers of new shared memory region when new renderers appear, or when // script reloading completes. Script loading lives on the UI thread. Instances // of this class are embedded within classes with names ending in // UserScriptMaster. These "master" classes implement the strategy for which // scripts to load/unload on this logical unit of scripts. class UserScriptLoader : public content::NotificationObserver { public: using LoadScriptsCallback = base::Callback, scoped_ptr)>; class Observer { public: virtual void OnScriptsLoaded(UserScriptLoader* loader) = 0; virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0; }; // Parses the includes out of |script| and returns them in |includes|. static bool ParseMetadataHeader(const base::StringPiece& script_text, UserScript* script); UserScriptLoader(content::BrowserContext* browser_context, const HostID& host_id); ~UserScriptLoader() override; // Add |scripts| to the set of scripts managed by this loader. void AddScripts(const std::set& scripts); // Add |scripts| to the set of scripts managed by this loader. // The fetch of the content of the script starts URL request // to the associated render specified by // |render_process_id, render_view_id|. // TODO(hanxi): The renderer information doesn't really belong in this base // class, but it's not an easy fix. virtual void AddScripts(const std::set& scripts, int render_process_id, int render_view_id); // Remove |scripts| from the set of scripts managed by this loader. void RemoveScripts(const std::set& scripts); // Clears the set of scripts managed by this loader. void ClearScripts(); // Initiates procedure to start loading scripts on the file thread. void StartLoad(); // Returns true if we have any scripts ready. bool scripts_ready() const { return shared_memory_.get() != NULL; } // Pickle user scripts and return pointer to the shared memory. static scoped_ptr Serialize( const extensions::UserScriptList& scripts); // Adds or removes observers. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); protected: // Allows the derived classes have different ways to load user scripts. virtual void LoadScripts(scoped_ptr user_scripts, const std::set& changed_hosts, const std::set& added_script_ids, LoadScriptsCallback callback) = 0; // Sets the flag if the initial set of hosts has finished loading; if it's // set to be true, calls AttempLoad() to bootstrap. void SetReady(bool ready); content::BrowserContext* browser_context() const { return browser_context_; } const HostID& host_id() const { return host_id_; } private: // content::NotificationObserver implementation. void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) override; // Returns whether or not it is possible that calls to AddScripts(), // RemoveScripts(), and/or ClearScripts() have caused any real change in the // set of scripts to be loaded. bool ScriptsMayHaveChanged() const; // Attempts to initiate a load. void AttemptLoad(); // Called once we have finished loading the scripts on the file thread. void OnScriptsLoaded(scoped_ptr user_scripts, scoped_ptr shared_memory); // Sends the renderer process a new set of user scripts. If // |changed_hosts| is not empty, this signals that only the scripts from // those hosts should be updated. Otherwise, all hosts will be // updated. void SendUpdate(content::RenderProcessHost* process, base::SharedMemory* shared_memory, const std::set& changed_hosts); bool is_loading() const { // Ownership of |user_scripts_| is passed to the file thread when loading. return user_scripts_.get() == NULL; } // Manages our notification registrations. content::NotificationRegistrar registrar_; // Contains the scripts that were found the last time scripts were updated. scoped_ptr shared_memory_; // List of scripts from currently-installed extensions we should load. scoped_ptr user_scripts_; // The mutually-exclusive sets of scripts that were added or removed since the // last script load. std::set added_scripts_; std::set removed_scripts_; // Indicates whether the the collection of scripts should be cleared before // additions and removals on the next script load. bool clear_scripts_; // The IDs of the extensions which changed in the last update sent to the // renderer. std::set changed_hosts_; // If the initial set of hosts has finished loading. bool ready_; // If list of user scripts is modified while we're loading it, we note // that we're currently mid-load and then start over again once the load // finishes. This boolean tracks whether another load is pending. bool pending_load_; // The browser_context for which the scripts managed here are installed. content::BrowserContext* browser_context_; // ID of the host that owns these scripts, if any. This is only set to a // non-empty value for declarative user script shared memory regions. HostID host_id_; // The associated observers. base::ObserverList observers_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(UserScriptLoader); }; } // namespace extensions #endif // EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_