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"
19 bool IsStoppedAndRedundant(const ServiceWorkerVersionInfo
& version_info
) {
20 return version_info
.running_status
==
21 content::ServiceWorkerVersion::STOPPED
&&
22 version_info
.status
== content::ServiceWorkerVersion::REDUNDANT
;
27 ServiceWorkerContextWatcher::ServiceWorkerContextWatcher(
28 scoped_refptr
<ServiceWorkerContextWrapper
> context
,
29 const WorkerRegistrationUpdatedCallback
& registration_callback
,
30 const WorkerVersionUpdatedCallback
& version_callback
,
31 const WorkerErrorReportedCallback
& error_callback
)
33 registration_callback_(registration_callback
),
34 version_callback_(version_callback
),
35 error_callback_(error_callback
) {
36 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
39 void ServiceWorkerContextWatcher::Start() {
40 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
41 BrowserThread::PostTask(
42 BrowserThread::IO
, FROM_HERE
,
43 base::Bind(&ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread
,
47 void ServiceWorkerContextWatcher::Stop() {
48 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
49 BrowserThread::PostTask(
50 BrowserThread::IO
, FROM_HERE
,
51 base::Bind(&ServiceWorkerContextWatcher::StopOnIOThread
, this));
54 void ServiceWorkerContextWatcher::GetStoredRegistrationsOnIOThread() {
55 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
56 context_
->context()->storage()->GetAllRegistrations(base::Bind(
57 &ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread
, this));
60 void ServiceWorkerContextWatcher::OnStoredRegistrationsOnIOThread(
61 const std::vector
<ServiceWorkerRegistrationInfo
>& stored_registrations
) {
62 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
63 context_
->AddObserver(this);
65 base::ScopedPtrHashMap
<int64
, ServiceWorkerRegistrationInfo
>
66 registration_info_map
;
67 for (const auto& registration
: stored_registrations
)
68 StoreRegistrationInfo(registration
, ®istration_info_map
);
69 for (const auto& registration
:
70 context_
->context()->GetAllLiveRegistrationInfo()) {
71 StoreRegistrationInfo(registration
, ®istration_info_map
);
73 for (const auto& version
: context_
->context()->GetAllLiveVersionInfo())
74 StoreVersionInfo(version
);
76 std::vector
<ServiceWorkerRegistrationInfo
> registrations
;
77 registrations
.reserve(registration_info_map
.size());
78 for (const auto& registration_id_info_pair
: registration_info_map
)
79 registrations
.push_back(*registration_id_info_pair
.second
);
81 std::vector
<ServiceWorkerVersionInfo
> versions
;
82 versions
.reserve(version_info_map_
.size());
84 for (auto version_it
= version_info_map_
.begin();
85 version_it
!= version_info_map_
.end();) {
86 versions
.push_back(*version_it
->second
);
87 if (IsStoppedAndRedundant(*version_it
->second
))
88 version_info_map_
.erase(version_it
++);
93 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
94 base::Bind(registration_callback_
, registrations
));
95 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
96 base::Bind(version_callback_
, versions
));
99 void ServiceWorkerContextWatcher::StopOnIOThread() {
100 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
101 context_
->RemoveObserver(this);
104 ServiceWorkerContextWatcher::~ServiceWorkerContextWatcher() {
107 void ServiceWorkerContextWatcher::StoreRegistrationInfo(
108 const ServiceWorkerRegistrationInfo
& registration_info
,
109 base::ScopedPtrHashMap
<int64
, ServiceWorkerRegistrationInfo
>* info_map
) {
110 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
111 if (registration_info
.registration_id
== kInvalidServiceWorkerRegistrationId
)
113 info_map
->set(registration_info
.registration_id
,
114 scoped_ptr
<ServiceWorkerRegistrationInfo
>(
115 new ServiceWorkerRegistrationInfo(registration_info
)));
116 StoreVersionInfo(registration_info
.active_version
);
117 StoreVersionInfo(registration_info
.waiting_version
);
118 StoreVersionInfo(registration_info
.installing_version
);
121 void ServiceWorkerContextWatcher::StoreVersionInfo(
122 const ServiceWorkerVersionInfo
& version_info
) {
123 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
124 if (version_info
.version_id
== kInvalidServiceWorkerVersionId
)
126 version_info_map_
.set(version_info
.version_id
,
127 scoped_ptr
<ServiceWorkerVersionInfo
>(
128 new ServiceWorkerVersionInfo(version_info
)));
131 void ServiceWorkerContextWatcher::SendRegistrationInfo(
132 int64 registration_id
,
134 ServiceWorkerRegistrationInfo::DeleteFlag delete_flag
) {
135 std::vector
<ServiceWorkerRegistrationInfo
> registrations
;
136 registrations
.push_back(
137 ServiceWorkerRegistrationInfo(pattern
, registration_id
, delete_flag
));
138 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
139 base::Bind(registration_callback_
, registrations
));
142 void ServiceWorkerContextWatcher::SendVersionInfo(
143 const ServiceWorkerVersionInfo
& version_info
) {
144 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
145 std::vector
<ServiceWorkerVersionInfo
> versions
;
146 versions
.push_back(version_info
);
147 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
148 base::Bind(version_callback_
, versions
));
151 void ServiceWorkerContextWatcher::OnNewLiveRegistration(int64 registration_id
,
152 const GURL
& pattern
) {
153 SendRegistrationInfo(registration_id
, pattern
,
154 ServiceWorkerRegistrationInfo::IS_NOT_DELETED
);
157 void ServiceWorkerContextWatcher::OnNewLiveVersion(int64 version_id
,
158 int64 registration_id
,
159 const GURL
& script_url
) {
160 if (ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
)) {
161 DCHECK_EQ(version
->registration_id
, registration_id
);
162 DCHECK_EQ(version
->script_url
, script_url
);
166 scoped_ptr
<ServiceWorkerVersionInfo
> version(new ServiceWorkerVersionInfo());
167 version
->version_id
= version_id
;
168 version
->registration_id
= registration_id
;
169 version
->script_url
= script_url
;
170 SendVersionInfo(*version
);
171 if (!IsStoppedAndRedundant(*version
))
172 version_info_map_
.set(version_id
, version
.Pass());
175 void ServiceWorkerContextWatcher::OnRunningStateChanged(
177 content::ServiceWorkerVersion::RunningStatus running_status
) {
178 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
180 if (version
->running_status
== running_status
)
182 version
->running_status
= running_status
;
183 SendVersionInfo(*version
);
184 if (IsStoppedAndRedundant(*version
))
185 version_info_map_
.erase(version_id
);
188 void ServiceWorkerContextWatcher::OnVersionStateChanged(
190 content::ServiceWorkerVersion::Status status
) {
191 ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
);
193 if (version
->status
== status
)
195 version
->status
= status
;
196 SendVersionInfo(*version
);
197 if (IsStoppedAndRedundant(*version
))
198 version_info_map_
.erase(version_id
);
201 void ServiceWorkerContextWatcher::OnErrorReported(int64 version_id
,
204 const ErrorInfo
& info
) {
205 int64 registration_id
= kInvalidServiceWorkerRegistrationId
;
206 if (ServiceWorkerVersionInfo
* version
= version_info_map_
.get(version_id
))
207 registration_id
= version
->registration_id
;
208 BrowserThread::PostTask(
209 BrowserThread::UI
, FROM_HERE
,
210 base::Bind(error_callback_
, registration_id
, version_id
, info
));
213 void ServiceWorkerContextWatcher::OnRegistrationStored(int64 registration_id
,
214 const GURL
& pattern
) {
215 SendRegistrationInfo(registration_id
, pattern
,
216 ServiceWorkerRegistrationInfo::IS_NOT_DELETED
);
219 void ServiceWorkerContextWatcher::OnRegistrationDeleted(int64 registration_id
,
220 const GURL
& pattern
) {
221 SendRegistrationInfo(registration_id
, pattern
,
222 ServiceWorkerRegistrationInfo::IS_DELETED
);
225 } // namespace content