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

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: compile_assert 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 // The amount of time the service will wait to collate incidents.
48 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 71 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
49 72
73 // Returns the number of incidents contained in |incident|. The result is
74 // expected to be 1. Used in DCHECKs.
75 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) {
76 size_t result = 0;
77 if (incident.has_tracked_preference())
78 ++result;
79 // Add detection for new incident types here.
80 return result;
81 }
82
83 // Returns the type of incident contained in |incident_data|.
84 IncidentType GetIncidentType(
85 const ClientIncidentReport_IncidentData& incident_data) {
86 if (incident_data.has_tracked_preference())
87 return TRACKED_PREFERENCE;
88
89 // Add detection for new incident types here.
90 COMPILE_ASSERT(TRACKED_PREFERENCE + 1 == NUM_INCIDENT_TYPES,
91 add_support_for_new_types);
92 NOTREACHED();
93 return NUM_INCIDENT_TYPES;
94 }
95
96 // Logs the type of incident in |incident_data| to a user metrics histogram.
50 void LogIncidentDataType( 97 void LogIncidentDataType(
51 IncidentDisposition disposition, 98 IncidentDisposition disposition,
52 const ClientIncidentReport_IncidentData& incident_data) { 99 const ClientIncidentReport_IncidentData& incident_data) {
53 IncidentType type = TRACKED_PREFERENCE; 100 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) { 101 if (disposition == ACCEPTED) {
59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); 102 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES);
60 } else { 103 } else {
61 DCHECK_EQ(disposition, DROPPED); 104 DCHECK_EQ(disposition, DROPPED);
62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, 105 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type,
63 NUM_INCIDENT_TYPES); 106 NUM_INCIDENT_TYPES);
64 } 107 }
65 } 108 }
66 109
110 // Computes the persistent state for an incident.
111 PersistentIncidentState ComputeIncidentState(
112 const ClientIncidentReport_IncidentData& incident) {
113 PersistentIncidentState state = {GetIncidentType(incident)};
114 switch (state.type) {
115 case TRACKED_PREFERENCE:
116 state.key = GetTrackedPreferenceIncidentKey(incident);
117 state.digest = GetTrackedPreferenceIncidentDigest(incident);
118 break;
119 // Add handling for new incident types here.
120 default:
121 COMPILE_ASSERT(TRACKED_PREFERENCE + 1 == NUM_INCIDENT_TYPES,
122 add_support_for_new_types);
123 NOTREACHED();
124 break;
125 }
126 return state;
127 }
128
129 // Returns true if the incident described by |state| has already been reported
130 // based on the bookkeeping in the |incidents_sent| preference dictionary.
131 bool IncidentHasBeenReported(const base::DictionaryValue* incidents_sent,
132 const PersistentIncidentState& state) {
133 const base::DictionaryValue* type_dict = NULL;
134 std::string digest_string;
135 return (incidents_sent &&
136 incidents_sent->GetDictionaryWithoutPathExpansion(
137 base::IntToString(state.type), &type_dict) &&
138 type_dict->GetStringWithoutPathExpansion(state.key, &digest_string) &&
139 digest_string == base::UintToString(state.digest));
140 }
141
142 // Marks the incidents described by |states| as having been reported
143 // in |incidents_set|.
144 void MarkIncidentsAsReported(const std::vector<PersistentIncidentState>& states,
145 base::DictionaryValue* incidents_sent) {
146 for (size_t i = 0; i < states.size(); ++i) {
147 const PersistentIncidentState& data = states[i];
148 base::DictionaryValue* type_dict = NULL;
149 const std::string type_string(base::IntToString(data.type));
150 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
151 &type_dict)) {
152 type_dict = new base::DictionaryValue();
153 incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
154 }
155 type_dict->SetStringWithoutPathExpansion(data.key,
156 base::UintToString(data.digest));
157 }
158 }
159
67 } // namespace 160 } // namespace
68 161
69 struct IncidentReportingService::ProfileContext { 162 struct IncidentReportingService::ProfileContext {
70 ProfileContext(); 163 ProfileContext();
71 ~ProfileContext(); 164 ~ProfileContext();
72 165
73 // The incidents collected for this profile pending creation and/or upload. 166 // The incidents collected for this profile pending creation and/or upload.
74 ScopedVector<ClientIncidentReport_IncidentData> incidents; 167 ScopedVector<ClientIncidentReport_IncidentData> incidents;
75 168
76 // False until PROFILE_ADDED notification is received. 169 // False until PROFILE_ADDED notification is received.
77 bool added; 170 bool added;
78 171
79 private: 172 private:
80 DISALLOW_COPY_AND_ASSIGN(ProfileContext); 173 DISALLOW_COPY_AND_ASSIGN(ProfileContext);
81 }; 174 };
82 175
83 class IncidentReportingService::UploadContext { 176 class IncidentReportingService::UploadContext {
84 public: 177 public:
178 typedef std::map<Profile*, std::vector<PersistentIncidentState> >
179 PersistentIncidentStateCollection;
180
85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); 181 explicit UploadContext(scoped_ptr<ClientIncidentReport> report);
86 ~UploadContext(); 182 ~UploadContext();
87 183
88 // The report being uploaded. 184 // The report being uploaded.
89 scoped_ptr<ClientIncidentReport> report; 185 scoped_ptr<ClientIncidentReport> report;
90 186
91 // The uploader in use. This is NULL until the CSD killswitch is checked. 187 // The uploader in use. This is NULL until the CSD killswitch is checked.
92 scoped_ptr<IncidentReportUploader> uploader; 188 scoped_ptr<IncidentReportUploader> uploader;
93 189
94 // The set of profiles from which incidents in |report| originated. 190 // A mapping of profiles to the data to be persisted upon successful upload.
95 std::vector<Profile*> profiles; 191 PersistentIncidentStateCollection profiles_to_state;
96 192
97 private: 193 private:
98 DISALLOW_COPY_AND_ASSIGN(UploadContext); 194 DISALLOW_COPY_AND_ASSIGN(UploadContext);
99 }; 195 };
100 196
101 IncidentReportingService::ProfileContext::ProfileContext() : added() { 197 IncidentReportingService::ProfileContext::ProfileContext() : added() {
102 } 198 }
103 199
104 IncidentReportingService::ProfileContext::~ProfileContext() { 200 IncidentReportingService::ProfileContext::~ProfileContext() {
105 } 201 }
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if (it == profiles_.end()) 350 if (it == profiles_.end())
255 return; 351 return;
256 352
257 // TODO(grt): Persist incidents for upload on future profile load. 353 // TODO(grt): Persist incidents for upload on future profile load.
258 354
259 // Forget about this profile. Incidents not yet sent for upload are lost. 355 // Forget about this profile. Incidents not yet sent for upload are lost.
260 // No new incidents will be accepted for it. 356 // No new incidents will be accepted for it.
261 delete it->second; 357 delete it->second;
262 profiles_.erase(it); 358 profiles_.erase(it);
263 359
264 // Remove the association with this profile from any pending uploads. 360 // Remove the association with this profile from all pending uploads.
265 for (size_t i = 0; i < uploads_.size(); ++i) { 361 for (size_t i = 0; i < uploads_.size(); ++i)
266 UploadContext* upload = uploads_[i]; 362 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 } 363 }
276 364
277 void IncidentReportingService::AddIncident( 365 void IncidentReportingService::AddIncident(
278 Profile* profile, 366 Profile* profile,
279 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 367 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
280 DCHECK(thread_checker_.CalledOnValidThread()); 368 DCHECK(thread_checker_.CalledOnValidThread());
281 // Incidents outside the context of a profile are not supported at the moment. 369 // Incidents outside the context of a profile are not supported at the moment.
282 DCHECK(profile); 370 DCHECK(profile);
371 DCHECK_EQ(1U, CountIncidents(*incident_data));
283 372
284 ProfileContext* context = GetProfileContext(profile); 373 ProfileContext* context = GetProfileContext(profile);
285 // It is forbidden to call this function with a destroyed profile. 374 // It is forbidden to call this function with a destroyed profile.
286 DCHECK(context); 375 DCHECK(context);
287 376
288 // Drop the incident immediately if profile creation has completed and the 377 // Drop the incident immediately if profile creation has completed and the
289 // profile is not participating in safe browsing. Preference evaluation is 378 // profile is not participating in safe browsing. Preference evaluation is
290 // deferred until OnProfileAdded() if profile creation has not yet 379 // deferred until OnProfileAdded() if profile creation has not yet
291 // completed. 380 // completed.
292 if (context->added && 381 if (context->added &&
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 if (g_browser_process->local_state()->FindPreference( 598 if (g_browser_process->local_state()->FindPreference(
510 prefs::kMetricsReportingEnabled)) { 599 prefs::kMetricsReportingEnabled)) {
511 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 600 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
512 prefs::kMetricsReportingEnabled)); 601 prefs::kMetricsReportingEnabled));
513 } 602 }
514 603
515 // Check for extended consent in any profile while collecting incidents. 604 // Check for extended consent in any profile while collecting incidents.
516 process->set_extended_consent(false); 605 process->set_extended_consent(false);
517 // Collect incidents across all profiles participating in safe browsing. Drop 606 // Collect incidents across all profiles participating in safe browsing. Drop
518 // incidents if the profile stopped participating before collection completed. 607 // incidents if the profile stopped participating before collection completed.
519 // Prune incidents if the profile has already submitted any incidents. 608 // Prune previously submitted incidents.
520 // Associate the participating profiles with the upload. 609 // Associate the profiles and their incident data with the upload.
521 size_t prune_count = 0; 610 size_t prune_count = 0;
522 std::vector<Profile*> profiles; 611 UploadContext::PersistentIncidentStateCollection profiles_to_state;
523 for (ProfileContextCollection::iterator scan = profiles_.begin(); 612 for (ProfileContextCollection::iterator scan = profiles_.begin();
524 scan != profiles_.end(); 613 scan != profiles_.end();
525 ++scan) { 614 ++scan) {
526 PrefService* prefs = scan->first->GetPrefs(); 615 PrefService* prefs = scan->first->GetPrefs();
527 if (process && 616 if (process &&
528 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { 617 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
529 process->set_extended_consent(true); 618 process->set_extended_consent(true);
530 process = NULL; // Don't check any more once one is found. 619 process = NULL; // Don't check any more once one is found.
531 } 620 }
532 ProfileContext* context = scan->second; 621 ProfileContext* context = scan->second;
533 if (context->incidents.empty()) 622 if (context->incidents.empty())
534 continue; 623 continue;
535 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 624 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
536 for (size_t i = 0; i < context->incidents.size(); ++i) { 625 for (size_t i = 0; i < context->incidents.size(); ++i) {
537 LogIncidentDataType(DROPPED, *context->incidents[i]); 626 LogIncidentDataType(DROPPED, *context->incidents[i]);
538 } 627 }
539 context->incidents.clear(); 628 context->incidents.clear();
540 } else if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) { 629 continue;
541 // Prune all incidents. 630 }
542 // TODO(grt): Only prune previously submitted incidents; 631 std::vector<PersistentIncidentState> states;
543 // http://crbug.com/383043. 632 const base::DictionaryValue* incidents_sent =
544 prune_count += context->incidents.size(); 633 prefs->GetDictionary(prefs::kSafeBrowsingIncidentsSent);
634 // Prep persistent data and prune any incidents already sent.
635 for (size_t i = 0; i < context->incidents.size(); ++i) {
636 ClientIncidentReport_IncidentData* incident = context->incidents[i];
637 const PersistentIncidentState state = ComputeIncidentState(*incident);
638 if (IncidentHasBeenReported(incidents_sent, state)) {
639 ++prune_count;
640 delete context->incidents[i];
641 context->incidents[i] = NULL;
642 } else {
643 states.push_back(state);
644 }
645 }
646 if (prefs->GetBoolean(prefs::kSafeBrowsingIncidentReportSent)) {
647 // Prune all incidents as if they had been reported, migrating to the new
648 // technique. TODO(grt): remove this branch after it has shipped.
649 for (size_t i = 0; i < context->incidents.size(); ++i) {
650 if (context->incidents[i])
651 ++prune_count;
652 }
545 context->incidents.clear(); 653 context->incidents.clear();
654 prefs->ClearPref(prefs::kSafeBrowsingIncidentReportSent);
655 DictionaryPrefUpdate pref_update(prefs,
656 prefs::kSafeBrowsingIncidentsSent);
657 MarkIncidentsAsReported(states, pref_update.Get());
546 } else { 658 } else {
547 for (size_t i = 0; i < context->incidents.size(); ++i) { 659 for (size_t i = 0; i < context->incidents.size(); ++i) {
548 ClientIncidentReport_IncidentData* incident = context->incidents[i]; 660 ClientIncidentReport_IncidentData* incident = context->incidents[i];
549 LogIncidentDataType(ACCEPTED, *incident); 661 if (incident) {
550 // Ownership of the incident is passed to the report. 662 LogIncidentDataType(ACCEPTED, *incident);
551 report->mutable_incident()->AddAllocated(incident); 663 // Ownership of the incident is passed to the report.
664 report->mutable_incident()->AddAllocated(incident);
665 }
552 } 666 }
553 context->incidents.weak_clear(); 667 context->incidents.weak_clear();
554 profiles.push_back(scan->first); 668 std::vector<PersistentIncidentState>& profile_states =
669 profiles_to_state[scan->first];
670 profile_states.swap(states);
555 } 671 }
556 } 672 }
557 673
558 const int count = report->incident_size(); 674 const int count = report->incident_size();
559 // Abandon the request if all incidents were dropped with none pruned. 675 // Abandon the request if all incidents were dropped with none pruned.
560 if (!count && !prune_count) 676 if (!count && !prune_count)
561 return; 677 return;
562 678
563 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count); 679 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", count + prune_count);
564 680
565 { 681 {
566 double prune_pct = static_cast<double>(prune_count); 682 double prune_pct = static_cast<double>(prune_count);
567 prune_pct = prune_pct * 100.0 / (count + prune_count); 683 prune_pct = prune_pct * 100.0 / (count + prune_count);
568 prune_pct = round(prune_pct); 684 prune_pct = round(prune_pct);
569 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); 685 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct));
570 } 686 }
571 // Abandon the report if all incidents were pruned. 687 // Abandon the report if all incidents were pruned.
572 if (!count) 688 if (!count)
573 return; 689 return;
574 690
575 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); 691 scoped_ptr<UploadContext> context(new UploadContext(report.Pass()));
576 context->profiles.swap(profiles); 692 context->profiles_to_state.swap(profiles_to_state);
577 if (!database_manager_) { 693 if (!database_manager_) {
578 // No database manager during testing. Take ownership of the context and 694 // No database manager during testing. Take ownership of the context and
579 // continue processing. 695 // continue processing.
580 UploadContext* temp_context = context.get(); 696 UploadContext* temp_context = context.get();
581 uploads_.push_back(context.release()); 697 uploads_.push_back(context.release());
582 IncidentReportingService::OnKillSwitchResult(temp_context, false); 698 IncidentReportingService::OnKillSwitchResult(temp_context, false);
583 } else { 699 } else {
584 if (content::BrowserThread::PostTaskAndReplyWithResult( 700 if (content::BrowserThread::PostTaskAndReplyWithResult(
585 content::BrowserThread::IO, 701 content::BrowserThread::IO,
586 FROM_HERE, 702 FROM_HERE,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 scoped_ptr<ClientIncidentResponse>()); 737 scoped_ptr<ClientIncidentResponse>());
622 } 738 }
623 } else { 739 } else {
624 OnReportUploadResult(context, 740 OnReportUploadResult(context,
625 IncidentReportUploader::UPLOAD_SUPPRESSED, 741 IncidentReportUploader::UPLOAD_SUPPRESSED,
626 scoped_ptr<ClientIncidentResponse>()); 742 scoped_ptr<ClientIncidentResponse>());
627 } 743 }
628 } 744 }
629 745
630 void IncidentReportingService::HandleResponse(const UploadContext& context) { 746 void IncidentReportingService::HandleResponse(const UploadContext& context) {
631 for (size_t i = 0; i < context.profiles.size(); ++i) { 747 for (UploadContext::PersistentIncidentStateCollection::const_iterator scan =
632 context.profiles[i]->GetPrefs()->SetBoolean( 748 context.profiles_to_state.begin();
633 prefs::kSafeBrowsingIncidentReportSent, true); 749 scan != context.profiles_to_state.end();
750 ++scan) {
751 DictionaryPrefUpdate pref_update(scan->first->GetPrefs(),
752 prefs::kSafeBrowsingIncidentsSent);
753 MarkIncidentsAsReported(scan->second, pref_update.Get());
634 } 754 }
635 } 755 }
636 756
637 void IncidentReportingService::OnReportUploadResult( 757 void IncidentReportingService::OnReportUploadResult(
638 UploadContext* context, 758 UploadContext* context,
639 IncidentReportUploader::Result result, 759 IncidentReportUploader::Result result,
640 scoped_ptr<ClientIncidentResponse> response) { 760 scoped_ptr<ClientIncidentResponse> response) {
641 DCHECK(thread_checker_.CalledOnValidThread()); 761 DCHECK(thread_checker_.CalledOnValidThread());
642 762
643 UMA_HISTOGRAM_ENUMERATION( 763 UMA_HISTOGRAM_ENUMERATION(
(...skipping 29 matching lines...) Expand all
673 if (!profile->IsOffTheRecord()) 793 if (!profile->IsOffTheRecord())
674 OnProfileDestroyed(profile); 794 OnProfileDestroyed(profile);
675 break; 795 break;
676 } 796 }
677 default: 797 default:
678 break; 798 break;
679 } 799 }
680 } 800 }
681 801
682 } // namespace safe_browsing 802 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698