| 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 |