• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetSharedMemory()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.
ScriptsReady()46   bool ScriptsReady() const { return shared_memory_.get() != NULL; }
47 
48   // Returns the path to the directory user scripts are stored in.
user_script_dir()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.
DisownMaster()89     void DisownMaster() {
90       master_ = NULL;
91     }
92 
93    private:
94     friend class base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader>;
95 
~ScriptReloader()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