| Index: content/browser/notifications/platform_notification_context_impl.cc
|
| diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc
|
| index b49a79c8fada3007eb84e5b35b1b8034fac593a6..ba23fc171971985d8e6bdee0d52f3e566ccc7015 100644
|
| --- a/content/browser/notifications/platform_notification_context_impl.cc
|
| +++ b/content/browser/notifications/platform_notification_context_impl.cc
|
| @@ -5,6 +5,7 @@
|
| #include "content/browser/notifications/platform_notification_context_impl.h"
|
|
|
| #include "base/bind_helpers.h"
|
| +#include "base/files/file_util.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| #include "content/browser/notifications/notification_database.h"
|
| #include "content/browser/service_worker/service_worker_context_wrapper.h"
|
| @@ -94,6 +95,8 @@ void PlatformNotificationContextImpl::DoReadNotificationData(
|
| origin,
|
| &database_data);
|
|
|
| + // TODO(peter): Record UMA on |status| for reading from the database.
|
| +
|
| if (status == NotificationDatabase::STATUS_OK) {
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -103,8 +106,9 @@ void PlatformNotificationContextImpl::DoReadNotificationData(
|
| return;
|
| }
|
|
|
| - // TODO(peter): Record UMA on |status| for reading from the database.
|
| - // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
|
| + // Blow away the database if reading data failed due to corruption.
|
| + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
|
| + DestroyDatabase();
|
|
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| @@ -135,9 +139,10 @@ void PlatformNotificationContextImpl::DoWriteNotificationData(
|
| database_data,
|
| ¬ification_id);
|
|
|
| - DCHECK_GT(notification_id, 0);
|
| + // TODO(peter): Record UMA on |status| for reading from the database.
|
|
|
| if (status == NotificationDatabase::STATUS_OK) {
|
| + DCHECK_GT(notification_id, 0);
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| base::Bind(callback,
|
| @@ -146,8 +151,9 @@ void PlatformNotificationContextImpl::DoWriteNotificationData(
|
| return;
|
| }
|
|
|
| - // TODO(peter): Record UMA on |status| for reading from the database.
|
| - // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
|
| + // Blow away the database if writing data failed due to corruption.
|
| + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
|
| + DestroyDatabase();
|
|
|
| BrowserThread::PostTask(
|
| BrowserThread::IO,
|
| @@ -175,10 +181,17 @@ void PlatformNotificationContextImpl::DoDeleteNotificationData(
|
| NotificationDatabase::Status status =
|
| database_->DeleteNotificationData(notification_id, origin);
|
|
|
| - const bool success = status == NotificationDatabase::STATUS_OK;
|
| -
|
| // TODO(peter): Record UMA on |status| for reading from the database.
|
| - // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
|
| +
|
| + bool success = status == NotificationDatabase::STATUS_OK;
|
| +
|
| + // Blow away the database if deleting data failed due to corruption. Following
|
| + // the contract of the delete methods, consider this to be a success as the
|
| + // caller's goal has been achieved: the data is gone.
|
| + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
|
| + DestroyDatabase();
|
| + success = true;
|
| + }
|
|
|
| BrowserThread::PostTask(BrowserThread::IO,
|
| FROM_HERE,
|
| @@ -203,15 +216,27 @@ void PlatformNotificationContextImpl::
|
| DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
|
|
| std::set<int64_t> deleted_notifications_set;
|
| - database_->DeleteAllNotificationDataForServiceWorkerRegistration(
|
| - origin, service_worker_registration_id, &deleted_notifications_set);
|
| + NotificationDatabase::Status status =
|
| + database_->DeleteAllNotificationDataForServiceWorkerRegistration(
|
| + origin, service_worker_registration_id, &deleted_notifications_set);
|
|
|
| // TODO(peter): Record UMA on status for deleting from the database.
|
| - // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
|
| +
|
| + // Blow away the database if a corruption error occurred during the deletion.
|
| + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
|
| + DestroyDatabase();
|
|
|
| // TODO(peter): Close the notifications in |deleted_notifications_set|.
|
| }
|
|
|
| +void PlatformNotificationContextImpl::OnStorageWiped() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + LazyInitialize(
|
| + base::Bind(base::IgnoreResult(
|
| + &PlatformNotificationContextImpl::DestroyDatabase), this),
|
| + base::Bind(&DoNothing));
|
| +}
|
| +
|
| void PlatformNotificationContextImpl::LazyInitialize(
|
| const base::Closure& success_closure,
|
| const base::Closure& failure_closure) {
|
| @@ -241,24 +266,51 @@ void PlatformNotificationContextImpl::OpenDatabase(
|
| }
|
|
|
| database_.reset(new NotificationDatabase(GetDatabasePath()));
|
| + NotificationDatabase::Status status =
|
| + database_->Open(true /* create_if_missing */);
|
|
|
| // TODO(peter): Record UMA on |status| for opening the database.
|
| - // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
|
|
|
| - NotificationDatabase::Status status =
|
| - database_->Open(true /* create_if_missing */);
|
| + // When the database could not be opened due to corruption, destroy it, blow
|
| + // away the contents of the directory and try re-opening the database.
|
| + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
|
| + if (DestroyDatabase()) {
|
| + status = database_->Open(true /* create_if_missing */);
|
| +
|
| + // TODO(peter): Record UMA on |status| for re-opening the database after
|
| + // corruption was detected.
|
| + }
|
| + }
|
|
|
| if (status == NotificationDatabase::STATUS_OK) {
|
| success_closure.Run();
|
| return;
|
| }
|
|
|
| - // TODO(peter): Properly handle failures when opening the database.
|
| database_.reset();
|
|
|
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure);
|
| }
|
|
|
| +bool PlatformNotificationContextImpl::DestroyDatabase() {
|
| + DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| + DCHECK(database_);
|
| +
|
| + // TODO(peter): Record UMA on the status code of the Destroy() call.
|
| + database_->Destroy();
|
| + database_.reset();
|
| +
|
| + // TODO(peter): Close any existing persistent notifications on the platform.
|
| +
|
| + // Remove all files in the directory that the database was previously located
|
| + // in, to make sure that any left-over files are gone as well.
|
| + base::FilePath database_path = GetDatabasePath();
|
| + if (!database_path.empty())
|
| + return base::DeleteFile(database_path, true);
|
| +
|
| + return true;
|
| +}
|
| +
|
| base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const {
|
| if (path_.empty())
|
| return path_;
|
|
|