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

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: gab comments Created 6 years, 5 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/hash.h"
12 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h" 14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h"
14 #include "base/process/process_info.h" 16 #include "base/process/process_info.h"
15 #include "base/stl_util.h" 17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
16 #include "base/threading/sequenced_worker_pool.h" 19 #include "base/threading/sequenced_worker_pool.h"
20 #include "base/values.h"
17 #include "chrome/browser/browser_process.h" 21 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h" 22 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" 23 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
20 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/safe_browsing/database_manager.h" 25 #include "chrome/browser/safe_browsing/database_manager.h"
22 #include "chrome/browser/safe_browsing/environment_data_collection.h" 26 #include "chrome/browser/safe_browsing/environment_data_collection.h"
23 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" 27 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h"
24 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" 28 #include "chrome/browser/safe_browsing/preference_validation_delegate.h"
25 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 29 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
26 #include "chrome/common/pref_names.h" 30 #include "chrome/common/pref_names.h"
(...skipping 11 matching lines...) Expand all
38 // the histogram. 42 // the histogram.
39 TRACKED_PREFERENCE = 1, 43 TRACKED_PREFERENCE = 1,
40 NUM_INCIDENT_TYPES 44 NUM_INCIDENT_TYPES
41 }; 45 };
42 46
43 enum IncidentDisposition { 47 enum IncidentDisposition {
44 DROPPED, 48 DROPPED,
45 ACCEPTED, 49 ACCEPTED,
46 }; 50 };
47 51
52 // The state persisted for a specific instance of an incident to enable pruning
53 // of previously-reported incidents.
54 struct PersistentIncidentState {
55 // The type of the incident.
56 IncidentType type;
57
58 // The key for a specific instance of an incident.
59 std::string key;
60
61 // A hash digest representing a specific instance of an incident.
62 uint32_t digest;
63 };
Scott Hess - ex-Googler 2014/07/23 22:05:51 Is there any system to how these are organized? T
grt (UTC plus 2) 2014/07/24 18:58:40 I was attempting to roughly follow the declaration
64
48 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 65 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
49 66
67 // Handlers for a specific type of incident.
68 struct IncidentTypeHandlers {
69 // The type of incident to which these handlers apply.
70 IncidentType type;
71
72 // A function that returns a unique key representing an incident.
73 std::string (*get_key_fn)(const ClientIncidentReport_IncidentData&);
74
75 // A function that returns a hash digest of an incident's data.
76 uint32_t (*get_digest_fn)(const ClientIncidentReport_IncidentData&);
77 };
78
79 // Forward declarations of incident type handler functions.
80 std::string GetTrackedPreferenceIncidentKey(
81 const ClientIncidentReport_IncidentData& incident_data);
82 uint32_t GetTrackedPreferenceIncidentDigest(
83 const ClientIncidentReport_IncidentData& incident_data);
84
85 // The collection of handlers for all incident types.
86 const IncidentTypeHandlers kIncidentTypeHandlers[] = {
87 {TRACKED_PREFERENCE,
88 &GetTrackedPreferenceIncidentKey,
89 &GetTrackedPreferenceIncidentDigest},
90 };
91
92 // Returns the type of incident contained in |incident_data|.
93 IncidentType GetIncidentType(
94 const ClientIncidentReport_IncidentData& incident_data) {
95 // Add logic once other types are supported.
96 DCHECK(incident_data.has_tracked_preference());
97
98 return TRACKED_PREFERENCE;
99 }
100
101 // Returns the handlers for a given type of incident.
102 const IncidentTypeHandlers* GetIncidentTypeHandlers(IncidentType type) {
Scott Hess - ex-Googler 2014/07/23 22:05:50 This seems like a kind of elaborate setup to repla
grt (UTC plus 2) 2014/07/24 18:58:40 There will be more incident types in the future. I
Scott Hess - ex-Googler 2014/07/24 21:22:19 I like the tests, my main complaint here was mostl
grt (UTC plus 2) 2014/07/24 22:58:11 You've convinced me. While I liked the idea that d
103 for (size_t i = 0; i < arraysize(kIncidentTypeHandlers); ++i) {
104 if (kIncidentTypeHandlers[i].type == type)
105 return &kIncidentTypeHandlers[i];
106 }
107 NOTREACHED();
108 return NULL;
109 }
110
111 // Computes a simple hash digest over the serialized form of |message|.
112 uint32_t HashMessage(const google::protobuf::MessageLite& message) {
113 std::string message_string;
114 if (!message.SerializeToString(&message_string)) {
115 NOTREACHED();
116 return 0;
117 }
118 return base::Hash(message_string);
119 }
Scott Hess - ex-Googler 2014/07/23 22:05:51 This seems questionable, to me. I think that if y
grt (UTC plus 2) 2014/07/24 18:58:40 Ah, yes. I hadn't thought about optional values wh
Scott Hess - ex-Googler 2014/07/24 21:22:19 It's plausible that the code paths which lead here
grt (UTC plus 2) 2014/07/24 22:58:11 I'm conflicted about this. In the current implemen
120
121 // Returns the path of the tracked preference.
122 std::string GetTrackedPreferenceIncidentKey(
123 const ClientIncidentReport_IncidentData& incident_data) {
124 DCHECK(incident_data.has_tracked_preference());
125 return incident_data.tracked_preference().path();
126 }
127
128 // Returns a digest computed over the tracked preference incident data.
129 uint32_t GetTrackedPreferenceIncidentDigest(
130 const ClientIncidentReport_IncidentData& incident_data) {
131 DCHECK(incident_data.has_tracked_preference());
132 return HashMessage(incident_data.tracked_preference());
133 }
134
135 // Logs the type of incident in |incident_data| to a user metrics histogram.
50 void LogIncidentDataType( 136 void LogIncidentDataType(
51 IncidentDisposition disposition, 137 IncidentDisposition disposition,
52 const ClientIncidentReport_IncidentData& incident_data) { 138 const ClientIncidentReport_IncidentData& incident_data) {
53 IncidentType type = TRACKED_PREFERENCE; 139 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) { 140 if (disposition == ACCEPTED) {
59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); 141 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES);
60 } else { 142 } else {
61 DCHECK_EQ(disposition, DROPPED); 143 DCHECK_EQ(disposition, DROPPED);
62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, 144 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type,
63 NUM_INCIDENT_TYPES); 145 NUM_INCIDENT_TYPES);
64 } 146 }
65 } 147 }
66 148
149 // Computes the persistent state for an incident.
150 PersistentIncidentState ComputeIncidentState(
151 const ClientIncidentReport_IncidentData& incident) {
152 PersistentIncidentState state;
153
154 state.type = GetIncidentType(incident);
155 const IncidentTypeHandlers* handlers = GetIncidentTypeHandlers(state.type);
156 state.key = handlers->get_key_fn(incident);
157 state.digest = handlers->get_digest_fn(incident);
158
159 return state;
160 }
161
162 // Returns true if the incident described by |state| has already been reported
163 // based on the bookkeeping in the |incidents_sent| preference dictionary.
164 bool IncidentHasBeenReported(const base::DictionaryValue* incidents_sent,
165 const PersistentIncidentState& state) {
166 const base::DictionaryValue* type_dict = NULL;
167 std::string digest_string;
168 uint32_t digest = 0;
169 return (incidents_sent &&
170 incidents_sent->GetDictionaryWithoutPathExpansion(
171 base::IntToString(state.type), &type_dict) &&
172 type_dict->GetStringWithoutPathExpansion(state.key, &digest_string) &&
173 base::StringToUint(digest_string, &digest) &&
174 digest == state.digest);
Scott Hess - ex-Googler 2014/07/23 22:05:51 Could the last two lines be: digest_string ==
grt (UTC plus 2) 2014/07/24 18:58:40 Rock on.
Scott Hess - ex-Googler 2014/07/24 21:22:19 I wouldn't expect there to be any cases where thin
grt (UTC plus 2) 2014/07/24 22:58:11 Ah. I'm not concerned about that. If code outside
175 }
176
177 // Marks the incidents described by |states| as having been reported
178 // in |incidents_set|.
179 void MarkIncidentsAsReported(const std::vector<PersistentIncidentState>& states,
180 base::DictionaryValue* incidents_sent) {
181 for (size_t i = 0; i < states.size(); ++i) {
182 const PersistentIncidentState& data = states[i];
183 base::DictionaryValue* type_dict = NULL;
184 const std::string type_string(base::IntToString(data.type));
185 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
186 &type_dict)) {
187 type_dict = new base::DictionaryValue();
188 incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
189 }
190 type_dict->SetStringWithoutPathExpansion(data.key,
191 base::UintToString(data.digest));
192 }
193 }
194
67 } // namespace 195 } // namespace
68 196
69 struct IncidentReportingService::ProfileContext { 197 struct IncidentReportingService::ProfileContext {
70 ProfileContext(); 198 ProfileContext();
71 ~ProfileContext(); 199 ~ProfileContext();
72 200
73 // The incidents collected for this profile pending creation and/or upload. 201 // The incidents collected for this profile pending creation and/or upload.
74 ScopedVector<ClientIncidentReport_IncidentData> incidents; 202 ScopedVector<ClientIncidentReport_IncidentData> incidents;
75 203
76 // False until PROFILE_ADDED notification is received. 204 // False until PROFILE_ADDED notification is received.
77 bool added; 205 bool added;
78 206
79 private: 207 private:
80 DISALLOW_COPY_AND_ASSIGN(ProfileContext); 208 DISALLOW_COPY_AND_ASSIGN(ProfileContext);
81 }; 209 };
82 210
83 class IncidentReportingService::UploadContext { 211 class IncidentReportingService::UploadContext {
84 public: 212 public:
213 typedef std::map<Profile*, std::vector<PersistentIncidentState> >
214 PersistentIncidentStateCollection;
215
85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); 216 explicit UploadContext(scoped_ptr<ClientIncidentReport> report);
86 ~UploadContext(); 217 ~UploadContext();
87 218
88 // The report being uploaded. 219 // The report being uploaded.
89 scoped_ptr<ClientIncidentReport> report; 220 scoped_ptr<ClientIncidentReport> report;
90 221
91 // The uploader in use. This is NULL until the CSD killswitch is checked. 222 // The uploader in use. This is NULL until the CSD killswitch is checked.
92 scoped_ptr<IncidentReportUploader> uploader; 223 scoped_ptr<IncidentReportUploader> uploader;
93 224
94 // The set of profiles from which incidents in |report| originated. 225 // A mapping of profiles to the data to be persisted upon successful upload.
95 std::vector<Profile*> profiles; 226 PersistentIncidentStateCollection profiles_to_state;
96 227
97 private: 228 private:
98 DISALLOW_COPY_AND_ASSIGN(UploadContext); 229 DISALLOW_COPY_AND_ASSIGN(UploadContext);
99 }; 230 };
100 231
101 IncidentReportingService::ProfileContext::ProfileContext() : added() { 232 IncidentReportingService::ProfileContext::ProfileContext() : added() {
102 } 233 }
103 234
104 IncidentReportingService::ProfileContext::~ProfileContext() { 235 IncidentReportingService::ProfileContext::~ProfileContext() {
105 } 236 }
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if (it == profiles_.end()) 385 if (it == profiles_.end())
255 return; 386 return;
256 387
257 // TODO(grt): Persist incidents for upload on future profile load. 388 // TODO(grt): Persist incidents for upload on future profile load.
258 389
259 // Forget about this profile. Incidents not yet sent for upload are lost. 390 // Forget about this profile. Incidents not yet sent for upload are lost.
260 // No new incidents will be accepted for it. 391 // No new incidents will be accepted for it.
261 delete it->second; 392 delete it->second;
262 profiles_.erase(it); 393 profiles_.erase(it);
263 394
264 // Remove the association with this profile from any pending uploads. 395 // Remove the association with this profile from all pending uploads.
265 for (size_t i = 0; i < uploads_.size(); ++i) { 396 for (size_t i = 0; i < uploads_.size(); ++i)
266 UploadContext* upload = uploads_[i]; 397 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 } 398 }
276 399
277 void IncidentReportingService::AddIncident( 400 void IncidentReportingService::AddIncident(
278 Profile* profile, 401 Profile* profile,
279 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 402 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
280 DCHECK(thread_checker_.CalledOnValidThread()); 403 DCHECK(thread_checker_.CalledOnValidThread());
281 // Incidents outside the context of a profile are not supported at the moment. 404 // Incidents outside the context of a profile are not supported at the moment.
282 DCHECK(profile); 405 DCHECK(profile);
283 406
284 ProfileContext* context = GetProfileContext(profile); 407 ProfileContext* context = GetProfileContext(profile);
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 if (g_browser_process->local_state()->FindPreference( 632 if (g_browser_process->local_state()->FindPreference(
510 prefs::kMetricsReportingEnabled)) { 633 prefs::kMetricsReportingEnabled)) {
511 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 634 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
512 prefs::kMetricsReportingEnabled)); 635 prefs::kMetricsReportingEnabled));
513 } 636 }
514 637
515 // Check for extended consent in any profile while collecting incidents. 638 // Check for extended consent in any profile while collecting incidents.
516 process->set_extended_consent(false); 639 process->set_extended_consent(false);
517 // Collect incidents across all profiles participating in safe browsing. Drop 640 // Collect incidents across all profiles participating in safe browsing. Drop
518 // incidents if the profile stopped participating before collection completed. 641 // incidents if the profile stopped participating before collection completed.
519 // Prune incidents if the profile has already submitted any incidents. 642 // Prune previously submitted incidents.
520 // Associate the participating profiles with the upload. 643 // Associate the profiles and their incident data with the upload.
521 size_t prune_count = 0; 644 size_t prune_count = 0;
522 std::vector<Profile*> profiles; 645 std::map<Profile*, std::vector<PersistentIncidentState> > profiles_to_state;
Scott Hess - ex-Googler 2014/07/23 22:05:51 PersistentIncidentStateCollection? The code below
grt (UTC plus 2) 2014/07/24 18:58:40 Done.
523 for (ProfileContextCollection::iterator scan = profiles_.begin(); 646 for (ProfileContextCollection::iterator scan = profiles_.begin();
524 scan != profiles_.end(); 647 scan != profiles_.end();
525 ++scan) { 648 ++scan) {
526 PrefService* prefs = scan->first->GetPrefs(); 649 PrefService* prefs = scan->first->GetPrefs();
527 if (process && 650 if (process &&
528 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { 651 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
529 process->set_extended_consent(true); 652 process->set_extended_consent(true);
530 process = NULL; // Don't check any more once one is found. 653 process = NULL; // Don't check any more once one is found.
531 } 654 }
532 ProfileContext* context = scan->second; 655 ProfileContext* context = scan->second;
533 if (context->incidents.empty()) 656 if (context->incidents.empty())
534 continue; 657 continue;
535 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 658 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
536 for (size_t i = 0; i < context->incidents.size(); ++i) { 659 for (size_t i = 0; i < context->incidents.size(); ++i) {
537 LogIncidentDataType(DROPPED, *context->incidents[i]); 660 LogIncidentDataType(DROPPED, *context->incidents[i]);
538 } 661 }
539 context->incidents.clear(); 662 context->incidents.clear();
540 } else if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) { 663 continue;
541 // Prune all incidents. 664 }
542 // TODO(grt): Only prune previously submitted incidents; 665 std::vector<PersistentIncidentState> states;
543 // http://crbug.com/383043. 666 const base::DictionaryValue* incidents_sent =
544 prune_count += context->incidents.size(); 667 prefs->GetDictionary(prefs::kSafeBrowsingIncidentsSent);
668 // Prep persistent data and prune any incidents already sent.
669 for (size_t i = 0; i < context->incidents.size(); ++i) {
670 ClientIncidentReport_IncidentData* incident = context->incidents[i];
671 const PersistentIncidentState state = ComputeIncidentState(*incident);
672 if (IncidentHasBeenReported(incidents_sent, state)) {
673 ++prune_count;
674 delete context->incidents[i];
675 context->incidents[i] = NULL;
676 } else {
677 states.push_back(state);
678 }
679 }
680 if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) {
681 // Prune all incidents as if they had been reported, migrating to the new
682 // technique. TODO(grt): remove this branch after it has shipped.
683 for (size_t i = 0; i < context->incidents.size(); ++i) {
684 if (context->incidents[i])
685 ++prune_count;
686 }
545 context->incidents.clear(); 687 context->incidents.clear();
688 prefs->ClearPref(prefs::kSafeBrowsingIncidentReportSent);
689 DictionaryPrefUpdate pref_update(prefs,
690 prefs::kSafeBrowsingIncidentsSent);
691 MarkIncidentsAsReported(states, pref_update.Get());
546 } else { 692 } else {
547 for (size_t i = 0; i < context->incidents.size(); ++i) { 693 for (size_t i = 0; i < context->incidents.size(); ++i) {
548 ClientIncidentReport_IncidentData* incident = context->incidents[i]; 694 ClientIncidentReport_IncidentData* incident = context->incidents[i];
549 LogIncidentDataType(ACCEPTED, *incident); 695 if (incident) {
550 // Ownership of the incident is passed to the report. 696 LogIncidentDataType(ACCEPTED, *incident);
551 report->mutable_incident()->AddAllocated(incident); 697 // Ownership of the incident is passed to the report.
698 report->mutable_incident()->AddAllocated(incident);
699 }
552 } 700 }
553 context->incidents.weak_clear(); 701 context->incidents.weak_clear();
554 profiles.push_back(scan->first); 702 std::vector<PersistentIncidentState>& profile_states =
703 profiles_to_state[scan->first];
704 profile_states.swap(states);
555 } 705 }
556 } 706 }
557 707
558 const int count = report->incident_size(); 708 const int count = report->incident_size();
559 // Abandon the request if all incidents were dropped with none pruned. 709 // Abandon the request if all incidents were dropped with none pruned.
560 if (!count && !prune_count) 710 if (!count && !prune_count)
561 return; 711 return;
562 712
563 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count); 713 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count);
564 714
565 { 715 {
566 double prune_pct = static_cast<double>(prune_count); 716 double prune_pct = static_cast<double>(prune_count);
567 prune_pct = prune_pct * 100.0 / (count + prune_count); 717 prune_pct = prune_pct * 100.0 / (count + prune_count);
568 prune_pct = round(prune_pct); 718 prune_pct = round(prune_pct);
569 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); 719 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct));
570 } 720 }
571 // Abandon the report if all incidents were pruned. 721 // Abandon the report if all incidents were pruned.
572 if (!count) 722 if (!count)
573 return; 723 return;
574 724
575 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); 725 scoped_ptr<UploadContext> context(new UploadContext(report.Pass()));
576 context->profiles.swap(profiles); 726 context->profiles_to_state.swap(profiles_to_state);
577 if (!database_manager_) { 727 if (!database_manager_) {
578 // No database manager during testing. Take ownership of the context and 728 // No database manager during testing. Take ownership of the context and
579 // continue processing. 729 // continue processing.
580 UploadContext* temp_context = context.get(); 730 UploadContext* temp_context = context.get();
581 uploads_.push_back(context.release()); 731 uploads_.push_back(context.release());
582 IncidentReportingService::OnKillSwitchResult(temp_context, false); 732 IncidentReportingService::OnKillSwitchResult(temp_context, false);
583 } else { 733 } else {
584 if (content::BrowserThread::PostTaskAndReplyWithResult( 734 if (content::BrowserThread::PostTaskAndReplyWithResult(
585 content::BrowserThread::IO, 735 content::BrowserThread::IO,
586 FROM_HERE, 736 FROM_HERE,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 scoped_ptr<ClientIncidentResponse>()); 771 scoped_ptr<ClientIncidentResponse>());
622 } 772 }
623 } else { 773 } else {
624 OnReportUploadResult(context, 774 OnReportUploadResult(context,
625 IncidentReportUploader::UPLOAD_SUPPRESSED, 775 IncidentReportUploader::UPLOAD_SUPPRESSED,
626 scoped_ptr<ClientIncidentResponse>()); 776 scoped_ptr<ClientIncidentResponse>());
627 } 777 }
628 } 778 }
629 779
630 void IncidentReportingService::HandleResponse(const UploadContext& context) { 780 void IncidentReportingService::HandleResponse(const UploadContext& context) {
631 for (size_t i = 0; i < context.profiles.size(); ++i) { 781 for (UploadContext::PersistentIncidentStateCollection::const_iterator scan =
632 context.profiles[i]->GetPrefs()->SetBoolean( 782 context.profiles_to_state.begin();
633 prefs::kSafeBrowsingIncidentReportSent, true); 783 scan != context.profiles_to_state.end();
784 ++scan) {
785 DictionaryPrefUpdate pref_update(scan->first->GetPrefs(),
786 prefs::kSafeBrowsingIncidentsSent);
787 MarkIncidentsAsReported(scan->second, pref_update.Get());
634 } 788 }
635 } 789 }
636 790
637 void IncidentReportingService::OnReportUploadResult( 791 void IncidentReportingService::OnReportUploadResult(
638 UploadContext* context, 792 UploadContext* context,
639 IncidentReportUploader::Result result, 793 IncidentReportUploader::Result result,
640 scoped_ptr<ClientIncidentResponse> response) { 794 scoped_ptr<ClientIncidentResponse> response) {
641 DCHECK(thread_checker_.CalledOnValidThread()); 795 DCHECK(thread_checker_.CalledOnValidThread());
642 796
643 UMA_HISTOGRAM_ENUMERATION( 797 UMA_HISTOGRAM_ENUMERATION(
(...skipping 29 matching lines...) Expand all
673 if (!profile->IsOffTheRecord()) 827 if (!profile->IsOffTheRecord())
674 OnProfileDestroyed(profile); 828 OnProfileDestroyed(profile);
675 break; 829 break;
676 } 830 }
677 default: 831 default:
678 break; 832 break;
679 } 833 }
680 } 834 }
681 835
682 } // namespace safe_browsing 836 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « chrome/browser/profiles/profile.cc ('k') | chrome/browser/safe_browsing/incident_reporting_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698