1 // Copyright (c) 2011 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 #pragma once 8 9 #include "base/file_path.h" 10 #include "base/gtest_prod_util.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/shared_memory.h" 13 #include "chrome/common/extensions/user_script.h" 14 #include "content/browser/browser_thread.h" 15 #include "content/common/notification_observer.h" 16 #include "content/common/notification_registrar.h" 17 18 namespace base { 19 class StringPiece; 20 } 21 22 class Profile; 23 24 // Manages a segment of shared memory that contains the user scripts the user 25 // has installed. Lives on the UI thread. 26 class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>, 27 public NotificationObserver { 28 public: 29 // For testability, the constructor takes the path the scripts live in. 30 // This is normally a directory inside the profile. 31 explicit UserScriptMaster(const FilePath& script_dir, Profile* profile); 32 33 // Kicks off a process on the file thread to reload scripts from disk 34 // into a new chunk of shared memory and notify renderers. 35 virtual void StartScan(); 36 37 // Gets the segment of shared memory for the scripts. 38 base::SharedMemory* GetSharedMemory() const { 39 return shared_memory_.get(); 40 } 41 42 // Called by the script reloader when new scripts have been loaded. 43 void NewScriptsAvailable(base::SharedMemory* handle); 44 45 // Return true if we have any scripts ready. 46 bool ScriptsReady() const { return shared_memory_.get() != NULL; } 47 48 // Returns the path to the directory user scripts are stored in. 49 FilePath user_script_dir() const { return user_script_dir_; } 50 51 protected: 52 friend class base::RefCountedThreadSafe<UserScriptMaster>; 53 54 virtual ~UserScriptMaster(); 55 56 private: 57 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse1); 58 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse2); 59 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse3); 60 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse4); 61 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse5); 62 FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, Parse6); 63 64 public: 65 // We reload user scripts on the file thread to prevent blocking the UI. 66 // ScriptReloader lives on the file thread and does the reload 67 // work, and then sends a message back to its master with a new SharedMemory*. 68 // ScriptReloader is the worker that manages running the script scan 69 // on the file thread. It must be created on, and its public API must only be 70 // called from, the master's thread. 71 class ScriptReloader 72 : public base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader> { 73 public: 74 // Parses the includes out of |script| and returns them in |includes|. 75 static bool ParseMetadataHeader(const base::StringPiece& script_text, 76 UserScript* script); 77 78 static void LoadScriptsFromDirectory(const FilePath& script_dir, 79 UserScriptList* result); 80 81 explicit ScriptReloader(UserScriptMaster* master); 82 83 // Start a scan for scripts. 84 // Will always send a message to the master upon completion. 85 void StartScan(const FilePath& script_dir, 86 const UserScriptList& external_scripts); 87 88 // The master is going away; don't call it back. 89 void DisownMaster() { 90 master_ = NULL; 91 } 92 93 private: 94 friend class base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader>; 95 96 ~ScriptReloader() {} 97 98 // Where functions are run: 99 // master file 100 // StartScan -> RunScan 101 // LoadScriptsFromDirectory() 102 // LoadLoneScripts() 103 // NotifyMaster <- RunScan 104 105 // Runs on the master thread. 106 // Notify the master that new scripts are available. 107 void NotifyMaster(base::SharedMemory* memory); 108 109 // Runs on the File thread. 110 // Scan the specified directory and lone scripts, calling NotifyMaster when 111 // done. The parameters are intentionally passed by value so their lifetimes 112 // aren't tied to the caller. 113 void RunScan(const FilePath script_dir, UserScriptList lone_scripts); 114 115 // A pointer back to our master. 116 // May be NULL if DisownMaster() is called. 117 UserScriptMaster* master_; 118 119 // The message loop to call our master back on. 120 // Expected to always outlive us. 121 BrowserThread::ID master_thread_id_; 122 123 DISALLOW_COPY_AND_ASSIGN(ScriptReloader); 124 }; 125 126 private: 127 // NotificationObserver implementation. 128 virtual void Observe(NotificationType type, 129 const NotificationSource& source, 130 const NotificationDetails& details); 131 132 // Manages our notification registrations. 133 NotificationRegistrar registrar_; 134 135 // The directories containing user scripts. 136 FilePath user_script_dir_; 137 138 // We hang on to our pointer to know if we've already got one running. 139 scoped_refptr<ScriptReloader> script_reloader_; 140 141 // Contains the scripts that were found the last time scripts were updated. 142 scoped_ptr<base::SharedMemory> shared_memory_; 143 144 // List of scripts outside of script directories we should also load. 145 UserScriptList lone_scripts_; 146 147 // If the extensions service has finished loading its initial set of 148 // extensions. 149 bool extensions_service_ready_; 150 151 // If the script directory is modified while we're rescanning it, we note 152 // that we're currently mid-scan and then start over again once the scan 153 // finishes. This boolean tracks whether another scan is pending. 154 bool pending_scan_; 155 156 // The profile for which the scripts managed here are installed. 157 Profile* profile_; 158 159 DISALLOW_COPY_AND_ASSIGN(UserScriptMaster); 160 }; 161 162 #endif // CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_ 163