• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #ifndef CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LOADER_H_
6 #define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LOADER_H_
7 
8 #include <map>
9 #include <set>
10 
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/scoped_observer.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.h"
19 #include "extensions/common/extension_set.h"
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 
31 class Profile;
32 
33 namespace extensions {
34 
35 class ContentVerifier;
36 class ExtensionRegistry;
37 
38 typedef std::map<ExtensionId, ExtensionSet::ExtensionPathAndDefaultLocale>
39     ExtensionsInfo;
40 
41 // Manages one "logical unit" of user scripts in shared memory by constructing a
42 // new shared memory region when the set of scripts changes. Also notifies
43 // renderers of new shared memory region when new renderers appear, or when
44 // script reloading completes. Script loading lives on the UI thread. Instances
45 // of this class are embedded within classes with names ending in
46 // UserScriptMaster. These "master" classes implement the strategy for which
47 // scripts to load/unload on this logical unit of scripts.
48 class UserScriptLoader : public content::NotificationObserver,
49                          public ExtensionRegistryObserver {
50  public:
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 
55   // A wrapper around the method to load user scripts, which is normally run on
56   // the file thread. Exposed only for tests.
57   static void LoadScriptsForTest(UserScriptList* user_scripts);
58 
59   UserScriptLoader(Profile* profile,
60                    const ExtensionId& owner_extension_id,
61                    bool listen_for_extension_system_loaded);
62   virtual ~UserScriptLoader();
63 
64   // Add |scripts| to the set of scripts managed by this loader.
65   void AddScripts(const std::set<UserScript>& scripts);
66 
67   // Remove |scripts| from the set of scripts managed by this loader.
68   void RemoveScripts(const std::set<UserScript>& scripts);
69 
70   // Clears the set of scripts managed by this loader.
71   void ClearScripts();
72 
73   // Initiates procedure to start loading scripts on the file thread.
74   void StartLoad();
75 
76   // Return true if we have any scripts ready.
scripts_ready()77   bool scripts_ready() const { return shared_memory_.get() != NULL; }
78 
79  private:
80   // content::NotificationObserver implementation.
81   virtual void Observe(int type,
82                        const content::NotificationSource& source,
83                        const content::NotificationDetails& details) OVERRIDE;
84 
85   // ExtensionRegistryObserver implementation.
86   virtual void OnExtensionUnloaded(
87       content::BrowserContext* browser_context,
88       const Extension* extension,
89       UnloadedExtensionInfo::Reason reason) OVERRIDE;
90 
91   // Initiates script load when we have been waiting for the extension system
92   // to be ready.
93   void OnExtensionSystemReady();
94 
95   // Returns whether or not it is possible that calls to AddScripts(),
96   // RemoveScripts(), and/or ClearScripts() have caused any real change in the
97   // set of scripts to be loaded.
98   bool ScriptsMayHaveChanged() const;
99 
100   // Attempt to initiate a load.
101   void AttemptLoad();
102 
103   // Called once we have finished loading the scripts on the file thread.
104   void OnScriptsLoaded(scoped_ptr<UserScriptList> user_scripts,
105                        scoped_ptr<base::SharedMemory> shared_memory);
106 
107   // Sends the renderer process a new set of user scripts. If
108   // |changed_extensions| is not empty, this signals that only the scripts from
109   // those extensions should be updated. Otherwise, all extensions will be
110   // updated.
111   void SendUpdate(content::RenderProcessHost* process,
112                   base::SharedMemory* shared_memory,
113                   const std::set<ExtensionId>& changed_extensions);
114 
115   // Add to |changed_extensions_| those extensions referred to by |scripts|.
116   void ExpandChangedExtensions(const std::set<UserScript>& scripts);
117 
118   // Update |extensions_info_| to contain info for each element of
119   // |changed_extensions_|.
120   void UpdateExtensionsInfo();
121 
is_loading()122   bool is_loading() const {
123     // Ownership of |user_scripts_| is passed to the file thread when loading.
124     return user_scripts_.get() == NULL;
125   }
126 
127   // Manages our notification registrations.
128   content::NotificationRegistrar registrar_;
129 
130   // Contains the scripts that were found the last time scripts were updated.
131   scoped_ptr<base::SharedMemory> shared_memory_;
132 
133   // List of scripts from currently-installed extensions we should load.
134   scoped_ptr<UserScriptList> user_scripts_;
135 
136   // Maps extension info needed for localization to an extension ID.
137   ExtensionsInfo extensions_info_;
138 
139   // The mutually-exclusive sets of scripts that were added or removed since the
140   // last script load.
141   std::set<UserScript> added_scripts_;
142   std::set<UserScript> removed_scripts_;
143 
144   // Indicates whether the the collection of scripts should be cleared before
145   // additions and removals on the next script load.
146   bool clear_scripts_;
147 
148   // The IDs of the extensions which changed in the last update sent to the
149   // renderer.
150   ExtensionIdSet changed_extensions_;
151 
152   // If the extensions service has finished loading its initial set of
153   // extensions.
154   bool extension_system_ready_;
155 
156   // If list of user scripts is modified while we're loading it, we note
157   // that we're currently mid-load and then start over again once the load
158   // finishes.  This boolean tracks whether another load is pending.
159   bool pending_load_;
160 
161   // Whether or not we are currently loading.
162   bool is_loading_;
163 
164   // The profile for which the scripts managed here are installed.
165   Profile* profile_;
166 
167   // ID of the extension that owns these scripts, if any. This is only set to a
168   // non-empty value for declarative user script shared memory regions.
169   ExtensionId owner_extension_id_;
170 
171   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
172       extension_registry_observer_;
173 
174   base::WeakPtrFactory<UserScriptLoader> weak_factory_;
175 
176   DISALLOW_COPY_AND_ASSIGN(UserScriptLoader);
177 };
178 
179 }  // namespace extensions
180 
181 #endif  // CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LOADER_H_
182