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"
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"
20 bool IsStoppedAndRedundant(const ServiceWorkerVersionInfo
& version_info
) {
21 return version_info
.running_status
==
22 content::ServiceWorkerVersion::STOPPED
&&
23 version_info
.status
== content::ServiceWorkerVersion::REDUNDANT
;
28 ServiceWorkerContextWatcher::ServiceWorkerContextWatcher(
29 scoped_refptr
<ServiceWorkerContextWrapper
> context
,
30 const WorkerRegistrationUpdatedCallback
& registration_callback
,
31 const WorkerVersionUpdatedCallback
& version_callback
,
32 const WorkerErrorReportedCallback
& error_callback
)
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
,
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
, ®istration_info_map
);
70 for (const auto& registration
:
71 context_
->context()->GetAllLiveRegistrationInfo()) {
72 StoreRegistrationInfo(registration
, ®istration_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
++);
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
)
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
)
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
,
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
);
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(
178 content::ServiceWorkerVersion::RunningStatus running_status
) {
179 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
181 if (version
->running_status
== running_status
)
183 version
->running_status
= running_status
;
184 SendVersionInfo(*version
);
185 if (IsStoppedAndRedundant(*version
))
186 version_info_map_
.erase(version_id
);
189 void ServiceWorkerContextWatcher::OnVersionStateChanged(
191 content::ServiceWorkerVersion::Status status
) {
192 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
194 if (version
->status
== status
)
196 version
->status
= status
;
197 SendVersionInfo(*version
);
198 if (IsStoppedAndRedundant(*version
))
199 version_info_map_
.erase(version_id
);
202 void ServiceWorkerContextWatcher::OnMainScriptHttpResponseInfoSet(
204 base::Time script_response_time
,
205 base::Time script_last_modified
) {
206 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
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
,
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(
229 const ConsoleMessage
& message
) {
230 if (message
.message_level
!= CONSOLE_MESSAGE_LEVEL_ERROR
)
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