Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_context_watcher.cc
blob5d1a1a8ff813dcd845e9299ebe358a64a79a2b90
1 // Copyright 2015 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_context_watcher.h"
7 #include "base/bind.h"
8 #include "base/containers/scoped_ptr_hash_map.h"
9 #include "content/browser/service_worker/service_worker_context_observer.h"
10 #include "content/browser/service_worker/service_worker_context_wrapper.h"
11 #include "content/browser/service_worker/service_worker_version.h"
12 #include "content/common/service_worker/service_worker_types.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/common/console_message_level.h"
15 #include "url/gurl.h"
17 namespace content {
18 namespace {
20 bool IsStoppedAndRedundant(const ServiceWorkerVersionInfo& version_info) {
21 return version_info.running_status ==
22 content::ServiceWorkerVersion::STOPPED &&
23 version_info.status == content::ServiceWorkerVersion::REDUNDANT;
26 } // namespace
28 ServiceWorkerContextWatcher::ServiceWorkerContextWatcher(
29 scoped_refptr<ServiceWorkerContextWrapper> context,
30 const WorkerRegistrationUpdatedCallback& registration_callback,
31 const WorkerVersionUpdatedCallback& version_callback,
32 const WorkerErrorReportedCallback& error_callback)
33 : context_(context),
34 registration_callback_(registration_callback),
35 version_callback_(version_callback),
36 error_callback_(error_callback) {
37 DCHECK_CURRENTLY_ON(BrowserThread::UI);
40 void ServiceWorkerContextWatcher::Start() {
41 DCHECK_CURRENTLY_ON(BrowserThread::UI);
42 BrowserThread::PostTask(
43 BrowserThread::IO, FROM_HERE,
44 base::Bind(&ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread,
45 this));
48 void ServiceWorkerContextWatcher::Stop() {
49 DCHECK_CURRENTLY_ON(BrowserThread::UI);
50 BrowserThread::PostTask(
51 BrowserThread::IO, FROM_HERE,
52 base::Bind(&ServiceWorkerContextWatcher::StopOnIOThread, this));
55 void ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread() {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO);
57 context_->context()->storage()->GetAllRegistrations(base::Bind(
58 &ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread, this));
61 void ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread(
62 const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) {
63 DCHECK_CURRENTLY_ON(BrowserThread::IO);
64 context_->AddObserver(this);
66 base::ScopedPtrHashMap<int64, ServiceWorkerRegistrationInfo>
67 registration_info_map;
68 for (const auto& registration : stored_registrations)
69 StoreRegistrationInfo(registration, &registration_info_map);
70 for (const auto& registration :
71 context_->context()->GetAllLiveRegistrationInfo()) {
72 StoreRegistrationInfo(registration, &registration_info_map);
74 for (const auto& version : context_->context()->GetAllLiveVersionInfo())
75 StoreVersionInfo(version);
77 std::vector<ServiceWorkerRegistrationInfo> registrations;
78 registrations.reserve(registration_info_map.size());
79 for (const auto& registration_id_info_pair : registration_info_map)
80 registrations.push_back(*registration_id_info_pair.second);
82 std::vector<ServiceWorkerVersionInfo> versions;
83 versions.reserve(version_info_map_.size());
85 for (auto version_it = version_info_map_.begin();
86 version_it != version_info_map_.end();) {
87 versions.push_back(*version_it->second);
88 if (IsStoppedAndRedundant(*version_it->second))
89 version_info_map_.erase(version_it++);
90 else
91 ++version_it;
94 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
95 base::Bind(registration_callback_, registrations));
96 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
97 base::Bind(version_callback_, versions));
100 void ServiceWorkerContextWatcher::StopOnIOThread() {
101 DCHECK_CURRENTLY_ON(BrowserThread::IO);
102 context_->RemoveObserver(this);
105 ServiceWorkerContextWatcher::~ServiceWorkerContextWatcher() {
108 void ServiceWorkerContextWatcher::StoreRegistrationInfo(
109 const ServiceWorkerRegistrationInfo& registration_info,
110 base::ScopedPtrHashMap<int64, ServiceWorkerRegistrationInfo>* info_map) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
112 if (registration_info.registration_id == kInvalidServiceWorkerRegistrationId)
113 return;
114 info_map->set(registration_info.registration_id,
115 scoped_ptr<ServiceWorkerRegistrationInfo>(
116 new ServiceWorkerRegistrationInfo(registration_info)));
117 StoreVersionInfo(registration_info.active_version);
118 StoreVersionInfo(registration_info.waiting_version);
119 StoreVersionInfo(registration_info.installing_version);
122 void ServiceWorkerContextWatcher::StoreVersionInfo(
123 const ServiceWorkerVersionInfo& version_info) {
124 DCHECK_CURRENTLY_ON(BrowserThread::IO);
125 if (version_info.version_id == kInvalidServiceWorkerVersionId)
126 return;
127 version_info_map_.set(version_info.version_id,
128 scoped_ptr<ServiceWorkerVersionInfo>(
129 new ServiceWorkerVersionInfo(version_info)));
132 void ServiceWorkerContextWatcher::SendRegistrationInfo(
133 int64 registration_id,
134 const GURL& pattern,
135 ServiceWorkerRegistrationInfo::DeleteFlag delete_flag) {
136 std::vector<ServiceWorkerRegistrationInfo> registrations;
137 registrations.push_back(
138 ServiceWorkerRegistrationInfo(pattern, registration_id, delete_flag));
139 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
140 base::Bind(registration_callback_, registrations));
143 void ServiceWorkerContextWatcher::SendVersionInfo(
144 const ServiceWorkerVersionInfo& version_info) {
145 DCHECK_CURRENTLY_ON(BrowserThread::IO);
146 std::vector<ServiceWorkerVersionInfo> versions;
147 versions.push_back(version_info);
148 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
149 base::Bind(version_callback_, versions));
152 void ServiceWorkerContextWatcher::OnNewLiveRegistration(int64 registration_id,
153 const GURL& pattern) {
154 SendRegistrationInfo(registration_id, pattern,
155 ServiceWorkerRegistrationInfo::IS_NOT_DELETED);
158 void ServiceWorkerContextWatcher::OnNewLiveVersion(int64 version_id,
159 int64 registration_id,
160 const GURL& script_url) {
161 if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id)) {
162 DCHECK_EQ(version->registration_id, registration_id);
163 DCHECK_EQ(version->script_url, script_url);
164 return;
167 scoped_ptr<ServiceWorkerVersionInfo> version(new ServiceWorkerVersionInfo());
168 version->version_id = version_id;
169 version->registration_id = registration_id;
170 version->script_url = script_url;
171 SendVersionInfo(*version);
172 if (!IsStoppedAndRedundant(*version))
173 version_info_map_.set(version_id, version.Pass());
176 void ServiceWorkerContextWatcher::OnRunningStateChanged(
177 int64 version_id,
178 content::ServiceWorkerVersion::RunningStatus running_status) {
179 ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
180 DCHECK(version);
181 if (version->running_status == running_status)
182 return;
183 version->running_status = running_status;
184 SendVersionInfo(*version);
185 if (IsStoppedAndRedundant(*version))
186 version_info_map_.erase(version_id);
189 void ServiceWorkerContextWatcher::OnVersionStateChanged(
190 int64 version_id,
191 content::ServiceWorkerVersion::Status status) {
192 ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
193 DCHECK(version);
194 if (version->status == status)
195 return;
196 version->status = status;
197 SendVersionInfo(*version);
198 if (IsStoppedAndRedundant(*version))
199 version_info_map_.erase(version_id);
202 void ServiceWorkerContextWatcher::OnMainScriptHttpResponseInfoSet(
203 int64 version_id,
204 base::Time script_response_time,
205 base::Time script_last_modified) {
206 ServiceWorkerVersionInfo* version = version_info_map_.get(version_id);
207 DCHECK(version);
208 version->script_response_time = script_response_time;
209 version->script_last_modified = script_last_modified;
210 SendVersionInfo(*version);
213 void ServiceWorkerContextWatcher::OnErrorReported(int64 version_id,
214 int process_id,
215 int thread_id,
216 const ErrorInfo& info) {
217 int64 registration_id = kInvalidServiceWorkerRegistrationId;
218 if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id))
219 registration_id = version->registration_id;
220 BrowserThread::PostTask(
221 BrowserThread::UI, FROM_HERE,
222 base::Bind(error_callback_, registration_id, version_id, info));
225 void ServiceWorkerContextWatcher::OnReportConsoleMessage(
226 int64 version_id,
227 int process_id,
228 int thread_id,
229 const ConsoleMessage& message) {
230 if (message.message_level != CONSOLE_MESSAGE_LEVEL_ERROR)
231 return;
232 int64 registration_id = kInvalidServiceWorkerRegistrationId;
233 if (ServiceWorkerVersionInfo* version = version_info_map_.get(version_id))
234 registration_id = version->registration_id;
235 BrowserThread::PostTask(
236 BrowserThread::UI, FROM_HERE,
237 base::Bind(error_callback_, registration_id, version_id,
238 ErrorInfo(message.message, message.line_number, -1,
239 message.source_url)));
242 void ServiceWorkerContextWatcher::OnRegistrationStored(int64 registration_id,
243 const GURL& pattern) {
244 SendRegistrationInfo(registration_id, pattern,
245 ServiceWorkerRegistrationInfo::IS_NOT_DELETED);
248 void ServiceWorkerContextWatcher::OnRegistrationDeleted(int64 registration_id,
249 const GURL& pattern) {
250 SendRegistrationInfo(registration_id, pattern,
251 ServiceWorkerRegistrationInfo::IS_DELETED);
254 } // namespace content