Home | History | Annotate | Download | only in extensions
      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.
     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 
    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