• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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