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

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

Issue 411793004: More fine-grained pruning in safe browsing incident reporting service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: extract incident-specific code into its own file Created 6 years, 4 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> 9 #include <algorithm>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h" 13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
14 #include "base/process/process_info.h" 15 #include "base/process/process_info.h"
15 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
16 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/values.h"
17 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" 22 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
20 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/safe_browsing/database_manager.h" 24 #include "chrome/browser/safe_browsing/database_manager.h"
22 #include "chrome/browser/safe_browsing/environment_data_collection.h" 25 #include "chrome/browser/safe_browsing/environment_data_collection.h"
23 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" 26 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h"
24 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" 27 #include "chrome/browser/safe_browsing/preference_validation_delegate.h"
25 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 28 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
29 #include "chrome/browser/safe_browsing/tracked_preference_incident_handlers.h"
26 #include "chrome/common/pref_names.h" 30 #include "chrome/common/pref_names.h"
27 #include "chrome/common/safe_browsing/csd.pb.h" 31 #include "chrome/common/safe_browsing/csd.pb.h"
28 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/notification_service.h"
30 #include "net/url_request/url_request_context_getter.h" 34 #include "net/url_request/url_request_context_getter.h"
31 35
32 namespace safe_browsing { 36 namespace safe_browsing {
33 37
34 namespace { 38 namespace {
35 39
40 // The type of an incident. Used for user metrics and for pruning of
41 // previously-reported incidents.
36 enum IncidentType { 42 enum IncidentType {
37 // Start with 1 rather than zero; otherwise there won't be enough buckets for 43 // Start with 1 rather than zero; otherwise there won't be enough buckets for
38 // the histogram. 44 // the histogram.
39 TRACKED_PREFERENCE = 1, 45 TRACKED_PREFERENCE = 1,
46 // Values for new incident types go here.
40 NUM_INCIDENT_TYPES 47 NUM_INCIDENT_TYPES
41 }; 48 };
42 49
50 // The action taken for an incident; used for user metrics (see
51 // LogIncidentDataType).
43 enum IncidentDisposition { 52 enum IncidentDisposition {
44 DROPPED, 53 DROPPED,
45 ACCEPTED, 54 ACCEPTED,
46 }; 55 };
47 56
57 // The state persisted for a specific instance of an incident to enable pruning
58 // of previously-reported incidents.
59 struct PersistentIncidentState {
60 // The type of the incident.
61 IncidentType type;
62
63 // The key for a specific instance of an incident.
64 std::string key;
65
66 // A hash digest representing a specific instance of an incident.
67 uint32_t digest;
68 };
69
70 // Handlers for a specific type of incident.
71 struct IncidentTypeHandlers {
72 // The type of incident to which these handlers apply.
73 IncidentType type;
74
75 // A pointer to the has_*() method on IncidentData that tests for the presence
76 // of the incident payload for this type.
77 bool (ClientIncidentReport_IncidentData::*has_type_fn)(void) const;
78
79 // A function that returns a unique key representing an incident.
80 std::string (*get_key_fn)(const ClientIncidentReport_IncidentData&);
81
82 // A function that returns a hash digest of an incident's data.
83 uint32_t (*get_digest_fn)(const ClientIncidentReport_IncidentData&);
84 };
85
86 // The collection of handlers for all incident types.
87 const IncidentTypeHandlers kIncidentTypeHandlers[] = {
88 {TRACKED_PREFERENCE,
89 &ClientIncidentReport_IncidentData::has_tracked_preference,
90 &GetTrackedPreferenceIncidentKey,
91 &GetTrackedPreferenceIncidentDigest},
92 // Handler definitions for new incident types go here.
93 };
94
95 // The amount of time the service will wait to collate incidents.
48 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 96 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
49 97
98 // Returns the number of incidents contained in |incident|. The result is
99 // expected to be 1. Used in DCHECKs.
100 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) {
101 size_t result = 0;
102 for (size_t i = 0; i < arraysize(kIncidentTypeHandlers); ++i) {
103 if ((incident.*kIncidentTypeHandlers[i].has_type_fn)())
Scott Hess - ex-Googler 2014/07/24 21:22:20 This is wow. And I'm not sure there are alternati
grt (UTC plus 2) 2014/07/24 22:58:12 i was making use of the .* operator here which tak
104 ++result;
105 }
106 return result;
107 }
108
109 // Returns the type of incident contained in |incident_data|.
110 IncidentType GetIncidentType(
111 const ClientIncidentReport_IncidentData& incident_data) {
112 for (size_t i = 0; i < arraysize(kIncidentTypeHandlers); ++i) {
113 if ((incident_data.*kIncidentTypeHandlers[i].has_type_fn)())
114 return kIncidentTypeHandlers[i].type;
115 }
116 NOTREACHED();
117 return NUM_INCIDENT_TYPES;
118 }
119
120 // Returns the handlers for a given type of incident.
121 const IncidentTypeHandlers* GetIncidentTypeHandlers(IncidentType type) {
122 for (size_t i = 0; i < arraysize(kIncidentTypeHandlers); ++i) {
123 if (kIncidentTypeHandlers[i].type == type)
124 return &kIncidentTypeHandlers[i];
125 }
126 NOTREACHED();
127 return NULL;
128 }
129
130 // Logs the type of incident in |incident_data| to a user metrics histogram.
50 void LogIncidentDataType( 131 void LogIncidentDataType(
51 IncidentDisposition disposition, 132 IncidentDisposition disposition,
52 const ClientIncidentReport_IncidentData& incident_data) { 133 const ClientIncidentReport_IncidentData& incident_data) {
53 IncidentType type = TRACKED_PREFERENCE; 134 IncidentType type = GetIncidentType(incident_data);
54
55 // Add a switch statement once other types are supported.
56 DCHECK(incident_data.has_tracked_preference());
57
58 if (disposition == ACCEPTED) { 135 if (disposition == ACCEPTED) {
59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); 136 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES);
60 } else { 137 } else {
61 DCHECK_EQ(disposition, DROPPED); 138 DCHECK_EQ(disposition, DROPPED);
62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, 139 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type,
63 NUM_INCIDENT_TYPES); 140 NUM_INCIDENT_TYPES);
64 } 141 }
65 } 142 }
66 143
144 // Computes the persistent state for an incident.
145 PersistentIncidentState ComputeIncidentState(
146 const ClientIncidentReport_IncidentData& incident) {
147 PersistentIncidentState state;
148
149 state.type = GetIncidentType(incident);
150 const IncidentTypeHandlers* handlers = GetIncidentTypeHandlers(state.type);
151 state.key = handlers->get_key_fn(incident);
152 state.digest = handlers->get_digest_fn(incident);
153
154 return state;
155 }
156
157 // Returns true if the incident described by |state| has already been reported
158 // based on the bookkeeping in the |incidents_sent| preference dictionary.
159 bool IncidentHasBeenReported(const base::DictionaryValue* incidents_sent,
160 const PersistentIncidentState& state) {
161 const base::DictionaryValue* type_dict = NULL;
162 std::string digest_string;
163 return (incidents_sent &&
164 incidents_sent->GetDictionaryWithoutPathExpansion(
165 base::IntToString(state.type), &type_dict) &&
166 type_dict->GetStringWithoutPathExpansion(state.key, &digest_string) &&
167 digest_string == base::UintToString(state.digest));
168 }
169
170 // Marks the incidents described by |states| as having been reported
171 // in |incidents_set|.
172 void MarkIncidentsAsReported(const std::vector<PersistentIncidentState>& states,
173 base::DictionaryValue* incidents_sent) {
174 for (size_t i = 0; i < states.size(); ++i) {
175 const PersistentIncidentState& data = states[i];
176 base::DictionaryValue* type_dict = NULL;
177 const std::string type_string(base::IntToString(data.type));
178 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
179 &type_dict)) {
180 type_dict = new base::DictionaryValue();
181 incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
182 }
183 type_dict->SetStringWithoutPathExpansion(data.key,
184 base::UintToString(data.digest));
185 }
186 }
187
67 } // namespace 188 } // namespace
68 189
69 struct IncidentReportingService::ProfileContext { 190 struct IncidentReportingService::ProfileContext {
70 ProfileContext(); 191 ProfileContext();
71 ~ProfileContext(); 192 ~ProfileContext();
72 193
73 // The incidents collected for this profile pending creation and/or upload. 194 // The incidents collected for this profile pending creation and/or upload.
74 ScopedVector<ClientIncidentReport_IncidentData> incidents; 195 ScopedVector<ClientIncidentReport_IncidentData> incidents;
75 196
76 // False until PROFILE_ADDED notification is received. 197 // False until PROFILE_ADDED notification is received.
77 bool added; 198 bool added;
78 199
79 private: 200 private:
80 DISALLOW_COPY_AND_ASSIGN(ProfileContext); 201 DISALLOW_COPY_AND_ASSIGN(ProfileContext);
81 }; 202 };
82 203
83 class IncidentReportingService::UploadContext { 204 class IncidentReportingService::UploadContext {
84 public: 205 public:
206 typedef std::map<Profile*, std::vector<PersistentIncidentState> >
207 PersistentIncidentStateCollection;
208
85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); 209 explicit UploadContext(scoped_ptr<ClientIncidentReport> report);
86 ~UploadContext(); 210 ~UploadContext();
87 211
88 // The report being uploaded. 212 // The report being uploaded.
89 scoped_ptr<ClientIncidentReport> report; 213 scoped_ptr<ClientIncidentReport> report;
90 214
91 // The uploader in use. This is NULL until the CSD killswitch is checked. 215 // The uploader in use. This is NULL until the CSD killswitch is checked.
92 scoped_ptr<IncidentReportUploader> uploader; 216 scoped_ptr<IncidentReportUploader> uploader;
93 217
94 // The set of profiles from which incidents in |report| originated. 218 // A mapping of profiles to the data to be persisted upon successful upload.
95 std::vector<Profile*> profiles; 219 PersistentIncidentStateCollection profiles_to_state;
96 220
97 private: 221 private:
98 DISALLOW_COPY_AND_ASSIGN(UploadContext); 222 DISALLOW_COPY_AND_ASSIGN(UploadContext);
99 }; 223 };
100 224
101 IncidentReportingService::ProfileContext::ProfileContext() : added() { 225 IncidentReportingService::ProfileContext::ProfileContext() : added() {
102 } 226 }
103 227
104 IncidentReportingService::ProfileContext::~ProfileContext() { 228 IncidentReportingService::ProfileContext::~ProfileContext() {
105 } 229 }
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if (it == profiles_.end()) 378 if (it == profiles_.end())
255 return; 379 return;
256 380
257 // TODO(grt): Persist incidents for upload on future profile load. 381 // TODO(grt): Persist incidents for upload on future profile load.
258 382
259 // Forget about this profile. Incidents not yet sent for upload are lost. 383 // Forget about this profile. Incidents not yet sent for upload are lost.
260 // No new incidents will be accepted for it. 384 // No new incidents will be accepted for it.
261 delete it->second; 385 delete it->second;
262 profiles_.erase(it); 386 profiles_.erase(it);
263 387
264 // Remove the association with this profile from any pending uploads. 388 // Remove the association with this profile from all pending uploads.
265 for (size_t i = 0; i < uploads_.size(); ++i) { 389 for (size_t i = 0; i < uploads_.size(); ++i)
266 UploadContext* upload = uploads_[i]; 390 uploads_[i]->profiles_to_state.erase(profile);
267 std::vector<Profile*>::iterator it =
268 std::find(upload->profiles.begin(), upload->profiles.end(), profile);
269 if (it != upload->profiles.end()) {
270 *it = upload->profiles.back();
271 upload->profiles.resize(upload->profiles.size() - 1);
272 break;
273 }
274 }
275 } 391 }
276 392
277 void IncidentReportingService::AddIncident( 393 void IncidentReportingService::AddIncident(
278 Profile* profile, 394 Profile* profile,
279 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 395 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
280 DCHECK(thread_checker_.CalledOnValidThread()); 396 DCHECK(thread_checker_.CalledOnValidThread());
281 // Incidents outside the context of a profile are not supported at the moment. 397 // Incidents outside the context of a profile are not supported at the moment.
282 DCHECK(profile); 398 DCHECK(profile);
399 DCHECK_EQ(1U, CountIncidents(*incident_data));
283 400
284 ProfileContext* context = GetProfileContext(profile); 401 ProfileContext* context = GetProfileContext(profile);
285 // It is forbidden to call this function with a destroyed profile. 402 // It is forbidden to call this function with a destroyed profile.
286 DCHECK(context); 403 DCHECK(context);
287 404
288 // Drop the incident immediately if profile creation has completed and the 405 // Drop the incident immediately if profile creation has completed and the
289 // profile is not participating in safe browsing. Preference evaluation is 406 // profile is not participating in safe browsing. Preference evaluation is
290 // deferred until OnProfileAdded() if profile creation has not yet 407 // deferred until OnProfileAdded() if profile creation has not yet
291 // completed. 408 // completed.
292 if (context->added && 409 if (context->added &&
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 if (g_browser_process->local_state()->FindPreference( 626 if (g_browser_process->local_state()->FindPreference(
510 prefs::kMetricsReportingEnabled)) { 627 prefs::kMetricsReportingEnabled)) {
511 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 628 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
512 prefs::kMetricsReportingEnabled)); 629 prefs::kMetricsReportingEnabled));
513 } 630 }
514 631
515 // Check for extended consent in any profile while collecting incidents. 632 // Check for extended consent in any profile while collecting incidents.
516 process->set_extended_consent(false); 633 process->set_extended_consent(false);
517 // Collect incidents across all profiles participating in safe browsing. Drop 634 // Collect incidents across all profiles participating in safe browsing. Drop
518 // incidents if the profile stopped participating before collection completed. 635 // incidents if the profile stopped participating before collection completed.
519 // Prune incidents if the profile has already submitted any incidents. 636 // Prune previously submitted incidents.
520 // Associate the participating profiles with the upload. 637 // Associate the profiles and their incident data with the upload.
521 size_t prune_count = 0; 638 size_t prune_count = 0;
522 std::vector<Profile*> profiles; 639 UploadContext::PersistentIncidentStateCollection profiles_to_state;
523 for (ProfileContextCollection::iterator scan = profiles_.begin(); 640 for (ProfileContextCollection::iterator scan = profiles_.begin();
524 scan != profiles_.end(); 641 scan != profiles_.end();
525 ++scan) { 642 ++scan) {
526 PrefService* prefs = scan->first->GetPrefs(); 643 PrefService* prefs = scan->first->GetPrefs();
527 if (process && 644 if (process &&
528 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { 645 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
529 process->set_extended_consent(true); 646 process->set_extended_consent(true);
530 process = NULL; // Don't check any more once one is found. 647 process = NULL; // Don't check any more once one is found.
531 } 648 }
532 ProfileContext* context = scan->second; 649 ProfileContext* context = scan->second;
533 if (context->incidents.empty()) 650 if (context->incidents.empty())
534 continue; 651 continue;
535 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 652 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
536 for (size_t i = 0; i < context->incidents.size(); ++i) { 653 for (size_t i = 0; i < context->incidents.size(); ++i) {
537 LogIncidentDataType(DROPPED, *context->incidents[i]); 654 LogIncidentDataType(DROPPED, *context->incidents[i]);
538 } 655 }
539 context->incidents.clear(); 656 context->incidents.clear();
540 } else if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) { 657 continue;
541 // Prune all incidents. 658 }
542 // TODO(grt): Only prune previously submitted incidents; 659 std::vector<PersistentIncidentState> states;
543 // http://crbug.com/383043. 660 const base::DictionaryValue* incidents_sent =
544 prune_count += context->incidents.size(); 661 prefs->GetDictionary(prefs::kSafeBrowsingIncidentsSent);
662 // Prep persistent data and prune any incidents already sent.
663 for (size_t i = 0; i < context->incidents.size(); ++i) {
664 ClientIncidentReport_IncidentData* incident = context->incidents[i];
665 const PersistentIncidentState state = ComputeIncidentState(*incident);
666 if (IncidentHasBeenReported(incidents_sent, state)) {
667 ++prune_count;
668 delete context->incidents[i];
669 context->incidents[i] = NULL;
670 } else {
671 states.push_back(state);
672 }
673 }
674 if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) {
675 // Prune all incidents as if they had been reported, migrating to the new
676 // technique. TODO(grt): remove this branch after it has shipped.
677 for (size_t i = 0; i < context->incidents.size(); ++i) {
678 if (context->incidents[i])
679 ++prune_count;
680 }
545 context->incidents.clear(); 681 context->incidents.clear();
682 prefs->ClearPref(prefs::kSafeBrowsingIncidentReportSent);
683 DictionaryPrefUpdate pref_update(prefs,
684 prefs::kSafeBrowsingIncidentsSent);
685 MarkIncidentsAsReported(states, pref_update.Get());
546 } else { 686 } else {
547 for (size_t i = 0; i < context->incidents.size(); ++i) { 687 for (size_t i = 0; i < context->incidents.size(); ++i) {
548 ClientIncidentReport_IncidentData* incident = context->incidents[i]; 688 ClientIncidentReport_IncidentData* incident = context->incidents[i];
549 LogIncidentDataType(ACCEPTED, *incident); 689 if (incident) {
550 // Ownership of the incident is passed to the report. 690 LogIncidentDataType(ACCEPTED, *incident);
551 report->mutable_incident()->AddAllocated(incident); 691 // Ownership of the incident is passed to the report.
692 report->mutable_incident()->AddAllocated(incident);
693 }
552 } 694 }
553 context->incidents.weak_clear(); 695 context->incidents.weak_clear();
554 profiles.push_back(scan->first); 696 std::vector<PersistentIncidentState>& profile_states =
697 profiles_to_state[scan->first];
698 profile_states.swap(states);
555 } 699 }
556 } 700 }
557 701
558 const int count = report->incident_size(); 702 const int count = report->incident_size();
559 // Abandon the request if all incidents were dropped with none pruned. 703 // Abandon the request if all incidents were dropped with none pruned.
560 if (!count && !prune_count) 704 if (!count && !prune_count)
561 return; 705 return;
562 706
563 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count); 707 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count);
564 708
565 { 709 {
566 double prune_pct = static_cast<double>(prune_count); 710 double prune_pct = static_cast<double>(prune_count);
567 prune_pct = prune_pct * 100.0 / (count + prune_count); 711 prune_pct = prune_pct * 100.0 / (count + prune_count);
568 prune_pct = round(prune_pct); 712 prune_pct = round(prune_pct);
569 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); 713 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct));
570 } 714 }
571 // Abandon the report if all incidents were pruned. 715 // Abandon the report if all incidents were pruned.
572 if (!count) 716 if (!count)
573 return; 717 return;
574 718
575 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); 719 scoped_ptr<UploadContext> context(new UploadContext(report.Pass()));
576 context->profiles.swap(profiles); 720 context->profiles_to_state.swap(profiles_to_state);
577 if (!database_manager_) { 721 if (!database_manager_) {
578 // No database manager during testing. Take ownership of the context and 722 // No database manager during testing. Take ownership of the context and
579 // continue processing. 723 // continue processing.
580 UploadContext* temp_context = context.get(); 724 UploadContext* temp_context = context.get();
581 uploads_.push_back(context.release()); 725 uploads_.push_back(context.release());
582 IncidentReportingService::OnKillSwitchResult(temp_context, false); 726 IncidentReportingService::OnKillSwitchResult(temp_context, false);
583 } else { 727 } else {
584 if (content::BrowserThread::PostTaskAndReplyWithResult( 728 if (content::BrowserThread::PostTaskAndReplyWithResult(
585 content::BrowserThread::IO, 729 content::BrowserThread::IO,
586 FROM_HERE, 730 FROM_HERE,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 scoped_ptr<ClientIncidentResponse>()); 765 scoped_ptr<ClientIncidentResponse>());
622 } 766 }
623 } else { 767 } else {
624 OnReportUploadResult(context, 768 OnReportUploadResult(context,
625 IncidentReportUploader::UPLOAD_SUPPRESSED, 769 IncidentReportUploader::UPLOAD_SUPPRESSED,
626 scoped_ptr<ClientIncidentResponse>()); 770 scoped_ptr<ClientIncidentResponse>());
627 } 771 }
628 } 772 }
629 773
630 void IncidentReportingService::HandleResponse(const UploadContext& context) { 774 void IncidentReportingService::HandleResponse(const UploadContext& context) {
631 for (size_t i = 0; i < context.profiles.size(); ++i) { 775 for (UploadContext::PersistentIncidentStateCollection::const_iterator scan =
632 context.profiles[i]->GetPrefs()->SetBoolean( 776 context.profiles_to_state.begin();
633 prefs::kSafeBrowsingIncidentReportSent, true); 777 scan != context.profiles_to_state.end();
778 ++scan) {
779 DictionaryPrefUpdate pref_update(scan->first->GetPrefs(),
780 prefs::kSafeBrowsingIncidentsSent);
781 MarkIncidentsAsReported(scan->second, pref_update.Get());
634 } 782 }
635 } 783 }
636 784
637 void IncidentReportingService::OnReportUploadResult( 785 void IncidentReportingService::OnReportUploadResult(
638 UploadContext* context, 786 UploadContext* context,
639 IncidentReportUploader::Result result, 787 IncidentReportUploader::Result result,
640 scoped_ptr<ClientIncidentResponse> response) { 788 scoped_ptr<ClientIncidentResponse> response) {
641 DCHECK(thread_checker_.CalledOnValidThread()); 789 DCHECK(thread_checker_.CalledOnValidThread());
642 790
643 UMA_HISTOGRAM_ENUMERATION( 791 UMA_HISTOGRAM_ENUMERATION(
(...skipping 29 matching lines...) Expand all
673 if (!profile->IsOffTheRecord()) 821 if (!profile->IsOffTheRecord())
674 OnProfileDestroyed(profile); 822 OnProfileDestroyed(profile);
675 break; 823 break;
676 } 824 }
677 default: 825 default:
678 break; 826 break;
679 } 827 }
680 } 828 }
681 829
682 } // namespace safe_browsing 830 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698