Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_process_manager.cc
blobab6012ad97d3e74a38fbd90ad27c68eabdcd8d3e
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.
5 #include "content/browser/service_worker/service_worker_process_manager.h"
7 #include "content/browser/renderer_host/render_process_host_impl.h"
8 #include "content/browser/service_worker/service_worker_context_wrapper.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/site_instance.h"
11 #include "url/gurl.h"
13 namespace content {
15 static bool IncrementWorkerRefCountByPid(int process_id) {
16 RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
17 if (!rph || rph->FastShutdownStarted())
18 return false;
20 static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
21 return true;
24 ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(
25 const scoped_refptr<SiteInstance>& site_instance)
26 : site_instance(site_instance),
27 process_id(site_instance->GetProcess()->GetID()) {
30 ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(int process_id)
31 : process_id(process_id) {
34 ServiceWorkerProcessManager::ProcessInfo::~ProcessInfo() {
37 ServiceWorkerProcessManager::ServiceWorkerProcessManager(
38 BrowserContext* browser_context)
39 : browser_context_(browser_context),
40 process_id_for_test_(-1),
41 weak_this_factory_(this),
42 weak_this_(weak_this_factory_.GetWeakPtr()) {
45 ServiceWorkerProcessManager::~ServiceWorkerProcessManager() {
46 DCHECK_CURRENTLY_ON(BrowserThread::UI);
47 DCHECK(browser_context_ == NULL)
48 << "Call Shutdown() before destroying |this|, so that racing method "
49 << "invocations don't use a destroyed BrowserContext.";
52 void ServiceWorkerProcessManager::Shutdown() {
53 browser_context_ = NULL;
54 for (std::map<int, ProcessInfo>::const_iterator it = instance_info_.begin();
55 it != instance_info_.end();
56 ++it) {
57 RenderProcessHost* rph = RenderProcessHost::FromID(it->second.process_id);
58 DCHECK(rph);
59 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount();
61 instance_info_.clear();
64 void ServiceWorkerProcessManager::AllocateWorkerProcess(
65 int embedded_worker_id,
66 const std::vector<int>& process_ids,
67 const GURL& script_url,
68 const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
69 callback) {
70 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
71 BrowserThread::PostTask(
72 BrowserThread::UI,
73 FROM_HERE,
74 base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess,
75 weak_this_,
76 embedded_worker_id,
77 process_ids,
78 script_url,
79 callback));
80 return;
83 if (process_id_for_test_ != -1) {
84 // Let tests specify the returned process ID. Note: We may need to be able
85 // to specify the error code too.
86 BrowserThread::PostTask(
87 BrowserThread::IO,
88 FROM_HERE,
89 base::Bind(callback, SERVICE_WORKER_OK, process_id_for_test_));
90 return;
93 DCHECK(!ContainsKey(instance_info_, embedded_worker_id))
94 << embedded_worker_id << " already has a process allocated";
96 for (std::vector<int>::const_iterator it = process_ids.begin();
97 it != process_ids.end();
98 ++it) {
99 if (IncrementWorkerRefCountByPid(*it)) {
100 instance_info_.insert(
101 std::make_pair(embedded_worker_id, ProcessInfo(*it)));
102 BrowserThread::PostTask(BrowserThread::IO,
103 FROM_HERE,
104 base::Bind(callback, SERVICE_WORKER_OK, *it));
105 return;
109 if (!browser_context_) {
110 // Shutdown has started.
111 BrowserThread::PostTask(
112 BrowserThread::IO,
113 FROM_HERE,
114 base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
115 return;
117 // No existing processes available; start a new one.
118 scoped_refptr<SiteInstance> site_instance =
119 SiteInstance::CreateForURL(browser_context_, script_url);
120 RenderProcessHost* rph = site_instance->GetProcess();
121 // This Init() call posts a task to the IO thread that adds the RPH's
122 // ServiceWorkerDispatcherHost to the
123 // EmbeddedWorkerRegistry::process_sender_map_.
124 if (!rph->Init()) {
125 LOG(ERROR) << "Couldn't start a new process!";
126 BrowserThread::PostTask(
127 BrowserThread::IO,
128 FROM_HERE,
129 base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
130 return;
133 instance_info_.insert(
134 std::make_pair(embedded_worker_id, ProcessInfo(site_instance)));
136 static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
137 BrowserThread::PostTask(
138 BrowserThread::IO,
139 FROM_HERE,
140 base::Bind(callback, SERVICE_WORKER_OK, rph->GetID()));
143 void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) {
144 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
145 BrowserThread::PostTask(
146 BrowserThread::UI,
147 FROM_HERE,
148 base::Bind(&ServiceWorkerProcessManager::ReleaseWorkerProcess,
149 weak_this_,
150 embedded_worker_id));
151 return;
153 if (process_id_for_test_ != -1) {
154 // Unittests don't increment or decrement the worker refcount of a
155 // RenderProcessHost.
156 return;
158 if (browser_context_ == NULL) {
159 // Shutdown already released all instances.
160 DCHECK(instance_info_.empty());
161 return;
163 std::map<int, ProcessInfo>::iterator info =
164 instance_info_.find(embedded_worker_id);
165 DCHECK(info != instance_info_.end());
166 RenderProcessHost* rph = NULL;
167 if (info->second.site_instance.get()) {
168 rph = info->second.site_instance->GetProcess();
169 DCHECK_EQ(info->second.process_id, rph->GetID())
170 << "A SiteInstance's process shouldn't get destroyed while we're "
171 "holding a reference to it. Was the reference actually held?";
172 } else {
173 rph = RenderProcessHost::FromID(info->second.process_id);
174 DCHECK(rph)
175 << "Process " << info->second.process_id
176 << " was destroyed unexpectedly. Did we actually hold a reference?";
178 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount();
179 instance_info_.erase(info);
182 } // namespace content
184 namespace base {
185 // Destroying ServiceWorkerProcessManagers only on the UI thread allows the
186 // member WeakPtr to safely guard the object's lifetime when used on that
187 // thread.
188 void DefaultDeleter<content::ServiceWorkerProcessManager>::operator()(
189 content::ServiceWorkerProcessManager* ptr) const {
190 content::BrowserThread::DeleteSoon(
191 content::BrowserThread::UI, FROM_HERE, ptr);
193 } // namespace base