Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1159)

Side by Side Diff: content/browser/notifications/platform_notification_context_impl.cc

Issue 1024463006: Destroy the notification database when corruption occurs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@n-db-SWContextObserver
Patch Set: rebase Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 &notification_id); 140 &notification_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698