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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 const GURL& origin, | 88 const GURL& origin, |
88 const ReadResultCallback& callback) { | 89 const ReadResultCallback& callback) { |
89 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 90 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
90 | 91 |
91 NotificationDatabaseData database_data; | 92 NotificationDatabaseData database_data; |
92 NotificationDatabase::Status status = | 93 NotificationDatabase::Status status = |
93 database_->ReadNotificationData(notification_id, | 94 database_->ReadNotificationData(notification_id, |
94 origin, | 95 origin, |
95 &database_data); | 96 &database_data); |
96 | 97 |
| 98 // TODO(peter): Record UMA on |status| for reading from the database. |
| 99 |
97 if (status == NotificationDatabase::STATUS_OK) { | 100 if (status == NotificationDatabase::STATUS_OK) { |
98 BrowserThread::PostTask(BrowserThread::IO, | 101 BrowserThread::PostTask(BrowserThread::IO, |
99 FROM_HERE, | 102 FROM_HERE, |
100 base::Bind(callback, | 103 base::Bind(callback, |
101 true /* success */, | 104 true /* success */, |
102 database_data)); | 105 database_data)); |
103 return; | 106 return; |
104 } | 107 } |
105 | 108 |
106 // TODO(peter): Record UMA on |status| for reading from the database. | 109 // Blow away the database if reading data failed due to corruption. |
107 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 110 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) |
| 111 DestroyDatabase(); |
108 | 112 |
109 BrowserThread::PostTask( | 113 BrowserThread::PostTask( |
110 BrowserThread::IO, | 114 BrowserThread::IO, |
111 FROM_HERE, | 115 FROM_HERE, |
112 base::Bind(callback, false /* success */, NotificationDatabaseData())); | 116 base::Bind(callback, false /* success */, NotificationDatabaseData())); |
113 } | 117 } |
114 | 118 |
115 void PlatformNotificationContextImpl::WriteNotificationData( | 119 void PlatformNotificationContextImpl::WriteNotificationData( |
116 const GURL& origin, | 120 const GURL& origin, |
117 const NotificationDatabaseData& database_data, | 121 const NotificationDatabaseData& database_data, |
(...skipping 10 matching lines...) Expand all Loading... |
128 const NotificationDatabaseData& database_data, | 132 const NotificationDatabaseData& database_data, |
129 const WriteResultCallback& callback) { | 133 const WriteResultCallback& callback) { |
130 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 134 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
131 | 135 |
132 int64_t notification_id = 0; | 136 int64_t notification_id = 0; |
133 NotificationDatabase::Status status = | 137 NotificationDatabase::Status status = |
134 database_->WriteNotificationData(origin, | 138 database_->WriteNotificationData(origin, |
135 database_data, | 139 database_data, |
136 ¬ification_id); | 140 ¬ification_id); |
137 | 141 |
138 DCHECK_GT(notification_id, 0); | 142 // TODO(peter): Record UMA on |status| for reading from the database. |
139 | 143 |
140 if (status == NotificationDatabase::STATUS_OK) { | 144 if (status == NotificationDatabase::STATUS_OK) { |
| 145 DCHECK_GT(notification_id, 0); |
141 BrowserThread::PostTask(BrowserThread::IO, | 146 BrowserThread::PostTask(BrowserThread::IO, |
142 FROM_HERE, | 147 FROM_HERE, |
143 base::Bind(callback, | 148 base::Bind(callback, |
144 true /* success */, | 149 true /* success */, |
145 notification_id)); | 150 notification_id)); |
146 return; | 151 return; |
147 } | 152 } |
148 | 153 |
149 // TODO(peter): Record UMA on |status| for reading from the database. | 154 // Blow away the database if writing data failed due to corruption. |
150 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 155 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) |
| 156 DestroyDatabase(); |
151 | 157 |
152 BrowserThread::PostTask( | 158 BrowserThread::PostTask( |
153 BrowserThread::IO, | 159 BrowserThread::IO, |
154 FROM_HERE, | 160 FROM_HERE, |
155 base::Bind(callback, false /* success */, 0 /* notification_id */)); | 161 base::Bind(callback, false /* success */, 0 /* notification_id */)); |
156 } | 162 } |
157 | 163 |
158 void PlatformNotificationContextImpl::DeleteNotificationData( | 164 void PlatformNotificationContextImpl::DeleteNotificationData( |
159 int64_t notification_id, | 165 int64_t notification_id, |
160 const GURL& origin, | 166 const GURL& origin, |
161 const DeleteResultCallback& callback) { | 167 const DeleteResultCallback& callback) { |
162 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 168 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
163 LazyInitialize( | 169 LazyInitialize( |
164 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData, | 170 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData, |
165 this, notification_id, origin, callback), | 171 this, notification_id, origin, callback), |
166 base::Bind(callback, false /* success */)); | 172 base::Bind(callback, false /* success */)); |
167 } | 173 } |
168 | 174 |
169 void PlatformNotificationContextImpl::DoDeleteNotificationData( | 175 void PlatformNotificationContextImpl::DoDeleteNotificationData( |
170 int64_t notification_id, | 176 int64_t notification_id, |
171 const GURL& origin, | 177 const GURL& origin, |
172 const DeleteResultCallback& callback) { | 178 const DeleteResultCallback& callback) { |
173 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 179 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
174 | 180 |
175 NotificationDatabase::Status status = | 181 NotificationDatabase::Status status = |
176 database_->DeleteNotificationData(notification_id, origin); | 182 database_->DeleteNotificationData(notification_id, origin); |
177 | 183 |
178 const bool success = status == NotificationDatabase::STATUS_OK; | 184 // TODO(peter): Record UMA on |status| for reading from the database. |
179 | 185 |
180 // TODO(peter): Record UMA on |status| for reading from the database. | 186 bool success = status == NotificationDatabase::STATUS_OK; |
181 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 187 |
| 188 // Blow away the database if deleting data failed due to corruption. Following |
| 189 // the contract of the delete methods, consider this to be a success as the |
| 190 // caller's goal has been achieved: the data is gone. |
| 191 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) { |
| 192 DestroyDatabase(); |
| 193 success = true; |
| 194 } |
182 | 195 |
183 BrowserThread::PostTask(BrowserThread::IO, | 196 BrowserThread::PostTask(BrowserThread::IO, |
184 FROM_HERE, | 197 FROM_HERE, |
185 base::Bind(callback, success)); | 198 base::Bind(callback, success)); |
186 } | 199 } |
187 | 200 |
188 void PlatformNotificationContextImpl::OnRegistrationDeleted( | 201 void PlatformNotificationContextImpl::OnRegistrationDeleted( |
189 int64_t registration_id, | 202 int64_t registration_id, |
190 const GURL& pattern) { | 203 const GURL& pattern) { |
191 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 204 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
192 LazyInitialize( | 205 LazyInitialize( |
193 base::Bind(&PlatformNotificationContextImpl:: | 206 base::Bind(&PlatformNotificationContextImpl:: |
194 DoDeleteNotificationsForServiceWorkerRegistration, | 207 DoDeleteNotificationsForServiceWorkerRegistration, |
195 this, pattern.GetOrigin(), registration_id), | 208 this, pattern.GetOrigin(), registration_id), |
196 base::Bind(&DoNothing)); | 209 base::Bind(&DoNothing)); |
197 } | 210 } |
198 | 211 |
199 void PlatformNotificationContextImpl:: | 212 void PlatformNotificationContextImpl:: |
200 DoDeleteNotificationsForServiceWorkerRegistration( | 213 DoDeleteNotificationsForServiceWorkerRegistration( |
201 const GURL& origin, | 214 const GURL& origin, |
202 int64_t service_worker_registration_id) { | 215 int64_t service_worker_registration_id) { |
203 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 216 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
204 | 217 |
205 std::set<int64_t> deleted_notifications_set; | 218 std::set<int64_t> deleted_notifications_set; |
206 database_->DeleteAllNotificationDataForServiceWorkerRegistration( | 219 NotificationDatabase::Status status = |
207 origin, service_worker_registration_id, &deleted_notifications_set); | 220 database_->DeleteAllNotificationDataForServiceWorkerRegistration( |
| 221 origin, service_worker_registration_id, &deleted_notifications_set); |
208 | 222 |
209 // TODO(peter): Record UMA on status for deleting from the database. | 223 // TODO(peter): Record UMA on status for deleting from the database. |
210 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | 224 |
| 225 // Blow away the database if a corruption error occurred during the deletion. |
| 226 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) |
| 227 DestroyDatabase(); |
211 | 228 |
212 // TODO(peter): Close the notifications in |deleted_notifications_set|. | 229 // TODO(peter): Close the notifications in |deleted_notifications_set|. |
213 } | 230 } |
214 | 231 |
| 232 void PlatformNotificationContextImpl::OnStorageWiped() { |
| 233 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 234 LazyInitialize( |
| 235 base::Bind(base::IgnoreResult( |
| 236 &PlatformNotificationContextImpl::DestroyDatabase), this), |
| 237 base::Bind(&DoNothing)); |
| 238 } |
| 239 |
215 void PlatformNotificationContextImpl::LazyInitialize( | 240 void PlatformNotificationContextImpl::LazyInitialize( |
216 const base::Closure& success_closure, | 241 const base::Closure& success_closure, |
217 const base::Closure& failure_closure) { | 242 const base::Closure& failure_closure) { |
218 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 243 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
219 | 244 |
220 if (!task_runner_) { | 245 if (!task_runner_) { |
221 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | 246 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); |
222 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken(); | 247 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken(); |
223 | 248 |
224 task_runner_ = pool->GetSequencedTaskRunner(token); | 249 task_runner_ = pool->GetSequencedTaskRunner(token); |
225 } | 250 } |
226 | 251 |
227 task_runner_->PostTask( | 252 task_runner_->PostTask( |
228 FROM_HERE, | 253 FROM_HERE, |
229 base::Bind(&PlatformNotificationContextImpl::OpenDatabase, | 254 base::Bind(&PlatformNotificationContextImpl::OpenDatabase, |
230 this, success_closure, failure_closure)); | 255 this, success_closure, failure_closure)); |
231 } | 256 } |
232 | 257 |
233 void PlatformNotificationContextImpl::OpenDatabase( | 258 void PlatformNotificationContextImpl::OpenDatabase( |
234 const base::Closure& success_closure, | 259 const base::Closure& success_closure, |
235 const base::Closure& failure_closure) { | 260 const base::Closure& failure_closure) { |
236 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 261 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
237 | 262 |
238 if (database_) { | 263 if (database_) { |
239 success_closure.Run(); | 264 success_closure.Run(); |
240 return; | 265 return; |
241 } | 266 } |
242 | 267 |
243 database_.reset(new NotificationDatabase(GetDatabasePath())); | 268 database_.reset(new NotificationDatabase(GetDatabasePath())); |
| 269 NotificationDatabase::Status status = |
| 270 database_->Open(true /* create_if_missing */); |
244 | 271 |
245 // TODO(peter): Record UMA on |status| for opening the database. | 272 // TODO(peter): Record UMA on |status| for opening the database. |
246 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. | |
247 | 273 |
248 NotificationDatabase::Status status = | 274 // When the database could not be opened due to corruption, destroy it, blow |
249 database_->Open(true /* create_if_missing */); | 275 // away the contents of the directory and try re-opening the database. |
| 276 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) { |
| 277 if (DestroyDatabase()) { |
| 278 status = database_->Open(true /* create_if_missing */); |
| 279 |
| 280 // TODO(peter): Record UMA on |status| for re-opening the database after |
| 281 // corruption was detected. |
| 282 } |
| 283 } |
250 | 284 |
251 if (status == NotificationDatabase::STATUS_OK) { | 285 if (status == NotificationDatabase::STATUS_OK) { |
252 success_closure.Run(); | 286 success_closure.Run(); |
253 return; | 287 return; |
254 } | 288 } |
255 | 289 |
256 // TODO(peter): Properly handle failures when opening the database. | |
257 database_.reset(); | 290 database_.reset(); |
258 | 291 |
259 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure); | 292 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure); |
260 } | 293 } |
261 | 294 |
| 295 bool PlatformNotificationContextImpl::DestroyDatabase() { |
| 296 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 297 DCHECK(database_); |
| 298 |
| 299 // TODO(peter): Record UMA on the status code of the Destroy() call. |
| 300 database_->Destroy(); |
| 301 database_.reset(); |
| 302 |
| 303 // TODO(peter): Close any existing persistent notifications on the platform. |
| 304 |
| 305 // Remove all files in the directory that the database was previously located |
| 306 // in, to make sure that any left-over files are gone as well. |
| 307 base::FilePath database_path = GetDatabasePath(); |
| 308 if (!database_path.empty()) |
| 309 return base::DeleteFile(database_path, true); |
| 310 |
| 311 return true; |
| 312 } |
| 313 |
262 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const { | 314 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const { |
263 if (path_.empty()) | 315 if (path_.empty()) |
264 return path_; | 316 return path_; |
265 | 317 |
266 return path_.Append(kPlatformNotificationsDirectory); | 318 return path_.Append(kPlatformNotificationsDirectory); |
267 } | 319 } |
268 | 320 |
269 void PlatformNotificationContextImpl::SetTaskRunnerForTesting( | 321 void PlatformNotificationContextImpl::SetTaskRunnerForTesting( |
270 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { | 322 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { |
271 task_runner_ = task_runner; | 323 task_runner_ = task_runner; |
272 } | 324 } |
273 | 325 |
274 } // namespace content | 326 } // namespace content |
OLD | NEW |