summaryrefslogtreecommitdiffstats
path: root/extensions/browser/process_manager.h
blob: 65ee76f8a1d2ccfda3c83d1f336cd8551aed3a15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_PROCESS_MANAGER_H_
#define EXTENSIONS_BROWSER_PROCESS_MANAGER_H_

#include <stdint.h>

#include <map>
#include <set>
#include <string>

#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "extensions/browser/event_page_tracker.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/extension.h"
#include "extensions/common/view_type.h"

class GURL;

namespace content {
class BrowserContext;
class DevToolsAgentHost;
class RenderFrameHost;
class SiteInstance;
class WebContents;
};

namespace extensions {

class Extension;
class ExtensionHost;
class ExtensionRegistry;
class ProcessManagerObserver;

// Manages dynamic state of running Chromium extensions. There is one instance
// of this class per Profile. OTR Profiles have a separate instance that keeps
// track of split-mode extensions only.
class ProcessManager : public KeyedService,
                       public content::NotificationObserver,
                       public ExtensionRegistryObserver,
                       public EventPageTracker {
 public:
  using ExtensionHostSet = std::set<extensions::ExtensionHost*>;

  static ProcessManager* Get(content::BrowserContext* context);
  ~ProcessManager() override;

  void RegisterRenderFrameHost(content::WebContents* web_contents,
                               content::RenderFrameHost* render_frame_host,
                               const Extension* extension);
  void UnregisterRenderFrameHost(content::RenderFrameHost* render_frame_host);
  void DidNavigateRenderFrameHost(content::RenderFrameHost* render_frame_host);

  // Returns the SiteInstance that the given URL belongs to.
  // TODO(aa): This only returns correct results for extensions and packaged
  // apps, not hosted apps.
  virtual scoped_refptr<content::SiteInstance> GetSiteInstanceForURL(
      const GURL& url);

  using FrameSet = std::set<content::RenderFrameHost*>;
  const FrameSet GetAllFrames() const;

  // Returns all RenderFrameHosts that are registered for the specified
  // extension.
  ProcessManager::FrameSet GetRenderFrameHostsForExtension(
      const std::string& extension_id);

  bool IsRenderFrameHostRegistered(content::RenderFrameHost* render_frame_host);

  void AddObserver(ProcessManagerObserver* observer);
  void RemoveObserver(ProcessManagerObserver* observer);

  // Creates a new UI-less extension instance.  Like CreateViewHost, but not
  // displayed anywhere.  Returns false if no background host can be created,
  // for example for hosted apps and extensions that aren't enabled in
  // Incognito.
  virtual bool CreateBackgroundHost(const Extension* extension,
                                    const GURL& url);

  // Creates background hosts if the embedder is ready and they are not already
  // loaded.
  void MaybeCreateStartupBackgroundHosts();

  // Gets the ExtensionHost for the background page for an extension, or null if
  // the extension isn't running or doesn't have a background page.
  ExtensionHost* GetBackgroundHostForExtension(const std::string& extension_id);

  // Returns the ExtensionHost for the given |render_frame_host|, if there is
  // one.
  ExtensionHost* GetExtensionHostForRenderFrameHost(
      content::RenderFrameHost* render_frame_host);

  // Returns true if the (lazy) background host for the given extension has
  // already been sent the unload event and is shutting down.
  bool IsBackgroundHostClosing(const std::string& extension_id);

  // Returns the extension associated with the specified RenderFrameHost/
  // WebContents, or null.
  const Extension* GetExtensionForRenderFrameHost(
      content::RenderFrameHost* render_frame_host);
  const Extension* GetExtensionForWebContents(
      const content::WebContents* web_contents);

  // Getter and setter for the lazy background page's keepalive count. This is
  // the count of how many outstanding "things" are keeping the page alive.
  // When this reaches 0, we will begin the process of shutting down the page.
  // "Things" include pending events, resource loads, and API calls.
  int GetLazyKeepaliveCount(const Extension* extension);
  void IncrementLazyKeepaliveCount(const Extension* extension);
  void DecrementLazyKeepaliveCount(const Extension* extension);

  // Keeps a background page alive. Unlike IncrementLazyKeepaliveCount, these
  // impulses will only keep the page alive for a limited amount of time unless
  // called regularly.
  void KeepaliveImpulse(const Extension* extension);

  // Triggers a keepalive impulse for a plugin (e.g NaCl).
  static void OnKeepaliveFromPlugin(int render_process_id,
                                    int render_frame_id,
                                    const std::string& extension_id);

  // Handles a response to the ShouldSuspend message, used for lazy background
  // pages.
  void OnShouldSuspendAck(const std::string& extension_id,
                          uint64_t sequence_id);

  // Same as above, for the Suspend message.
  void OnSuspendAck(const std::string& extension_id);

  // Tracks network requests for a given RenderFrameHost, used to know
  // when network activity is idle for lazy background pages.
  void OnNetworkRequestStarted(content::RenderFrameHost* render_frame_host,
                               uint64_t request_id);
  void OnNetworkRequestDone(content::RenderFrameHost* render_frame_host,
                            uint64_t request_id);

  // Prevents |extension|'s background page from being closed and sends the
  // onSuspendCanceled() event to it.
  void CancelSuspend(const Extension* extension);

  // Called on shutdown to close our extension hosts.
  void CloseBackgroundHosts();

  // Sets callbacks for testing keepalive impulse behavior.
  using ImpulseCallbackForTesting =
      base::Callback<void(const std::string& extension_id)>;
  void SetKeepaliveImpulseCallbackForTesting(
      const ImpulseCallbackForTesting& callback);
  void SetKeepaliveImpulseDecrementCallbackForTesting(
      const ImpulseCallbackForTesting& callback);

  // EventPageTracker implementation.
  bool IsEventPageSuspended(const std::string& extension_id) override;
  bool WakeEventPage(const std::string& extension_id,
                     const base::Callback<void(bool)>& callback) override;

  // Sets the time in milliseconds that an extension event page can
  // be idle before it is shut down; must be > 0.
  static void SetEventPageIdleTimeForTesting(unsigned idle_time_msec);

  // Sets the time in milliseconds that an extension event page has
  // between being notified of its impending unload and that unload
  // happening.
  static void SetEventPageSuspendingTimeForTesting(
      unsigned suspending_time_msec);

  // Creates a non-incognito instance for tests. |registry| allows unit tests
  // to inject an ExtensionRegistry that is not managed by the usual
  // BrowserContextKeyedServiceFactory system.
  static ProcessManager* CreateForTesting(content::BrowserContext* context,
                                          ExtensionRegistry* registry);

  // Creates an incognito-context instance for tests.
  static ProcessManager* CreateIncognitoForTesting(
      content::BrowserContext* incognito_context,
      content::BrowserContext* original_context,
      ExtensionRegistry* registry);

  content::BrowserContext* browser_context() const { return browser_context_; }

  const ExtensionHostSet& background_hosts() const {
    return background_hosts_;
  }

  bool startup_background_hosts_created_for_test() const {
    return startup_background_hosts_created_;
  }

 protected:
  static ProcessManager* Create(content::BrowserContext* context);

  // |context| is incognito pass the master context as |original_context|.
  // Otherwise pass the same context for both. Pass the ExtensionRegistry for
  // |context| as |registry|, or override it for testing.
  ProcessManager(content::BrowserContext* context,
                 content::BrowserContext* original_context,
                 ExtensionRegistry* registry);

  // Not owned. Also used by IncognitoProcessManager.
  ExtensionRegistry* extension_registry_;

 private:
  friend class ProcessManagerFactory;
  friend class ProcessManagerTest;

  // content::NotificationObserver:
  void Observe(int type,
               const content::NotificationSource& source,
               const content::NotificationDetails& details) override;

  // ExtensionRegistryObserver:
  void OnExtensionLoaded(content::BrowserContext* browser_context,
                         const Extension* extension) override;
  void OnExtensionUnloaded(content::BrowserContext* browser_context,
                           const Extension* extension,
                           UnloadedExtensionInfo::Reason reason) override;

  // Extra information we keep for each extension's background page.
  struct BackgroundPageData;
  struct ExtensionRenderFrameData;
  using BackgroundPageDataMap = std::map<ExtensionId, BackgroundPageData>;
  using ExtensionRenderFrames =
      std::map<content::RenderFrameHost*, ExtensionRenderFrameData>;

  // Load all background pages once the profile data is ready and the pages
  // should be loaded.
  void CreateStartupBackgroundHosts();

  // Called just after |host| is created so it can be registered in our lists.
  void OnBackgroundHostCreated(ExtensionHost* host);

  // Close the given |host| iff it's a background page.
  void CloseBackgroundHost(ExtensionHost* host);

  // If the frame isn't keeping the lazy background page alive, increments the
  // keepalive count to do so.
  void AcquireLazyKeepaliveCountForFrame(
      content::RenderFrameHost* render_frame_host);

  // If the frame is keeping the lazy background page alive, decrements the
  // keepalive count to stop doing it.
  void ReleaseLazyKeepaliveCountForFrame(
      content::RenderFrameHost* render_frame_host);

  // Internal implementation of DecrementLazyKeepaliveCount with an
  // |extension_id| known to have a lazy background page.
  void DecrementLazyKeepaliveCount(const std::string& extension_id);

  // Checks if keepalive impulses have occured, and adjusts keep alive count.
  void OnKeepaliveImpulseCheck();

  // These are called when the extension transitions between idle and active.
  // They control the process of closing the background page when idle.
  void OnLazyBackgroundPageIdle(const std::string& extension_id,
                                uint64_t sequence_id);
  void OnLazyBackgroundPageActive(const std::string& extension_id);
  void CloseLazyBackgroundPageNow(const std::string& extension_id,
                                  uint64_t sequence_id);

  void OnDevToolsStateChanged(content::DevToolsAgentHost*, bool attached);

  // Unregister RenderFrameHosts and clear background page data for an extension
  // which has been unloaded.
  void UnregisterExtension(const std::string& extension_id);

  // Clears background page data for this extension.
  void ClearBackgroundPageData(const std::string& extension_id);

  content::NotificationRegistrar registrar_;

  // The set of ExtensionHosts running viewless background extensions.
  ExtensionHostSet background_hosts_;

  // A SiteInstance related to the SiteInstance for all extensions in
  // this profile.  We create it in such a way that a new
  // browsing instance is created.  This controls process grouping.
  scoped_refptr<content::SiteInstance> site_instance_;

  // The browser context associated with the |site_instance_|.
  content::BrowserContext* browser_context_;

  // Contains all active extension-related RenderFrameHost instances for all
  // extensions. We also keep a cache of the host's view type, because that
  // information is not accessible at registration/deregistration time.
  ExtensionRenderFrames all_extension_frames_;

  BackgroundPageDataMap background_page_data_;

  // True if we have created the startup set of background hosts.
  bool startup_background_hosts_created_;

  base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_;

  ImpulseCallbackForTesting keepalive_impulse_callback_for_testing_;
  ImpulseCallbackForTesting keepalive_impulse_decrement_callback_for_testing_;

  base::ObserverList<ProcessManagerObserver> observer_list_;

  // ID Counter used to set ProcessManager::BackgroundPageData close_sequence_id
  // members. These IDs are tracked per extension in background_page_data_ and
  // are used to verify that nothing has interrupted the process of closing a
  // lazy background process.
  //
  // Any interruption obtains a new ID by incrementing
  // last_background_close_sequence_id_ and storing it in background_page_data_
  // for a particular extension. Callbacks and round-trip IPC messages store the
  // value of the extension's close_sequence_id at the beginning of the process.
  // Thus comparisons can be done to halt when IDs no longer match.
  //
  // This counter provides unique IDs even when BackgroundPageData objects are
  // reset.
  uint64_t last_background_close_sequence_id_;

  // Tracks pending network requests by opaque ID. This is used to ensure proper
  // keepalive counting in response to request status updates; e.g., if an
  // extension URLRequest is constructed and then destroyed without ever
  // starting, we can receive a completion notification without a corresponding
  // start notification. In that case we want to avoid decrementing keepalive.
  std::set<int> pending_network_requests_;

  // Must be last member, see doc on WeakPtrFactory.
  base::WeakPtrFactory<ProcessManager> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(ProcessManager);
};

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_PROCESS_MANAGER_H_