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_
->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
: context_
->GetAllLiveRegistrationInfo())
71 StoreRegistrationInfo(registration
, ®istration_info_map
);
72 for (const auto& version
: context_
->GetAllLiveVersionInfo())
73 StoreVersionInfo(version
);
75 std::vector
<ServiceWorkerRegistrationInfo
> registrations
;
76 registrations
.reserve(registration_info_map
.size());
77 for (const auto& registration_id_info_pair
: registration_info_map
)
78 registrations
.push_back(*registration_id_info_pair
.second
);
80 std::vector
<ServiceWorkerVersionInfo
> versions
;
81 versions
.reserve(version_info_map_
.size());
83 for (auto version_it
= version_info_map_
.begin();
84 version_it
!= version_info_map_
.end();) {
85 versions
.push_back(*version_it
->second
);
86 if (IsStoppedAndRedundant(*version_it
->second
))
87 version_info_map_
.erase(version_it
++);
92 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
93 base::Bind(registration_callback_
, registrations
));
94 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
95 base::Bind(version_callback_
, versions
));
98 void ServiceWorkerContextWatcher::StopOnIOThread() {
99 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
100 context_
->RemoveObserver(this);
103 ServiceWorkerContextWatcher::~ServiceWorkerContextWatcher() {
106 void ServiceWorkerContextWatcher::StoreRegistrationInfo(
107 const ServiceWorkerRegistrationInfo
& registration_info
,
108 base::ScopedPtrHashMap
<int64
, ServiceWorkerRegistrationInfo
>* info_map
) {
109 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
110 if (registration_info
.registration_id
== kInvalidServiceWorkerRegistrationId
)
112 info_map
->set(registration_info
.registration_id
,
113 scoped_ptr
<ServiceWorkerRegistrationInfo
>(
114 new ServiceWorkerRegistrationInfo(registration_info
)));
115 StoreVersionInfo(registration_info
.active_version
);
116 StoreVersionInfo(registration_info
.waiting_version
);
117 StoreVersionInfo(registration_info
.installing_version
);
120 void ServiceWorkerContextWatcher::StoreVersionInfo(
121 const ServiceWorkerVersionInfo
& version_info
) {
122 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
123 if (version_info
.version_id
== kInvalidServiceWorkerVersionId
)
125 version_info_map_
.set(version_info
.version_id
,
126 scoped_ptr
<ServiceWorkerVersionInfo
>(
127 new ServiceWorkerVersionInfo(version_info
)));
130 void ServiceWorkerContextWatcher::SendRegistrationInfo(
131 int64 registration_id
,
133 ServiceWorkerRegistrationInfo::DeleteFlag delete_flag
) {
134 std::vector
<ServiceWorkerRegistrationInfo
> registrations
;
135 registrations
.push_back(
136 ServiceWorkerRegistrationInfo(pattern
, registration_id
, delete_flag
));
137 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
138 base::Bind(registration_callback_
, registrations
));
141 void ServiceWorkerContextWatcher::SendVersionInfo(
142 const ServiceWorkerVersionInfo
& version_info
) {
143 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
144 std::vector
<ServiceWorkerVersionInfo
> versions
;
145 versions
.push_back(version_info
);
146 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
147 base::Bind(version_callback_
, versions
));
150 void ServiceWorkerContextWatcher::OnNewLiveRegistration(int64 registration_id
,
151 const GURL
& pattern
) {
152 SendRegistrationInfo(registration_id
, pattern
,
153 ServiceWorkerRegistrationInfo::IS_NOT_DELETED
);
156 void ServiceWorkerContextWatcher::OnNewLiveVersion(int64 version_id
,
157 int64 registration_id
,
158 const GURL
& script_url
) {
159 if (ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
)) {
160 DCHECK_EQ(version
->registration_id
, registration_id
);
161 DCHECK_EQ(version
->script_url
, script_url
);
165 scoped_ptr
<ServiceWorkerVersionInfo
> version(new ServiceWorkerVersionInfo());
166 version
->version_id
= version_id
;
167 version
->registration_id
= registration_id
;
168 version
->script_url
= script_url
;
169 SendVersionInfo(*version
);
170 if (!IsStoppedAndRedundant(*version
))
171 version_info_map_
.set(version_id
, version
.Pass());
174 void ServiceWorkerContextWatcher::OnRunningStateChanged(
176 content::ServiceWorkerVersion::RunningStatus running_status
) {
177 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
179 if (version
->running_status
== running_status
)
181 version
->running_status
= running_status
;
182 SendVersionInfo(*version
);
183 if (IsStoppedAndRedundant(*version
))
184 version_info_map_
.erase(version_id
);
187 void ServiceWorkerContextWatcher::OnVersionStateChanged(
189 content::ServiceWorkerVersion::Status status
) {
190 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
192 if (version
->status
== status
)
194 version
->status
= status
;
195 SendVersionInfo(*version
);
196 if (IsStoppedAndRedundant(*version
))
197 version_info_map_
.erase(version_id
);
200 void ServiceWorkerContextWatcher::OnMainScriptHttpResponseInfoSet(
202 base::Time script_response_time
,
203 base::Time script_last_modified
) {
204 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
206 version
->script_response_time
= script_response_time
;
207 version
->script_last_modified
= script_last_modified
;
208 SendVersionInfo(*version
);
211 void ServiceWorkerContextWatcher::OnErrorReported(int64 version_id
,
214 const ErrorInfo
& info
) {
215 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
216 if (ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
))
217 registration_id
= version
->registration_id
;
218 BrowserThread::PostTask(
219 BrowserThread::UI
, FROM_HERE
,
220 base::Bind(error_callback_
, registration_id
, version_id
, info
));
223 void ServiceWorkerContextWatcher::OnReportConsoleMessage(
227 const ConsoleMessage
& message
) {
228 if (message
.message_level
!= CONSOLE_MESSAGE_LEVEL_ERROR
)
230 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
231 if (ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
))
232 registration_id
= version
->registration_id
;
233 BrowserThread::PostTask(
234 BrowserThread::UI
, FROM_HERE
,
235 base::Bind(error_callback_
, registration_id
, version_id
,
236 ErrorInfo(message
.message
, message
.line_number
, -1,
237 message
.source_url
)));
240 void ServiceWorkerContextWatcher::OnRegistrationStored(int64 registration_id
,
241 const GURL
& pattern
) {
242 SendRegistrationInfo(registration_id
, pattern
,
243 ServiceWorkerRegistrationInfo::IS_NOT_DELETED
);
246 void ServiceWorkerContextWatcher::OnRegistrationDeleted(int64 registration_id
,
247 const GURL
& pattern
) {
248 SendRegistrationInfo(registration_id
, pattern
,
249 ServiceWorkerRegistrationInfo::IS_DELETED
);
252 } // namespace content