[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
hanxi | 3b2b3df | 2015-02-24 15:28:07 | [diff] [blame] | 5 | #ifndef EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_ |
| 6 | #define EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_ |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 7 | |
| 8 | #include <map> |
| 9 | #include <set> |
| 10 | |
| 11 | #include "base/compiler_specific.h" |
| 12 | #include "base/memory/scoped_ptr.h" |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 13 | #include "base/memory/shared_memory.h" |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 14 | #include "base/memory/weak_ptr.h" |
hanxi | 9bd85fa | 2015-05-05 19:55:00 | [diff] [blame] | 15 | #include "base/observer_list.h" |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 16 | #include "base/scoped_observer.h" |
| 17 | #include "content/public/browser/notification_observer.h" |
| 18 | #include "content/public/browser/notification_registrar.h" |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 19 | #include "extensions/common/host_id.h" |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 20 | #include "extensions/common/user_script.h" |
| 21 | |
| 22 | namespace base { |
| 23 | class SharedMemory; |
| 24 | } |
| 25 | |
| 26 | namespace content { |
| 27 | class BrowserContext; |
| 28 | class RenderProcessHost; |
| 29 | } |
| 30 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 31 | namespace extensions { |
| 32 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 33 | // Manages one "logical unit" of user scripts in shared memory by constructing a |
| 34 | // new shared memory region when the set of scripts changes. Also notifies |
| 35 | // renderers of new shared memory region when new renderers appear, or when |
| 36 | // script reloading completes. Script loading lives on the UI thread. Instances |
| 37 | // of this class are embedded within classes with names ending in |
| 38 | // UserScriptMaster. These "master" classes implement the strategy for which |
| 39 | // scripts to load/unload on this logical unit of scripts. |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 40 | class UserScriptLoader : public content::NotificationObserver { |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 41 | public: |
hanxi | feb6a64f | 2015-04-24 19:21:40 | [diff] [blame] | 42 | using LoadScriptsCallback = |
| 43 | base::Callback<void(scoped_ptr<UserScriptList>, |
| 44 | scoped_ptr<base::SharedMemory>)>; |
hanxi | 9bd85fa | 2015-05-05 19:55:00 | [diff] [blame] | 45 | class Observer { |
| 46 | public: |
| 47 | virtual void OnScriptsLoaded(UserScriptLoader* loader) = 0; |
| 48 | virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0; |
| 49 | }; |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 50 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 51 | // Parses the includes out of |script| and returns them in |includes|. |
| 52 | static bool ParseMetadataHeader(const base::StringPiece& script_text, |
| 53 | UserScript* script); |
| 54 | |
hanxi | 3b2b3df | 2015-02-24 15:28:07 | [diff] [blame] | 55 | UserScriptLoader(content::BrowserContext* browser_context, |
hanxi | feb6a64f | 2015-04-24 19:21:40 | [diff] [blame] | 56 | const HostID& host_id); |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 57 | ~UserScriptLoader() override; |
| 58 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 59 | // Add |scripts| to the set of scripts managed by this loader. |
| 60 | void AddScripts(const std::set<UserScript>& scripts); |
| 61 | |
hanxi | feb6a64f | 2015-04-24 19:21:40 | [diff] [blame] | 62 | // Add |scripts| to the set of scripts managed by this loader. |
| 63 | // The fetch of the content of the script starts URL request |
| 64 | // to the associated render specified by |
| 65 | // |render_process_id, render_view_id|. |
| 66 | // TODO(hanxi): The renderer information doesn't really belong in this base |
| 67 | // class, but it's not an easy fix. |
| 68 | virtual void AddScripts(const std::set<UserScript>& scripts, |
| 69 | int render_process_id, |
| 70 | int render_view_id); |
| 71 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 72 | // Remove |scripts| from the set of scripts managed by this loader. |
| 73 | void RemoveScripts(const std::set<UserScript>& scripts); |
| 74 | |
| 75 | // Clears the set of scripts managed by this loader. |
| 76 | void ClearScripts(); |
| 77 | |
| 78 | // Initiates procedure to start loading scripts on the file thread. |
| 79 | void StartLoad(); |
| 80 | |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 81 | // Returns true if we have any scripts ready. |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 82 | bool scripts_ready() const { return shared_memory_.get() != NULL; } |
| 83 | |
hanxi | feb6a64f | 2015-04-24 19:21:40 | [diff] [blame] | 84 | // Pickle user scripts and return pointer to the shared memory. |
| 85 | static scoped_ptr<base::SharedMemory> Serialize( |
| 86 | const extensions::UserScriptList& scripts); |
| 87 | |
hanxi | 9bd85fa | 2015-05-05 19:55:00 | [diff] [blame] | 88 | // Adds or removes observers. |
| 89 | void AddObserver(Observer* observer); |
| 90 | void RemoveObserver(Observer* observer); |
| 91 | |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 92 | protected: |
hanxi | feb6a64f | 2015-04-24 19:21:40 | [diff] [blame] | 93 | // Allows the derived classes have different ways to load user scripts. |
| 94 | virtual void LoadScripts(scoped_ptr<UserScriptList> user_scripts, |
| 95 | const std::set<HostID>& changed_hosts, |
| 96 | const std::set<int>& added_script_ids, |
| 97 | LoadScriptsCallback callback) = 0; |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 98 | |
| 99 | // Sets the flag if the initial set of hosts has finished loading; if it's |
| 100 | // set to be true, calls AttempLoad() to bootstrap. |
| 101 | void SetReady(bool ready); |
| 102 | |
hanxi | 3b2b3df | 2015-02-24 15:28:07 | [diff] [blame] | 103 | content::BrowserContext* browser_context() const { return browser_context_; } |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 104 | const HostID& host_id() const { return host_id_; } |
| 105 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 106 | private: |
| 107 | // content::NotificationObserver implementation. |
dcheng | ae36a4a | 2014-10-21 12:36:36 | [diff] [blame] | 108 | void Observe(int type, |
| 109 | const content::NotificationSource& source, |
| 110 | const content::NotificationDetails& details) override; |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 111 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 112 | // Returns whether or not it is possible that calls to AddScripts(), |
| 113 | // RemoveScripts(), and/or ClearScripts() have caused any real change in the |
| 114 | // set of scripts to be loaded. |
| 115 | bool ScriptsMayHaveChanged() const; |
| 116 | |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 117 | // Attempts to initiate a load. |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 118 | void AttemptLoad(); |
| 119 | |
| 120 | // Called once we have finished loading the scripts on the file thread. |
| 121 | void OnScriptsLoaded(scoped_ptr<UserScriptList> user_scripts, |
| 122 | scoped_ptr<base::SharedMemory> shared_memory); |
| 123 | |
| 124 | // Sends the renderer process a new set of user scripts. If |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 125 | // |changed_hosts| is not empty, this signals that only the scripts from |
| 126 | // those hosts should be updated. Otherwise, all hosts will be |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 127 | // updated. |
| 128 | void SendUpdate(content::RenderProcessHost* process, |
| 129 | base::SharedMemory* shared_memory, |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 130 | const std::set<HostID>& changed_hosts); |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 131 | |
| 132 | bool is_loading() const { |
| 133 | // Ownership of |user_scripts_| is passed to the file thread when loading. |
| 134 | return user_scripts_.get() == NULL; |
| 135 | } |
| 136 | |
| 137 | // Manages our notification registrations. |
| 138 | content::NotificationRegistrar registrar_; |
| 139 | |
| 140 | // Contains the scripts that were found the last time scripts were updated. |
| 141 | scoped_ptr<base::SharedMemory> shared_memory_; |
| 142 | |
| 143 | // List of scripts from currently-installed extensions we should load. |
| 144 | scoped_ptr<UserScriptList> user_scripts_; |
| 145 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 146 | // The mutually-exclusive sets of scripts that were added or removed since the |
| 147 | // last script load. |
| 148 | std::set<UserScript> added_scripts_; |
| 149 | std::set<UserScript> removed_scripts_; |
| 150 | |
| 151 | // Indicates whether the the collection of scripts should be cleared before |
| 152 | // additions and removals on the next script load. |
| 153 | bool clear_scripts_; |
| 154 | |
| 155 | // The IDs of the extensions which changed in the last update sent to the |
| 156 | // renderer. |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 157 | std::set<HostID> changed_hosts_; |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 158 | |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 159 | // If the initial set of hosts has finished loading. |
| 160 | bool ready_; |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 161 | |
| 162 | // If list of user scripts is modified while we're loading it, we note |
| 163 | // that we're currently mid-load and then start over again once the load |
| 164 | // finishes. This boolean tracks whether another load is pending. |
| 165 | bool pending_load_; |
| 166 | |
| 167 | // Whether or not we are currently loading. |
| 168 | bool is_loading_; |
| 169 | |
hanxi | 3b2b3df | 2015-02-24 15:28:07 | [diff] [blame] | 170 | // The browser_context for which the scripts managed here are installed. |
| 171 | content::BrowserContext* browser_context_; |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 172 | |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 173 | // ID of the host that owns these scripts, if any. This is only set to a |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 174 | // non-empty value for declarative user script shared memory regions. |
hanxi | c0503d7 | 2015-02-05 14:27:32 | [diff] [blame] | 175 | HostID host_id_; |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 176 | |
hanxi | 9bd85fa | 2015-05-05 19:55:00 | [diff] [blame] | 177 | // The associated observers. |
brettw | 236d317 | 2015-06-03 16:31:43 | [diff] [blame] | 178 | base::ObserverList<Observer> observers_; |
hanxi | 9bd85fa | 2015-05-05 19:55:00 | [diff] [blame] | 179 | |
mohan.reddy | 63d6300 | 2014-09-16 04:13:56 | [diff] [blame] | 180 | base::WeakPtrFactory<UserScriptLoader> weak_factory_; |
| 181 | |
[email protected] | 15ad2ee | 2014-08-15 19:15:26 | [diff] [blame] | 182 | DISALLOW_COPY_AND_ASSIGN(UserScriptLoader); |
| 183 | }; |
| 184 | |
| 185 | } // namespace extensions |
| 186 | |
hanxi | 3b2b3df | 2015-02-24 15:28:07 | [diff] [blame] | 187 | #endif // EXTENSIONS_BROWSER_USER_SCRIPT_LOADER_H_ |