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 CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
6#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
7
8#include <map>
9#include <vector>
10
11#include "base/callback.h"
12#include "base/gtest_prod_util.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "content/common/service_worker/service_worker_status_code.h"
16
17class GURL;
18
19namespace content {
20
21class BrowserContext;
22class SiteInstance;
23
24// Interacts with the UI thread to keep RenderProcessHosts alive while the
25// ServiceWorker system is using them. It also tracks candidate processes
26// for each pattern. Each instance of ServiceWorkerProcessManager is destroyed
27// on the UI thread shortly after its ServiceWorkerContextWrapper is destroyed.
28class CONTENT_EXPORT ServiceWorkerProcessManager {
29 public:
30  // |*this| must be owned by a ServiceWorkerContextWrapper in a
31  // StoragePartition within |browser_context|.
32  explicit ServiceWorkerProcessManager(BrowserContext* browser_context);
33
34  // Shutdown must be called before the ProcessManager is destroyed.
35  ~ServiceWorkerProcessManager();
36
37  // Synchronously prevents new processes from being allocated.
38  // TODO(jyasskin): Drop references to RenderProcessHosts too.
39  void Shutdown();
40
41  // Returns a reference to a running process suitable for starting the Service
42  // Worker at |script_url|. Posts |callback| to the IO thread to indicate
43  // whether creation succeeded and the process ID that has a new reference.
44  //
45  // Allocation can fail with SERVICE_WORKER_ERROR_START_WORKER_FAILED if
46  // RenderProcessHost::Init fails.
47  void AllocateWorkerProcess(
48      int embedded_worker_id,
49      const GURL& pattern,
50      const GURL& script_url,
51      const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
52          callback);
53
54  // Drops a reference to a process that was running a Service Worker, and its
55  // SiteInstance.  This must match a call to AllocateWorkerProcess.
56  void ReleaseWorkerProcess(int embedded_worker_id);
57
58  // Sets a single process ID that will be used for all embedded workers.  This
59  // bypasses the work of creating a process and managing its worker refcount so
60  // that unittests can run without a BrowserContext.  The test is in charge of
61  // making sure this is only called on the same thread as runs the UI message
62  // loop.
63  void SetProcessIdForTest(int process_id) {
64    process_id_for_test_ = process_id;
65  }
66
67  // Adds/removes process reference for the |pattern|, the process with highest
68  // references count will be chosen to start a worker.
69  void AddProcessReferenceToPattern(const GURL& pattern, int process_id);
70  void RemoveProcessReferenceFromPattern(const GURL& pattern, int process_id);
71
72  // Returns true if the |pattern| has at least one process to run.
73  bool PatternHasProcessToRun(const GURL& pattern) const;
74
75 private:
76  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest, SortProcess);
77
78  // Information about the process for an EmbeddedWorkerInstance.
79  struct ProcessInfo {
80    explicit ProcessInfo(const scoped_refptr<SiteInstance>& site_instance);
81    explicit ProcessInfo(int process_id);
82    ~ProcessInfo();
83
84    // Stores the SiteInstance the Worker lives inside. This needs to outlive
85    // the instance's use of its RPH to uphold assumptions in the
86    // ContentBrowserClient interface.
87    scoped_refptr<SiteInstance> site_instance;
88
89    // In case the process was allocated without using a SiteInstance, we need
90    // to store a process ID to decrement a worker reference on shutdown.
91    // TODO(jyasskin): Implement http://crbug.com/372045 or thread a frame_id in
92    // so all processes can be allocated with a SiteInstance.
93    int process_id;
94  };
95
96  // Maps the process ID to its reference count.
97  typedef std::map<int, int> ProcessRefMap;
98
99  // Maps registration scope pattern to ProcessRefMap.
100  typedef std::map<const GURL, ProcessRefMap> PatternProcessRefMap;
101
102  // Returns a process vector sorted by the reference count for the |pattern|.
103  std::vector<int> SortProcessesForPattern(const GURL& pattern) const;
104
105  // These fields are only accessed on the UI thread.
106  BrowserContext* browser_context_;
107
108  // Maps the ID of a running EmbeddedWorkerInstance to information about the
109  // process it's running inside. Since the Instances themselves live on the IO
110  // thread, this can be slightly out of date:
111  //  * instance_info_ is populated while an Instance is STARTING and before
112  //    it's RUNNING.
113  //  * instance_info_ is depopulated in a message sent as the Instance becomes
114  //    STOPPED.
115  std::map<int, ProcessInfo> instance_info_;
116
117  // In unit tests, this will be returned as the process for all
118  // EmbeddedWorkerInstances.
119  int process_id_for_test_;
120
121  // Candidate processes info for each pattern, should be accessed on the
122  // UI thread.
123  PatternProcessRefMap pattern_processes_;
124
125  // Used to double-check that we don't access *this after it's destroyed.
126  base::WeakPtrFactory<ServiceWorkerProcessManager> weak_this_factory_;
127  const base::WeakPtr<ServiceWorkerProcessManager> weak_this_;
128};
129
130}  // namespace content
131
132namespace base {
133// Specialized to post the deletion to the UI thread.
134template <>
135struct CONTENT_EXPORT DefaultDeleter<content::ServiceWorkerProcessManager> {
136  void operator()(content::ServiceWorkerProcessManager* ptr) const;
137};
138}  // namespace base
139
140#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
141