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

Side by Side Diff: chrome/browser/safe_browsing/incident_reporting_service.cc

Issue 348433004: Prune all safe browsing incidents when already reported. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: path string fix for non-win platforms Created 6 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "chrome/browser/safe_browsing/incident_reporting_service.h" 5 #include "chrome/browser/safe_browsing/incident_reporting_service.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm>
10 #include <vector>
11
9 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
10 #include "base/prefs/pref_service.h" 13 #include "base/prefs/pref_service.h"
11 #include "base/process/process_info.h" 14 #include "base/process/process_info.h"
12 #include "base/stl_util.h" 15 #include "base/stl_util.h"
13 #include "base/threading/sequenced_worker_pool.h" 16 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/browser_process.h" 17 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" 19 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
17 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/safe_browsing/database_manager.h" 21 #include "chrome/browser/safe_browsing/database_manager.h"
(...skipping 21 matching lines...) Expand all
40 enum IncidentDisposition { 43 enum IncidentDisposition {
41 DROPPED, 44 DROPPED,
42 ACCEPTED, 45 ACCEPTED,
43 }; 46 };
44 47
45 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 48 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
46 49
47 void LogIncidentDataType( 50 void LogIncidentDataType(
48 IncidentDisposition disposition, 51 IncidentDisposition disposition,
49 const ClientIncidentReport_IncidentData& incident_data) { 52 const ClientIncidentReport_IncidentData& incident_data) {
50 static const char kAcceptedMetric[] = "SBIRS.Incident";
51 static const char kDroppedMetric[] = "SBIRS.DroppedIncident";
52
53 IncidentType type = TRACKED_PREFERENCE; 53 IncidentType type = TRACKED_PREFERENCE;
54 54
55 // Add a switch statement once other types are supported. 55 // Add a switch statement once other types are supported.
56 DCHECK(incident_data.has_tracked_preference()); 56 DCHECK(incident_data.has_tracked_preference());
57 57
58 if (disposition == ACCEPTED) { 58 if (disposition == ACCEPTED) {
59 UMA_HISTOGRAM_ENUMERATION(kAcceptedMetric, type, NUM_INCIDENT_TYPES); 59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES);
60 } else { 60 } else {
61 DCHECK_EQ(disposition, DROPPED); 61 DCHECK_EQ(disposition, DROPPED);
62 UMA_HISTOGRAM_ENUMERATION(kDroppedMetric, type, NUM_INCIDENT_TYPES); 62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type,
63 NUM_INCIDENT_TYPES);
63 } 64 }
64 } 65 }
65 66
66 } // namespace 67 } // namespace
67 68
68 struct IncidentReportingService::ProfileContext { 69 struct IncidentReportingService::ProfileContext {
69 ProfileContext(); 70 ProfileContext();
70 ~ProfileContext(); 71 ~ProfileContext();
71 72
72 // The incidents collected for this profile pending creation and/or upload. 73 // The incidents collected for this profile pending creation and/or upload.
73 ScopedVector<ClientIncidentReport_IncidentData> incidents; 74 ScopedVector<ClientIncidentReport_IncidentData> incidents;
74 75
75 // False until PROFILE_CREATED notification is received. 76 // False until PROFILE_CREATED notification is received.
76 bool created; 77 bool created;
77 78
78 private: 79 private:
79 DISALLOW_COPY_AND_ASSIGN(ProfileContext); 80 DISALLOW_COPY_AND_ASSIGN(ProfileContext);
80 }; 81 };
81 82
82 class IncidentReportingService::UploadContext { 83 class IncidentReportingService::UploadContext {
83 public: 84 public:
84 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); 85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report);
85 ~UploadContext(); 86 ~UploadContext();
86 87
88 // The report being uploaded.
87 scoped_ptr<ClientIncidentReport> report; 89 scoped_ptr<ClientIncidentReport> report;
90
91 // The uploader in use. This is NULL until the CSD killswitch is checked.
88 scoped_ptr<IncidentReportUploader> uploader; 92 scoped_ptr<IncidentReportUploader> uploader;
89 93
94 // The set of profiles from which incidents in |report| originated.
95 std::vector<Profile*> profiles;
96
90 private: 97 private:
91 DISALLOW_COPY_AND_ASSIGN(UploadContext); 98 DISALLOW_COPY_AND_ASSIGN(UploadContext);
92 }; 99 };
93 100
94 IncidentReportingService::ProfileContext::ProfileContext() : created() { 101 IncidentReportingService::ProfileContext::ProfileContext() : created() {
95 } 102 }
96 103
97 IncidentReportingService::ProfileContext::~ProfileContext() { 104 IncidentReportingService::ProfileContext::~ProfileContext() {
98 } 105 }
99 106
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 ProfileContextCollection::iterator it = profiles_.find(profile); 239 ProfileContextCollection::iterator it = profiles_.find(profile);
233 if (it == profiles_.end()) 240 if (it == profiles_.end())
234 return; 241 return;
235 242
236 // TODO(grt): Persist incidents for upload on future profile load. 243 // TODO(grt): Persist incidents for upload on future profile load.
237 244
238 // Forget about this profile. Incidents not yet sent for upload are lost. 245 // Forget about this profile. Incidents not yet sent for upload are lost.
239 // No new incidents will be accepted for it. 246 // No new incidents will be accepted for it.
240 delete it->second; 247 delete it->second;
241 profiles_.erase(it); 248 profiles_.erase(it);
249
250 // Remove the association with this profile from any pending uploads.
251 for (size_t i = 0; i < uploads_.size(); ++i) {
252 UploadContext* upload = uploads_[i];
253 std::vector<Profile*>::iterator it =
254 std::find(upload->profiles.begin(), upload->profiles.end(), profile);
255 if (it != upload->profiles.end()) {
256 *it = upload->profiles.back();
257 upload->profiles.resize(upload->profiles.size() - 1);
258 break;
259 }
260 }
242 } 261 }
243 262
244 void IncidentReportingService::AddIncident( 263 void IncidentReportingService::AddIncident(
245 Profile* profile, 264 Profile* profile,
246 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 265 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
247 DCHECK(thread_checker_.CalledOnValidThread()); 266 DCHECK(thread_checker_.CalledOnValidThread());
248 // Incidents outside the context of a profile are not supported at the moment. 267 // Incidents outside the context of a profile are not supported at the moment.
249 DCHECK(profile); 268 DCHECK(profile);
250 269
251 ProfileContext* context = GetProfileContext(profile); 270 ProfileContext* context = GetProfileContext(profile);
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 389
371 UploadIfCollectionComplete(); 390 UploadIfCollectionComplete();
372 } 391 }
373 392
374 void IncidentReportingService::CollectDownloadDetails( 393 void IncidentReportingService::CollectDownloadDetails(
375 ClientIncidentReport_DownloadDetails* download_details) { 394 ClientIncidentReport_DownloadDetails* download_details) {
376 DCHECK(thread_checker_.CalledOnValidThread()); 395 DCHECK(thread_checker_.CalledOnValidThread());
377 // TODO(grt): collect download info; http://crbug.com/383042. 396 // TODO(grt): collect download info; http://crbug.com/383042.
378 } 397 }
379 398
380 void IncidentReportingService::RecordReportedIncidents() {
381 // TODO(grt): store state about reported incidents.
382 }
383
384 void IncidentReportingService::PruneReportedIncidents(
385 ClientIncidentReport* report) {
386 // TODO(grt): remove previously reported incidents; http://crbug.com/383043.
387 }
388
389 void IncidentReportingService::UploadIfCollectionComplete() { 399 void IncidentReportingService::UploadIfCollectionComplete() {
390 DCHECK(report_); 400 DCHECK(report_);
391 // Bail out if there are still outstanding collection tasks. 401 // Bail out if there are still outstanding collection tasks.
392 if (environment_collection_pending_ || collection_timeout_pending_) 402 if (environment_collection_pending_ || collection_timeout_pending_)
393 return; 403 return;
394 404
395 // Take ownership of the report and clear things for future reports. 405 // Take ownership of the report and clear things for future reports.
396 scoped_ptr<ClientIncidentReport> report(report_.Pass()); 406 scoped_ptr<ClientIncidentReport> report(report_.Pass());
397 last_incident_time_ = base::TimeTicks(); 407 last_incident_time_ = base::TimeTicks();
398 408
399 ClientIncidentReport_EnvironmentData_Process* process = 409 ClientIncidentReport_EnvironmentData_Process* process =
400 report->mutable_environment()->mutable_process(); 410 report->mutable_environment()->mutable_process();
401 411
402 // Not all platforms have a metrics reporting preference. 412 // Not all platforms have a metrics reporting preference.
403 if (g_browser_process->local_state()->FindPreference( 413 if (g_browser_process->local_state()->FindPreference(
404 prefs::kMetricsReportingEnabled)) { 414 prefs::kMetricsReportingEnabled)) {
405 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 415 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
406 prefs::kMetricsReportingEnabled)); 416 prefs::kMetricsReportingEnabled));
407 } 417 }
418
408 // Check for extended consent in any profile while collecting incidents. 419 // Check for extended consent in any profile while collecting incidents.
409 process->set_extended_consent(false); 420 process->set_extended_consent(false);
410 // Collect incidents across all profiles participating in safe browsing. Drop 421 // Collect incidents across all profiles participating in safe browsing. Drop
411 // incidents if the profile stopped participating before collection completed. 422 // incidents if the profile stopped participating before collection completed.
423 // Prune incidents if the profile has already submitted any incidents.
424 // Associate the participating profiles with the upload.
425 size_t prune_count = 0;
426 std::vector<Profile*> profiles;
412 for (ProfileContextCollection::iterator scan = profiles_.begin(); 427 for (ProfileContextCollection::iterator scan = profiles_.begin();
413 scan != profiles_.end(); 428 scan != profiles_.end();
414 ++scan) { 429 ++scan) {
415 PrefService* prefs = scan->first->GetPrefs(); 430 PrefService* prefs = scan->first->GetPrefs();
416 if (process && 431 if (process &&
417 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { 432 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
418 process->set_extended_consent(true); 433 process->set_extended_consent(true);
419 process = NULL; // Don't check any more once one is found. 434 process = NULL; // Don't check any more once one is found.
420 } 435 }
421 ProfileContext* context = scan->second; 436 ProfileContext* context = scan->second;
422 if (context->incidents.empty()) 437 if (context->incidents.empty())
423 continue; 438 continue;
424 if (prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 439 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
440 for (size_t i = 0; i < context->incidents.size(); ++i) {
441 LogIncidentDataType(DROPPED, *context->incidents[i]);
442 }
443 context->incidents.clear();
444 } else if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) {
445 // Prune all incidents.
446 // TODO(grt): Only prune previously submitted incidents;
447 // http://crbug.com/383043.
448 prune_count += context->incidents.size();
449 context->incidents.clear();
450 } else {
425 for (size_t i = 0; i < context->incidents.size(); ++i) { 451 for (size_t i = 0; i < context->incidents.size(); ++i) {
426 ClientIncidentReport_IncidentData* incident = context->incidents[i]; 452 ClientIncidentReport_IncidentData* incident = context->incidents[i];
427 LogIncidentDataType(ACCEPTED, *incident); 453 LogIncidentDataType(ACCEPTED, *incident);
428 // Ownership of the incident is passed to the report. 454 // Ownership of the incident is passed to the report.
429 report->mutable_incident()->AddAllocated(incident); 455 report->mutable_incident()->AddAllocated(incident);
430 } 456 }
431 context->incidents.weak_clear(); 457 context->incidents.weak_clear();
432 } else { 458 profiles.push_back(scan->first);
433 for (size_t i = 0; i < context->incidents.size(); ++i) {
434 LogIncidentDataType(DROPPED, *context->incidents[i]);
435 }
436 context->incidents.clear();
437 } 459 }
438 } 460 }
439 461
440 const int original_count = report->incident_size(); 462 const int count = report->incident_size();
441 // Abandon the request if all incidents were dropped. 463 // Abandon the request if all incidents were dropped with none pruned.
442 if (!original_count) 464 if (!count && !prune_count)
443 return; 465 return;
444 466
445 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", original_count); 467 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count);
446 468
447 PruneReportedIncidents(report.get());
448
449 int final_count = report->incident_size();
450 { 469 {
451 double prune_pct = static_cast<double>(original_count - final_count); 470 double prune_pct = static_cast<double>(prune_count);
452 prune_pct = prune_pct * 100.0 / original_count; 471 prune_pct = prune_pct * 100.0 / (count + prune_count);
453 prune_pct = round(prune_pct); 472 prune_pct = round(prune_pct);
454 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); 473 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct));
455 } 474 }
456 // Abandon the report if all incidents were pruned. 475 // Abandon the report if all incidents were pruned.
457 if (!final_count) 476 if (!count)
458 return; 477 return;
459 478
460 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); 479 scoped_ptr<UploadContext> context(new UploadContext(report.Pass()));
480 context->profiles.swap(profiles);
461 if (!database_manager_) { 481 if (!database_manager_) {
462 // No database manager during testing. Take ownership of the context and 482 // No database manager during testing. Take ownership of the context and
463 // continue processing. 483 // continue processing.
464 UploadContext* temp_context = context.get(); 484 UploadContext* temp_context = context.get();
465 uploads_.push_back(context.release()); 485 uploads_.push_back(context.release());
466 IncidentReportingService::OnKillSwitchResult(temp_context, false); 486 IncidentReportingService::OnKillSwitchResult(temp_context, false);
467 } else { 487 } else {
468 if (content::BrowserThread::PostTaskAndReplyWithResult( 488 if (content::BrowserThread::PostTaskAndReplyWithResult(
469 content::BrowserThread::IO, 489 content::BrowserThread::IO,
470 FROM_HERE, 490 FROM_HERE,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 IncidentReportUploader::UPLOAD_INVALID_REQUEST, 524 IncidentReportUploader::UPLOAD_INVALID_REQUEST,
505 scoped_ptr<ClientIncidentResponse>()); 525 scoped_ptr<ClientIncidentResponse>());
506 } 526 }
507 } else { 527 } else {
508 OnReportUploadResult(context, 528 OnReportUploadResult(context,
509 IncidentReportUploader::UPLOAD_SUPPRESSED, 529 IncidentReportUploader::UPLOAD_SUPPRESSED,
510 scoped_ptr<ClientIncidentResponse>()); 530 scoped_ptr<ClientIncidentResponse>());
511 } 531 }
512 } 532 }
513 533
514 void IncidentReportingService::HandleResponse( 534 void IncidentReportingService::HandleResponse(const UploadContext& context) {
515 scoped_ptr<ClientIncidentReport> report, 535 for (size_t i = 0; i < context.profiles.size(); ++i) {
516 scoped_ptr<ClientIncidentResponse> response) { 536 context.profiles[i]->GetPrefs()->SetBoolean(
517 RecordReportedIncidents(); 537 prefs::kSafeBrowsingIncidentReportSent, true);
538 }
518 } 539 }
519 540
520 void IncidentReportingService::OnReportUploadResult( 541 void IncidentReportingService::OnReportUploadResult(
521 UploadContext* context, 542 UploadContext* context,
522 IncidentReportUploader::Result result, 543 IncidentReportUploader::Result result,
523 scoped_ptr<ClientIncidentResponse> response) { 544 scoped_ptr<ClientIncidentResponse> response) {
524 DCHECK(thread_checker_.CalledOnValidThread()); 545 DCHECK(thread_checker_.CalledOnValidThread());
525 546
526 UMA_HISTOGRAM_ENUMERATION( 547 UMA_HISTOGRAM_ENUMERATION(
527 "SBIRS.UploadResult", result, IncidentReportUploader::NUM_UPLOAD_RESULTS); 548 "SBIRS.UploadResult", result, IncidentReportUploader::NUM_UPLOAD_RESULTS);
528 549
529 // The upload is no longer outstanding, so take ownership of the context (from 550 // The upload is no longer outstanding, so take ownership of the context (from
530 // the collection of outstanding uploads) in this scope. 551 // the collection of outstanding uploads) in this scope.
531 ScopedVector<UploadContext>::iterator it( 552 ScopedVector<UploadContext>::iterator it(
532 std::find(uploads_.begin(), uploads_.end(), context)); 553 std::find(uploads_.begin(), uploads_.end(), context));
533 DCHECK(it != uploads_.end()); 554 DCHECK(it != uploads_.end());
534 scoped_ptr<UploadContext> upload(context); // == *it 555 scoped_ptr<UploadContext> upload(context); // == *it
535 *it = uploads_.back(); 556 *it = uploads_.back();
536 uploads_.weak_erase(uploads_.end() - 1); 557 uploads_.weak_erase(uploads_.end() - 1);
537 558
538 if (result == IncidentReportUploader::UPLOAD_SUCCESS) 559 if (result == IncidentReportUploader::UPLOAD_SUCCESS)
539 HandleResponse(upload->report.Pass(), response.Pass()); 560 HandleResponse(*upload);
540 // else retry? 561 // else retry?
541 } 562 }
542 563
543 void IncidentReportingService::Observe( 564 void IncidentReportingService::Observe(
544 int type, 565 int type,
545 const content::NotificationSource& source, 566 const content::NotificationSource& source,
546 const content::NotificationDetails& details) { 567 const content::NotificationDetails& details) {
547 switch (type) { 568 switch (type) {
548 case chrome::NOTIFICATION_PROFILE_CREATED: { 569 case chrome::NOTIFICATION_PROFILE_CREATED: {
549 Profile* profile = content::Source<Profile>(source).ptr(); 570 Profile* profile = content::Source<Profile>(source).ptr();
550 if (!profile->IsOffTheRecord()) 571 if (!profile->IsOffTheRecord())
551 OnProfileCreated(profile); 572 OnProfileCreated(profile);
552 break; 573 break;
553 } 574 }
554 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 575 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
555 Profile* profile = content::Source<Profile>(source).ptr(); 576 Profile* profile = content::Source<Profile>(source).ptr();
556 if (!profile->IsOffTheRecord()) 577 if (!profile->IsOffTheRecord())
557 OnProfileDestroyed(profile); 578 OnProfileDestroyed(profile);
558 break; 579 break;
559 } 580 }
560 default: 581 default:
561 break; 582 break;
562 } 583 }
563 } 584 }
564 585
565 } // namespace safe_browsing 586 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698