OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/notifications/platform_notification_context_impl.h" | 5 #include "content/browser/notifications/platform_notification_context_impl.h" |
6 | 6 |
7 #include "base/bind_helpers.h" | 7 #include "base/bind_helpers.h" |
8 #include "base/files/file_util.h" | |
8 #include "base/threading/sequenced_worker_pool.h" | 9 #include "base/threading/sequenced_worker_pool.h" |
9 #include "content/browser/notifications/notification_database.h" | 10 #include "content/browser/notifications/notification_database.h" |
10 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 11 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
11 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
12 #include "content/public/browser/notification_database_data.h" | 13 #include "content/public/browser/notification_database_data.h" |
13 | 14 |
14 using base::DoNothing; | 15 using base::DoNothing; |
15 | 16 |
16 namespace content { | 17 namespace content { |
17 | 18 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
81 const GURL& origin, | 82 const GURL& origin, |
82 const ReadResultCallback& callback) { | 83 const ReadResultCallback& callback) { |
83 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 84 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
84 | 85 |
85 NotificationDatabaseData database_data; | 86 NotificationDatabaseData database_data; |
86 NotificationDatabase::Status status = | 87 NotificationDatabase::Status status = |
87 database_->ReadNotificationData(notification_id, | 88 database_->ReadNotificationData(notification_id, |
88 origin, | 89 origin, |
89 &database_data); | 90 &database_data); |
90 | 91 |
92 // TODO(peter): Record UMA on |status| for reading from the database. | |
93 | |
91 if (status == NotificationDatabase::STATUS_OK) { | 94 if (status == NotificationDatabase::STATUS_OK) { |
92 BrowserThread::PostTask(BrowserThread::IO, | 95 BrowserThread::PostTask(BrowserThread::IO, |
93 FROM_HERE, | 96 FROM_HERE, |
94 base::Bind(callback, | 97 base::Bind(callback, |
95 true /* success */, | 98 true /* success */, |
96 database_data)); | 99 database_data)); |
97 return; | 100 return; |
98 } | 101 } |
99 | 102 |
100 // TODO(peter): Record UMA on |status| for reading from the database. | 103 // Blow away the database if reading data failed due to corruption. |
101 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 104 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) |
105 DestroyDatabase(); | |
102 | 106 |
103 BrowserThread::PostTask( | 107 BrowserThread::PostTask( |
104 BrowserThread::IO, | 108 BrowserThread::IO, |
105 FROM_HERE, | 109 FROM_HERE, |
106 base::Bind(callback, false /* success */, NotificationDatabaseData())); | 110 base::Bind(callback, false /* success */, NotificationDatabaseData())); |
107 } | 111 } |
108 | 112 |
109 void PlatformNotificationContextImpl::WriteNotificationData( | 113 void PlatformNotificationContextImpl::WriteNotificationData( |
110 const GURL& origin, | 114 const GURL& origin, |
111 const NotificationDatabaseData& database_data, | 115 const NotificationDatabaseData& database_data, |
(...skipping 10 matching lines...) Expand all Loading... | |
122 const NotificationDatabaseData& database_data, | 126 const NotificationDatabaseData& database_data, |
123 const WriteResultCallback& callback) { | 127 const WriteResultCallback& callback) { |
124 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 128 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
125 | 129 |
126 int64_t notification_id = 0; | 130 int64_t notification_id = 0; |
127 NotificationDatabase::Status status = | 131 NotificationDatabase::Status status = |
128 database_->WriteNotificationData(origin, | 132 database_->WriteNotificationData(origin, |
129 database_data, | 133 database_data, |
130 ¬ification_id); | 134 ¬ification_id); |
131 | 135 |
132 DCHECK_GT(notification_id, 0); | 136 // TODO(peter): Record UMA on |status| for reading from the database. |
133 | 137 |
134 if (status == NotificationDatabase::STATUS_OK) { | 138 if (status == NotificationDatabase::STATUS_OK) { |
139 DCHECK_GT(notification_id, 0); | |
135 BrowserThread::PostTask(BrowserThread::IO, | 140 BrowserThread::PostTask(BrowserThread::IO, |
136 FROM_HERE, | 141 FROM_HERE, |
137 base::Bind(callback, | 142 base::Bind(callback, |
138 true /* success */, | 143 true /* success */, |
139 notification_id)); | 144 notification_id)); |
140 return; | 145 return; |
141 } | 146 } |
142 | 147 |
143 // TODO(peter): Record UMA on |status| for reading from the database. | 148 // Blow away the database if writing data failed due to corruption. |
144 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 149 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) |
150 DestroyDatabase(); | |
145 | 151 |
146 BrowserThread::PostTask( | 152 BrowserThread::PostTask( |
147 BrowserThread::IO, | 153 BrowserThread::IO, |
148 FROM_HERE, | 154 FROM_HERE, |
149 base::Bind(callback, false /* success */, 0 /* notification_id */)); | 155 base::Bind(callback, false /* success */, 0 /* notification_id */)); |
150 } | 156 } |
151 | 157 |
152 void PlatformNotificationContextImpl::DeleteNotificationData( | 158 void PlatformNotificationContextImpl::DeleteNotificationData( |
153 int64_t notification_id, | 159 int64_t notification_id, |
154 const GURL& origin, | 160 const GURL& origin, |
155 const DeleteResultCallback& callback) { | 161 const DeleteResultCallback& callback) { |
156 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 162 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
157 LazyInitialize( | 163 LazyInitialize( |
158 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData, | 164 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData, |
159 this, notification_id, origin, callback), | 165 this, notification_id, origin, callback), |
160 base::Bind(callback, false /* success */)); | 166 base::Bind(callback, false /* success */)); |
161 } | 167 } |
162 | 168 |
163 void PlatformNotificationContextImpl::DoDeleteNotificationData( | 169 void PlatformNotificationContextImpl::DoDeleteNotificationData( |
164 int64_t notification_id, | 170 int64_t notification_id, |
165 const GURL& origin, | 171 const GURL& origin, |
166 const DeleteResultCallback& callback) { | 172 const DeleteResultCallback& callback) { |
167 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 173 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
168 | 174 |
169 NotificationDatabase::Status status = | 175 NotificationDatabase::Status status = |
170 database_->DeleteNotificationData(notification_id, origin); | 176 database_->DeleteNotificationData(notification_id, origin); |
171 | 177 |
172 const bool success = status == NotificationDatabase::STATUS_OK; | 178 // TODO(peter): Record UMA on |status| for reading from the database. |
173 | 179 |
174 // TODO(peter): Record UMA on |status| for reading from the database. | 180 bool success = status == NotificationDatabase::STATUS_OK; |
175 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 181 |
182 // Blow away the database if reading data failed due to corruption. Following | |
johnme
2015/03/20 15:29:06
s/reading/deleting/
Peter Beverloo
2015/03/20 18:55:37
Done.
| |
183 // the contract of the delete methods, consider this to be a success as the | |
184 // caller's goal has been achieved: the data is gone. | |
185 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) { | |
186 DestroyDatabase(); | |
cmumford
2015/03/20 17:36:52
Well I guess you will have times where DestroyData
| |
187 success = true; | |
188 } | |
176 | 189 |
177 BrowserThread::PostTask(BrowserThread::IO, | 190 BrowserThread::PostTask(BrowserThread::IO, |
178 FROM_HERE, | 191 FROM_HERE, |
179 base::Bind(callback, success)); | 192 base::Bind(callback, success)); |
180 } | 193 } |
181 | 194 |
182 void PlatformNotificationContextImpl::OnRegistrationDeleted( | 195 void PlatformNotificationContextImpl::OnRegistrationDeleted( |
183 int64_t registration_id, | 196 int64_t registration_id, |
184 const GURL& pattern) { | 197 const GURL& pattern) { |
185 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 198 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
186 LazyInitialize( | 199 LazyInitialize( |
187 base::Bind(&PlatformNotificationContextImpl:: | 200 base::Bind(&PlatformNotificationContextImpl:: |
188 DoDeleteNotificationsForServiceWorkerRegistration, | 201 DoDeleteNotificationsForServiceWorkerRegistration, |
189 this, pattern.GetOrigin(), registration_id), | 202 this, pattern.GetOrigin(), registration_id), |
190 base::Bind(&DoNothing)); | 203 base::Bind(&DoNothing)); |
191 } | 204 } |
192 | 205 |
193 void PlatformNotificationContextImpl:: | 206 void PlatformNotificationContextImpl:: |
194 DoDeleteNotificationsForServiceWorkerRegistration( | 207 DoDeleteNotificationsForServiceWorkerRegistration( |
195 const GURL& origin, | 208 const GURL& origin, |
196 int64_t service_worker_registration_id) { | 209 int64_t service_worker_registration_id) { |
197 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 210 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
198 | 211 |
199 std::set<int64_t> deleted_notifications_set; | 212 std::set<int64_t> deleted_notifications_set; |
200 database_->DeleteAllNotificationDataForServiceWorkerRegistration( | 213 NotificationDatabase::Status status = |
201 origin, service_worker_registration_id, &deleted_notifications_set); | 214 database_->DeleteAllNotificationDataForServiceWorkerRegistration( |
215 origin, service_worker_registration_id, &deleted_notifications_set); | |
202 | 216 |
203 // TODO(peter): Record UMA on status for deleting from the database. | 217 // TODO(peter): Record UMA on status for deleting from the database. |
218 | |
219 // Blow away the database if a corruption error occurred during the deletion. | |
220 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) | |
221 DestroyDatabase(); | |
222 | |
204 // TODO(peter): Close the notifications in |deleted_notifications_set|. | 223 // TODO(peter): Close the notifications in |deleted_notifications_set|. |
205 } | 224 } |
206 | 225 |
226 void PlatformNotificationContextImpl::OnStorageWiped() { | |
227 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
228 LazyInitialize( | |
229 base::Bind(&PlatformNotificationContextImpl::DestroyDatabase, this), | |
230 base::Bind(&DoNothing)); | |
231 } | |
232 | |
207 void PlatformNotificationContextImpl::LazyInitialize( | 233 void PlatformNotificationContextImpl::LazyInitialize( |
208 const base::Closure& success_closure, | 234 const base::Closure& success_closure, |
209 const base::Closure& failure_closure) { | 235 const base::Closure& failure_closure) { |
210 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 236 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
211 | 237 |
212 if (!task_runner_) { | 238 if (!task_runner_) { |
213 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | 239 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); |
214 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken(); | 240 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken(); |
215 | 241 |
216 task_runner_ = pool->GetSequencedTaskRunner(token); | 242 task_runner_ = pool->GetSequencedTaskRunner(token); |
217 } | 243 } |
218 | 244 |
219 task_runner_->PostTask( | 245 task_runner_->PostTask( |
220 FROM_HERE, | 246 FROM_HERE, |
221 base::Bind(&PlatformNotificationContextImpl::OpenDatabase, | 247 base::Bind(&PlatformNotificationContextImpl::OpenDatabase, |
222 this, success_closure, failure_closure)); | 248 this, success_closure, failure_closure, |
249 true /* delete_on_corruption */)); | |
223 } | 250 } |
224 | 251 |
225 void PlatformNotificationContextImpl::OpenDatabase( | 252 void PlatformNotificationContextImpl::OpenDatabase( |
226 const base::Closure& success_closure, | 253 const base::Closure& success_closure, |
227 const base::Closure& failure_closure) { | 254 const base::Closure& failure_closure, |
255 bool delete_on_corruption) { | |
228 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 256 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
229 | 257 |
230 if (database_) { | 258 if (database_) { |
231 success_closure.Run(); | 259 success_closure.Run(); |
232 return; | 260 return; |
233 } | 261 } |
234 | 262 |
235 database_.reset(new NotificationDatabase(GetDatabasePath())); | 263 database_.reset(new NotificationDatabase(GetDatabasePath())); |
264 NotificationDatabase::Status status = | |
265 database_->Open(true /* create_if_missing */); | |
236 | 266 |
237 // TODO(peter): Record UMA on |status| for opening the database. | 267 // TODO(peter): Record UMA on |status| for opening the database. |
238 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | |
239 | |
240 NotificationDatabase::Status status = | |
241 database_->Open(true /* create_if_missing */); | |
242 | 268 |
243 if (status == NotificationDatabase::STATUS_OK) { | 269 if (status == NotificationDatabase::STATUS_OK) { |
244 success_closure.Run(); | 270 success_closure.Run(); |
245 return; | 271 return; |
246 } | 272 } |
247 | 273 |
248 // TODO(peter): Properly handle failures when opening the database. | 274 // When the database could not be opened due to corruption, and the |
275 // |delete_on_corruption| parameter is true, blow it away and retry. | |
276 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED && | |
277 delete_on_corruption) { | |
278 DestroyDatabase(); | |
279 OpenDatabase(success_closure, | |
280 failure_closure, | |
281 false /* delete_on_corruption */); | |
cmumford
2015/03/20 17:36:52
I see your point about booleans - I prefer the rel
Peter Beverloo
2015/03/20 18:55:37
That's a great suggestion - thank you once again!
| |
282 return; | |
283 } | |
284 | |
249 database_.reset(); | 285 database_.reset(); |
250 | 286 |
251 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure); | 287 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure); |
252 } | 288 } |
253 | 289 |
290 void PlatformNotificationContextImpl::DestroyDatabase() { | |
291 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
292 DCHECK(database_); | |
293 | |
294 // TODO(peter): Record UMA on the status code of the Destroy() call. | |
295 database_->Destroy(); | |
296 database_.reset(); | |
297 | |
298 // Remove all files in the directory that the database was previously located | |
299 // in, to make sure that any left-over files are gone as well. | |
300 base::FilePath database_path = GetDatabasePath(); | |
301 if (!database_path.empty()) | |
302 base::DeleteFile(database_path, true); | |
303 | |
304 // TODO(peter): Close any existing persistent notifications on the platform. | |
305 } | |
306 | |
254 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const { | 307 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const { |
255 if (path_.empty()) | 308 if (path_.empty()) |
256 return path_; | 309 return path_; |
257 | 310 |
258 return path_.Append(kPlatformNotificationsDirectory); | 311 return path_.Append(kPlatformNotificationsDirectory); |
259 } | 312 } |
260 | 313 |
261 void PlatformNotificationContextImpl::SetTaskRunnerForTesting( | 314 void PlatformNotificationContextImpl::SetTaskRunnerForTesting( |
262 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { | 315 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { |
263 task_runner_ = task_runner; | 316 task_runner_ = task_runner; |
264 } | 317 } |
265 | 318 |
266 } // namespace content | 319 } // namespace content |
OLD | NEW |