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