Chromium Code Reviews| 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 |