1 // Copyright (c) 2012 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 5 #ifndef CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_ 7 8 #include <map> 9 #include <string> 10 11 #include "base/compiler_specific.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/scoped_observer.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/notification_observer.h" 16 #include "content/public/browser/notification_registrar.h" 17 #include "extensions/browser/extension_registry_observer.h" 18 #include "extensions/common/extension_messages.h" 19 #include "extensions/common/extension_set.h" 20 #include "extensions/common/user_script.h" 21 22 namespace content { 23 class RenderProcessHost; 24 } 25 26 class Profile; 27 28 namespace extensions { 29 30 class ContentVerifier; 31 class ExtensionRegistry; 32 33 typedef std::map<std::string, ExtensionSet::ExtensionPathAndDefaultLocale> 34 ExtensionsInfo; 35 36 // Manages a segment of shared memory that contains the user scripts the user 37 // has installed. Lives on the UI thread. 38 class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>, 39 public content::NotificationObserver, 40 public ExtensionRegistryObserver { 41 public: 42 explicit UserScriptMaster(Profile* profile); 43 44 // Kicks off a process on the file thread to reload scripts from disk 45 // into a new chunk of shared memory and notify renderers. 46 virtual void StartLoad(); 47 48 // Gets the segment of shared memory for the scripts. GetSharedMemory()49 base::SharedMemory* GetSharedMemory() const { 50 return shared_memory_.get(); 51 } 52 53 // Called by the script reloader when new scripts have been loaded. 54 void NewScriptsAvailable(scoped_ptr<base::SharedMemory> handle); 55 56 // Return true if we have any scripts ready. ScriptsReady()57 bool ScriptsReady() const { return shared_memory_.get() != NULL; } 58 59 // Returns the content verifier for our browser context. 60 ContentVerifier* content_verifier(); 61 62 protected: 63 friend class base::RefCountedThreadSafe<UserScriptMaster>; 64 65 virtual ~UserScriptMaster(); 66 67 public: 68 // We reload user scripts on the file thread to prevent blocking the UI. 69 // ScriptReloader lives on the file thread and does the reload 70 // work, and then sends a message back to its master with a new SharedMemory*. 71 // ScriptReloader is the worker that manages running the script load 72 // on the file thread. It must be created on, and its public API must only be 73 // called from, the master's thread. 74 class ScriptReloader 75 : public base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader> { 76 public: 77 // Parses the includes out of |script| and returns them in |includes|. 78 static bool ParseMetadataHeader(const base::StringPiece& script_text, 79 UserScript* script); 80 81 explicit ScriptReloader(UserScriptMaster* master); 82 83 // Start loading of scripts. 84 // Will always send a message to the master upon completion. 85 void StartLoad(const UserScriptList& external_scripts, 86 const ExtensionsInfo& extensions_info); 87 88 // The master is going away; don't call it back. DisownMaster()89 void DisownMaster() { 90 master_ = NULL; 91 } 92 93 private: 94 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, SkipBOMAtTheBeginning); 95 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, LeaveBOMNotAtTheBeginning); 96 friend class base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader>; 97 98 ~ScriptReloader(); 99 100 // Where functions are run: 101 // master file 102 // StartLoad -> RunLoad 103 // LoadUserScripts() 104 // NotifyMaster <- RunLoad 105 106 // Runs on the master thread. 107 // Notify the master that new scripts are available. 108 void NotifyMaster(scoped_ptr<base::SharedMemory> memory); 109 110 // Runs on the File thread. 111 // Load the specified user scripts, calling NotifyMaster when done. 112 // |user_scripts| is intentionally passed by value so its lifetime isn't 113 // tied to the caller. 114 void RunLoad(const UserScriptList& user_scripts); 115 116 void LoadUserScripts(UserScriptList* user_scripts); 117 118 // Uses extensions_info_ to build a map of localization messages. 119 // Returns NULL if |extension_id| is invalid. 120 SubstitutionMap* GetLocalizationMessages(const std::string& extension_id); 121 122 // A pointer back to our master. 123 // May be NULL if DisownMaster() is called. 124 UserScriptMaster* master_; 125 126 // Maps extension info needed for localization to an extension ID. 127 ExtensionsInfo extensions_info_; 128 129 // The message loop to call our master back on. 130 // Expected to always outlive us. 131 content::BrowserThread::ID master_thread_id_; 132 133 scoped_refptr<ContentVerifier> verifier_; 134 135 DISALLOW_COPY_AND_ASSIGN(ScriptReloader); 136 }; 137 138 private: 139 // content::NotificationObserver implementation. 140 virtual void Observe(int type, 141 const content::NotificationSource& source, 142 const content::NotificationDetails& details) OVERRIDE; 143 144 // ExtensionRegistryObserver implementation. 145 virtual void OnExtensionLoaded(content::BrowserContext* browser_context, 146 const Extension* extension) OVERRIDE; 147 virtual void OnExtensionUnloaded( 148 content::BrowserContext* browser_context, 149 const Extension* extension, 150 UnloadedExtensionInfo::Reason reason) OVERRIDE; 151 152 // Sends the renderer process a new set of user scripts. If 153 // |changed_extensions| is not empty, this signals that only the scripts from 154 // those extensions should be updated. Otherwise, all extensions will be 155 // updated. 156 void SendUpdate(content::RenderProcessHost* process, 157 base::SharedMemory* shared_memory, 158 const std::set<std::string>& changed_extensions); 159 160 // Manages our notification registrations. 161 content::NotificationRegistrar registrar_; 162 163 // We hang on to our pointer to know if we've already got one running. 164 scoped_refptr<ScriptReloader> script_reloader_; 165 166 // Contains the scripts that were found the last time scripts were updated. 167 scoped_ptr<base::SharedMemory> shared_memory_; 168 169 // List of scripts from currently-installed extensions we should load. 170 UserScriptList user_scripts_; 171 172 // Maps extension info needed for localization to an extension ID. 173 ExtensionsInfo extensions_info_; 174 175 // The IDs of the extensions which have changed since the last update sent to 176 // the renderer. 177 std::set<std::string> changed_extensions_; 178 179 // If the extensions service has finished loading its initial set of 180 // extensions. 181 bool extensions_service_ready_; 182 183 // If list of user scripts is modified while we're loading it, we note 184 // that we're currently mid-load and then start over again once the load 185 // finishes. This boolean tracks whether another load is pending. 186 bool pending_load_; 187 188 // The profile for which the scripts managed here are installed. 189 Profile* profile_; 190 191 // Listen to extension load, unloaded notifications. 192 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 193 extension_registry_observer_; 194 195 DISALLOW_COPY_AND_ASSIGN(UserScriptMaster); 196 }; 197 198 } // namespace extensions 199 200 #endif // CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_ 201