Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/prefs/pref_service.h" | |
| 10 #include "base/process/process_info.h" | 11 #include "base/process/process_info.h" |
| 12 #include "base/stl_util.h" | |
| 11 #include "base/threading/sequenced_worker_pool.h" | 13 #include "base/threading/sequenced_worker_pool.h" |
| 14 #include "chrome/browser/browser_process.h" | |
| 15 #include "chrome/browser/chrome_notification_types.h" | |
| 12 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" | 16 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" |
| 17 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/browser/safe_browsing/database_manager.h" | 18 #include "chrome/browser/safe_browsing/database_manager.h" |
| 14 #include "chrome/browser/safe_browsing/environment_data_collection.h" | 19 #include "chrome/browser/safe_browsing/environment_data_collection.h" |
| 15 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" | 20 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" |
| 16 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" | 21 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" |
| 17 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 22 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| 23 #include "chrome/common/pref_names.h" | |
| 18 #include "chrome/common/safe_browsing/csd.pb.h" | 24 #include "chrome/common/safe_browsing/csd.pb.h" |
| 19 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 26 #include "content/public/browser/notification_service.h" | |
| 20 #include "net/url_request/url_request_context_getter.h" | 27 #include "net/url_request/url_request_context_getter.h" |
| 21 | 28 |
| 22 namespace safe_browsing { | 29 namespace safe_browsing { |
| 23 | 30 |
| 24 namespace { | 31 namespace { |
| 25 | 32 |
| 26 enum IncidentType { | 33 enum IncidentType { |
| 27 // Start with 1 rather than zero; otherwise there won't be enough buckets for | 34 // Start with 1 rather than zero; otherwise there won't be enough buckets for |
| 28 // the histogram. | 35 // the histogram. |
| 29 TRACKED_PREFERENCE = 1, | 36 TRACKED_PREFERENCE = 1, |
| 30 NUM_INCIDENT_TYPES | 37 NUM_INCIDENT_TYPES |
| 31 }; | 38 }; |
| 32 | 39 |
| 40 enum IncidentDisposition { | |
| 41 DROPPED, | |
| 42 ACCEPTED, | |
| 43 }; | |
| 44 | |
| 33 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute | 45 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute |
| 34 | 46 |
| 35 void LogIncidentDataType( | 47 void LogIncidentDataType( |
| 48 IncidentDisposition disposition, | |
| 36 const ClientIncidentReport_IncidentData& incident_data) { | 49 const ClientIncidentReport_IncidentData& incident_data) { |
| 37 if (incident_data.has_tracked_preference()) { | 50 static const char kAcceptedMetric[] = "SBIRS.Incident"; |
|
Alexei Svitkine (slow)
2014/06/19 14:25:03
Nit: It's fine to inline these into the macros, ra
| |
| 38 UMA_HISTOGRAM_ENUMERATION( | 51 static const char kDroppedMetric[] = "SBIRS.DroppedIncident"; |
| 39 "SBIRS.Incident", TRACKED_PREFERENCE, NUM_INCIDENT_TYPES); | 52 |
| 53 IncidentType type = TRACKED_PREFERENCE; | |
| 54 | |
| 55 // Add a switch statement once other types are supported. | |
| 56 DCHECK(incident_data.has_tracked_preference()); | |
| 57 | |
| 58 if (disposition == ACCEPTED) { | |
| 59 UMA_HISTOGRAM_ENUMERATION(kAcceptedMetric, type, NUM_INCIDENT_TYPES); | |
| 60 } else { | |
| 61 DCHECK_EQ(disposition, DROPPED); | |
| 62 UMA_HISTOGRAM_ENUMERATION(kDroppedMetric, type, NUM_INCIDENT_TYPES); | |
| 40 } | 63 } |
| 41 } | 64 } |
| 42 | 65 |
| 43 } // namespace | 66 } // namespace |
| 44 | 67 |
| 68 struct IncidentReportingService::ProfileContext { | |
| 69 ProfileContext(); | |
| 70 ~ProfileContext(); | |
| 71 | |
| 72 // The incidents collected for this profile pending creation and/or upload. | |
| 73 ScopedVector<ClientIncidentReport_IncidentData> incidents; | |
| 74 | |
| 75 // False until PROFILE_CREATED notification is received. | |
| 76 bool created; | |
| 77 | |
| 78 private: | |
| 79 DISALLOW_COPY_AND_ASSIGN(ProfileContext); | |
| 80 }; | |
| 81 | |
| 45 class IncidentReportingService::UploadContext { | 82 class IncidentReportingService::UploadContext { |
| 46 public: | 83 public: |
| 47 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); | 84 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); |
| 48 ~UploadContext(); | 85 ~UploadContext(); |
| 49 | 86 |
| 50 scoped_ptr<ClientIncidentReport> report; | 87 scoped_ptr<ClientIncidentReport> report; |
| 51 scoped_ptr<IncidentReportUploader> uploader; | 88 scoped_ptr<IncidentReportUploader> uploader; |
| 52 | 89 |
| 53 private: | 90 private: |
| 54 DISALLOW_COPY_AND_ASSIGN(UploadContext); | 91 DISALLOW_COPY_AND_ASSIGN(UploadContext); |
| 55 }; | 92 }; |
| 56 | 93 |
| 94 IncidentReportingService::ProfileContext::ProfileContext() : created() { | |
| 95 } | |
| 96 | |
| 97 IncidentReportingService::ProfileContext::~ProfileContext() { | |
| 98 } | |
| 99 | |
| 57 IncidentReportingService::UploadContext::UploadContext( | 100 IncidentReportingService::UploadContext::UploadContext( |
| 58 scoped_ptr<ClientIncidentReport> report) | 101 scoped_ptr<ClientIncidentReport> report) |
| 59 : report(report.Pass()) { | 102 : report(report.Pass()) { |
| 60 } | 103 } |
| 61 | 104 |
| 62 IncidentReportingService::UploadContext::~UploadContext() { | 105 IncidentReportingService::UploadContext::~UploadContext() { |
| 63 } | 106 } |
| 64 | 107 |
| 65 IncidentReportingService::IncidentReportingService( | 108 IncidentReportingService::IncidentReportingService( |
| 66 SafeBrowsingService* safe_browsing_service, | 109 SafeBrowsingService* safe_browsing_service, |
| 67 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) | 110 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) |
| 68 : database_manager_(safe_browsing_service ? | 111 : database_manager_(safe_browsing_service ? |
| 69 safe_browsing_service->database_manager() : NULL), | 112 safe_browsing_service->database_manager() : NULL), |
| 70 url_request_context_getter_(request_context_getter), | 113 url_request_context_getter_(request_context_getter), |
| 71 collect_environment_data_fn_(&CollectEnvironmentData), | 114 collect_environment_data_fn_(&CollectEnvironmentData), |
| 72 environment_collection_task_runner_( | 115 environment_collection_task_runner_( |
| 73 content::BrowserThread::GetBlockingPool() | 116 content::BrowserThread::GetBlockingPool() |
| 74 ->GetTaskRunnerWithShutdownBehavior( | 117 ->GetTaskRunnerWithShutdownBehavior( |
| 75 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), | 118 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), |
| 76 enabled_(), | |
| 77 environment_collection_pending_(), | 119 environment_collection_pending_(), |
| 78 collection_timeout_pending_(), | 120 collection_timeout_pending_(), |
| 79 upload_timer_(FROM_HERE, | 121 upload_timer_(FROM_HERE, |
| 80 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), | 122 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), |
| 81 this, | 123 this, |
| 82 &IncidentReportingService::OnCollectionTimeout), | 124 &IncidentReportingService::OnCollectionTimeout), |
| 83 receiver_weak_ptr_factory_(this), | 125 receiver_weak_ptr_factory_(this), |
| 84 weak_ptr_factory_(this) { | 126 weak_ptr_factory_(this) { |
| 127 notification_registrar_.Add(this, | |
| 128 chrome::NOTIFICATION_PROFILE_CREATED, | |
| 129 content::NotificationService::AllSources()); | |
| 130 notification_registrar_.Add(this, | |
| 131 chrome::NOTIFICATION_PROFILE_DESTROYED, | |
| 132 content::NotificationService::AllSources()); | |
| 85 } | 133 } |
| 86 | 134 |
| 87 IncidentReportingService::~IncidentReportingService() { | 135 IncidentReportingService::~IncidentReportingService() { |
| 88 if (enabled_) | 136 CancelIncidentCollection(); |
| 89 SetEnabled(false); | 137 |
| 138 // Cancel all internal asynchronous tasks. | |
| 139 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 140 | |
| 141 CancelEnvironmentCollection(); | |
| 142 CancelAllReportUploads(); | |
| 143 | |
| 144 STLDeleteValues(&profiles_); | |
| 90 } | 145 } |
| 91 | 146 |
| 92 void IncidentReportingService::SetEnabled(bool enabled) { | 147 AddIncidentCallback IncidentReportingService::GetAddIncidentCallback( |
| 93 DCHECK(thread_checker_.CalledOnValidThread()); | 148 Profile* profile) { |
| 149 // Force the context to be created so that incidents added before | |
| 150 // OnProfileCreated is called are held until the profile's preferences can be | |
| 151 // queried. | |
| 152 ignore_result(GetOrCreateProfileContext(profile)); | |
| 94 | 153 |
| 95 if (!enabled) { | |
| 96 CancelIncidentCollection(); | |
| 97 | |
| 98 // Cancel all internal asynchronous tasks. | |
| 99 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 100 | |
| 101 CancelEnvironmentCollection(); | |
| 102 CancelAllReportUploads(); | |
| 103 } | |
| 104 | |
| 105 enabled_ = enabled; | |
| 106 } | |
| 107 | |
| 108 AddIncidentCallback IncidentReportingService::GetAddIncidentCallback() { | |
| 109 return base::Bind(&IncidentReportingService::AddIncident, | 154 return base::Bind(&IncidentReportingService::AddIncident, |
| 110 receiver_weak_ptr_factory_.GetWeakPtr()); | 155 receiver_weak_ptr_factory_.GetWeakPtr(), |
| 156 profile); | |
| 111 } | 157 } |
| 112 | 158 |
| 113 scoped_ptr<TrackedPreferenceValidationDelegate> | 159 scoped_ptr<TrackedPreferenceValidationDelegate> |
| 114 IncidentReportingService::CreatePreferenceValidationDelegate() { | 160 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { |
| 115 DCHECK(thread_checker_.CalledOnValidThread()); | 161 DCHECK(thread_checker_.CalledOnValidThread()); |
| 162 | |
| 163 if (profile->IsOffTheRecord()) | |
| 164 return scoped_ptr<TrackedPreferenceValidationDelegate>(); | |
| 116 return scoped_ptr<TrackedPreferenceValidationDelegate>( | 165 return scoped_ptr<TrackedPreferenceValidationDelegate>( |
| 117 new PreferenceValidationDelegate(GetAddIncidentCallback())); | 166 new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); |
| 118 } | 167 } |
| 119 | 168 |
| 120 void IncidentReportingService::SetCollectEnvironmentHook( | 169 void IncidentReportingService::SetCollectEnvironmentHook( |
| 121 CollectEnvironmentDataFn collect_environment_data_hook, | 170 CollectEnvironmentDataFn collect_environment_data_hook, |
| 122 const scoped_refptr<base::TaskRunner>& task_runner) { | 171 const scoped_refptr<base::TaskRunner>& task_runner) { |
| 123 if (collect_environment_data_hook) { | 172 if (collect_environment_data_hook) { |
| 124 collect_environment_data_fn_ = collect_environment_data_hook; | 173 collect_environment_data_fn_ = collect_environment_data_hook; |
| 125 environment_collection_task_runner_ = task_runner; | 174 environment_collection_task_runner_ = task_runner; |
| 126 } else { | 175 } else { |
| 127 collect_environment_data_fn_ = &CollectEnvironmentData; | 176 collect_environment_data_fn_ = &CollectEnvironmentData; |
| 128 environment_collection_task_runner_ = | 177 environment_collection_task_runner_ = |
| 129 content::BrowserThread::GetBlockingPool() | 178 content::BrowserThread::GetBlockingPool() |
| 130 ->GetTaskRunnerWithShutdownBehavior( | 179 ->GetTaskRunnerWithShutdownBehavior( |
| 131 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 180 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 132 } | 181 } |
| 133 } | 182 } |
| 134 | 183 |
| 184 void IncidentReportingService::OnProfileCreated(Profile* profile) { | |
| 185 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 186 | |
| 187 ProfileContext* context = GetOrCreateProfileContext(profile); | |
| 188 context->created = true; | |
| 189 | |
| 190 // Drop all incidents if this profile is not participating in safe browsing. | |
| 191 if (!context->incidents.empty() && | |
| 192 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | |
| 193 for (size_t i = 0; i < context->incidents.size(); ++i) { | |
| 194 LogIncidentDataType(DROPPED, *context->incidents[i]); | |
| 195 } | |
| 196 context->incidents.clear(); | |
| 197 } | |
| 198 } | |
| 199 | |
| 135 scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload( | 200 scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload( |
| 136 const IncidentReportUploader::OnResultCallback& callback, | 201 const IncidentReportUploader::OnResultCallback& callback, |
| 137 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, | 202 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, |
| 138 const ClientIncidentReport& report) { | 203 const ClientIncidentReport& report) { |
| 139 #if 0 | 204 #if 0 |
| 140 return IncidentReportUploaderImpl::UploadReport( | 205 return IncidentReportUploaderImpl::UploadReport( |
| 141 callback, request_context_getter, report).Pass(); | 206 callback, request_context_getter, report).Pass(); |
| 142 #else | 207 #else |
| 143 // TODO(grt): Remove this temporary suppression of all uploads. | 208 // TODO(grt): Remove this temporary suppression of all uploads. |
| 144 return scoped_ptr<IncidentReportUploader>(); | 209 return scoped_ptr<IncidentReportUploader>(); |
| 145 #endif | 210 #endif |
| 146 } | 211 } |
| 147 | 212 |
| 213 IncidentReportingService::ProfileContext* | |
| 214 IncidentReportingService::GetOrCreateProfileContext(Profile* profile) { | |
| 215 ProfileContextCollection::iterator it = | |
| 216 profiles_.insert(ProfileContextCollection::value_type(profile, NULL)) | |
| 217 .first; | |
| 218 if (!it->second) | |
| 219 it->second = new ProfileContext(); | |
| 220 return it->second; | |
| 221 } | |
| 222 | |
| 223 IncidentReportingService::ProfileContext* | |
| 224 IncidentReportingService::GetProfileContext(Profile* profile) { | |
| 225 ProfileContextCollection::iterator it = profiles_.find(profile); | |
| 226 return it == profiles_.end() ? NULL : it->second; | |
| 227 } | |
| 228 | |
| 229 void IncidentReportingService::OnProfileDestroyed(Profile* profile) { | |
| 230 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 231 | |
| 232 ProfileContextCollection::iterator it = profiles_.find(profile); | |
| 233 if (it == profiles_.end()) | |
| 234 return; | |
| 235 | |
| 236 // TODO(grt): Persist incidents for upload on future profile load. | |
| 237 | |
| 238 // Forget about this profile. Incidents not yet sent for upload are lost. | |
| 239 // No new incidents will be accepted for it. | |
| 240 delete it->second; | |
| 241 profiles_.erase(it); | |
| 242 } | |
| 243 | |
| 148 void IncidentReportingService::AddIncident( | 244 void IncidentReportingService::AddIncident( |
| 245 Profile* profile, | |
| 149 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { | 246 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { |
| 150 DCHECK(thread_checker_.CalledOnValidThread()); | 247 DCHECK(thread_checker_.CalledOnValidThread()); |
| 248 // Incidents outside the context of a profile are not supported at the moment. | |
| 249 DCHECK(profile); | |
| 151 | 250 |
| 152 // TODO(grt): Don't ignore incidents that arrive before | 251 ProfileContext* context = GetProfileContext(profile); |
| 153 // NOTIFICATION_PROFILE_CREATED; http://crbug.com/383365. | 252 // It is forbidden to call this function with a destroyed profile. |
| 154 if (!enabled_) | 253 DCHECK(context); |
| 254 | |
| 255 // Drop the incident immediately if profile creation has completed and the | |
| 256 // profile is not participating in safe browsing. | |
| 257 if (context->created && | |
| 258 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | |
| 259 LogIncidentDataType(DROPPED, *incident_data); | |
| 155 return; | 260 return; |
| 261 } | |
| 156 | 262 |
| 263 // Create a new report if this is the first incident ever or first since last | |
| 264 // upload. | |
| 157 if (!report_) { | 265 if (!report_) { |
| 158 report_.reset(new ClientIncidentReport()); | 266 report_.reset(new ClientIncidentReport()); |
| 159 first_incident_time_ = base::Time::Now(); | 267 first_incident_time_ = base::Time::Now(); |
| 160 } | 268 } |
| 269 | |
| 270 // Provide time to the new incident if the caller didn't provide it. | |
| 161 if (!incident_data->has_incident_time_msec()) | 271 if (!incident_data->has_incident_time_msec()) |
| 162 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); | 272 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); |
| 163 report_->mutable_incident()->AddAllocated(incident_data.release()); | 273 |
| 274 // Take ownership of the incident. | |
| 275 context->incidents.push_back(incident_data.release()); | |
| 164 | 276 |
| 165 if (!last_incident_time_.is_null()) { | 277 if (!last_incident_time_.is_null()) { |
| 166 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", | 278 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", |
| 167 base::TimeTicks::Now() - last_incident_time_); | 279 base::TimeTicks::Now() - last_incident_time_); |
| 168 } | 280 } |
| 169 last_incident_time_ = base::TimeTicks::Now(); | 281 last_incident_time_ = base::TimeTicks::Now(); |
| 170 | 282 |
| 171 // Persist the incident data. | 283 // Persist the incident data. |
| 172 | 284 |
| 173 // Restart the delay timer to send the report upon expiration. | 285 // Restart the delay timer to send the report upon expiration. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 report_.reset(); | 348 report_.reset(); |
| 237 } | 349 } |
| 238 | 350 |
| 239 void IncidentReportingService::OnCollectionTimeout() { | 351 void IncidentReportingService::OnCollectionTimeout() { |
| 240 DCHECK(thread_checker_.CalledOnValidThread()); | 352 DCHECK(thread_checker_.CalledOnValidThread()); |
| 241 | 353 |
| 242 // Exit early if collection was cancelled. | 354 // Exit early if collection was cancelled. |
| 243 if (!collection_timeout_pending_) | 355 if (!collection_timeout_pending_) |
| 244 return; | 356 return; |
| 245 | 357 |
| 358 // Wait another round if incidents have come in from a profile that has yet to | |
| 359 // complete creation. | |
| 360 for (ProfileContextCollection::iterator scan = profiles_.begin(); | |
| 361 scan != profiles_.end(); | |
| 362 ++scan) { | |
| 363 if (!scan->second->created && !scan->second->incidents.empty()) { | |
| 364 upload_timer_.Reset(); | |
| 365 return; | |
| 366 } | |
| 367 } | |
| 368 | |
| 246 collection_timeout_pending_ = false; | 369 collection_timeout_pending_ = false; |
| 247 | 370 |
| 248 UploadIfCollectionComplete(); | 371 UploadIfCollectionComplete(); |
| 249 } | 372 } |
| 250 | 373 |
| 251 void IncidentReportingService::CollectDownloadDetails( | 374 void IncidentReportingService::CollectDownloadDetails( |
| 252 ClientIncidentReport_DownloadDetails* download_details) { | 375 ClientIncidentReport_DownloadDetails* download_details) { |
| 253 DCHECK(thread_checker_.CalledOnValidThread()); | 376 DCHECK(thread_checker_.CalledOnValidThread()); |
| 254 // TODO(grt): collect download info; http://crbug.com/383042. | 377 // TODO(grt): collect download info; http://crbug.com/383042. |
| 255 } | 378 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 266 void IncidentReportingService::UploadIfCollectionComplete() { | 389 void IncidentReportingService::UploadIfCollectionComplete() { |
| 267 DCHECK(report_); | 390 DCHECK(report_); |
| 268 // Bail out if there are still outstanding collection tasks. | 391 // Bail out if there are still outstanding collection tasks. |
| 269 if (environment_collection_pending_ || collection_timeout_pending_) | 392 if (environment_collection_pending_ || collection_timeout_pending_) |
| 270 return; | 393 return; |
| 271 | 394 |
| 272 // Take ownership of the report and clear things for future reports. | 395 // Take ownership of the report and clear things for future reports. |
| 273 scoped_ptr<ClientIncidentReport> report(report_.Pass()); | 396 scoped_ptr<ClientIncidentReport> report(report_.Pass()); |
| 274 last_incident_time_ = base::TimeTicks(); | 397 last_incident_time_ = base::TimeTicks(); |
| 275 | 398 |
| 276 const int original_count = report->incident_size(); | 399 ClientIncidentReport_EnvironmentData_Process* process = |
| 277 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", original_count); | 400 report->mutable_environment()->mutable_process(); |
| 278 for (int i = 0; i < original_count; ++i) { | 401 |
| 279 LogIncidentDataType(report->incident(i)); | 402 // Not all platforms have a metrics reporting preference. |
| 403 if (g_browser_process->local_state()->FindPreference( | |
| 404 prefs::kMetricsReportingEnabled)) { | |
| 405 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( | |
| 406 prefs::kMetricsReportingEnabled)); | |
| 407 } | |
| 408 // Check for extended consent in any profile while collecting incidents. | |
| 409 process->set_extended_consent(false); | |
| 410 // Collect incidents across all profiles participating in safe browsing. Drop | |
| 411 // incidents if the profile stopped participating before collection completed. | |
| 412 for (ProfileContextCollection::iterator scan = profiles_.begin(); | |
| 413 scan != profiles_.end(); | |
| 414 ++scan) { | |
| 415 PrefService* prefs = scan->first->GetPrefs(); | |
| 416 if (process && | |
| 417 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { | |
| 418 process->set_extended_consent(true); | |
| 419 process = NULL; // Don't check any more once one is found. | |
| 420 } | |
| 421 ProfileContext* context = scan->second; | |
| 422 if (context->incidents.empty()) | |
| 423 continue; | |
| 424 if (prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { | |
| 425 for (size_t i = 0; i < context->incidents.size(); ++i) { | |
| 426 ClientIncidentReport_IncidentData* incident = context->incidents[i]; | |
| 427 LogIncidentDataType(ACCEPTED, *incident); | |
| 428 // Ownership of the incident is passed to the report. | |
| 429 report->mutable_incident()->AddAllocated(incident); | |
| 430 } | |
| 431 context->incidents.weak_clear(); | |
| 432 } else { | |
| 433 for (size_t i = 0; i < context->incidents.size(); ++i) { | |
| 434 LogIncidentDataType(DROPPED, *context->incidents[i]); | |
| 435 } | |
| 436 context->incidents.clear(); | |
| 437 } | |
| 280 } | 438 } |
| 281 | 439 |
| 440 const int original_count = report->incident_size(); | |
| 441 // Abandon the request if all incidents were dropped. | |
| 442 if (!original_count) | |
| 443 return; | |
| 444 | |
| 445 UMA_HISTOGRAM_COUNTS_100("SBIRS.IncidentCount", original_count); | |
| 446 | |
| 282 PruneReportedIncidents(report.get()); | 447 PruneReportedIncidents(report.get()); |
| 283 // TODO(grt): prune incidents from opted-out profiles; http://crbug.com/383039 | |
| 284 | 448 |
| 285 int final_count = report->incident_size(); | 449 int final_count = report->incident_size(); |
| 286 { | 450 { |
| 287 double prune_pct = static_cast<double>(original_count - final_count); | 451 double prune_pct = static_cast<double>(original_count - final_count); |
| 288 prune_pct = prune_pct * 100.0 / original_count; | 452 prune_pct = prune_pct * 100.0 / original_count; |
| 289 prune_pct = round(prune_pct); | 453 prune_pct = round(prune_pct); |
| 290 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); | 454 UMA_HISTOGRAM_PERCENTAGE("SBIRS.PruneRatio", static_cast<int>(prune_pct)); |
| 291 } | 455 } |
| 292 // Abandon the report if all incidents were pruned. | 456 // Abandon the report if all incidents were pruned. |
| 293 if (!final_count) | 457 if (!final_count) |
| 294 return; | 458 return; |
| 295 | 459 |
| 296 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); | 460 scoped_ptr<UploadContext> context(new UploadContext(report.Pass())); |
| 297 scoped_refptr<base::RefCountedData<bool> > is_killswitch_on( | |
| 298 new base::RefCountedData<bool>(false)); | |
| 299 if (!database_manager_) { | 461 if (!database_manager_) { |
| 300 // No database manager during testing. Take ownership of the context and | 462 // No database manager during testing. Take ownership of the context and |
| 301 // continue processing. | 463 // continue processing. |
| 302 UploadContext* temp_context = context.get(); | 464 UploadContext* temp_context = context.get(); |
| 303 uploads_.push_back(context.release()); | 465 uploads_.push_back(context.release()); |
| 304 IncidentReportingService::OnKillSwitchResult(temp_context, false); | 466 IncidentReportingService::OnKillSwitchResult(temp_context, false); |
| 305 } else { | 467 } else { |
| 306 if (content::BrowserThread::PostTaskAndReplyWithResult( | 468 if (content::BrowserThread::PostTaskAndReplyWithResult( |
| 307 content::BrowserThread::IO, | 469 content::BrowserThread::IO, |
| 308 FROM_HERE, | 470 FROM_HERE, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 DCHECK(it != uploads_.end()); | 533 DCHECK(it != uploads_.end()); |
| 372 scoped_ptr<UploadContext> upload(context); // == *it | 534 scoped_ptr<UploadContext> upload(context); // == *it |
| 373 *it = uploads_.back(); | 535 *it = uploads_.back(); |
| 374 uploads_.weak_erase(uploads_.end() - 1); | 536 uploads_.weak_erase(uploads_.end() - 1); |
| 375 | 537 |
| 376 if (result == IncidentReportUploader::UPLOAD_SUCCESS) | 538 if (result == IncidentReportUploader::UPLOAD_SUCCESS) |
| 377 HandleResponse(upload->report.Pass(), response.Pass()); | 539 HandleResponse(upload->report.Pass(), response.Pass()); |
| 378 // else retry? | 540 // else retry? |
| 379 } | 541 } |
| 380 | 542 |
| 543 void IncidentReportingService::Observe( | |
| 544 int type, | |
| 545 const content::NotificationSource& source, | |
| 546 const content::NotificationDetails& details) { | |
| 547 switch (type) { | |
| 548 case chrome::NOTIFICATION_PROFILE_CREATED: { | |
| 549 Profile* profile = content::Source<Profile>(source).ptr(); | |
| 550 if (!profile->IsOffTheRecord()) | |
| 551 OnProfileCreated(profile); | |
| 552 break; | |
| 553 } | |
| 554 case chrome::NOTIFICATION_PROFILE_DESTROYED: { | |
| 555 Profile* profile = content::Source<Profile>(source).ptr(); | |
| 556 if (!profile->IsOffTheRecord()) | |
| 557 OnProfileDestroyed(profile); | |
| 558 break; | |
| 559 } | |
| 560 default: | |
| 561 break; | |
| 562 } | |
| 563 } | |
| 564 | |
| 381 } // namespace safe_browsing | 565 } // namespace safe_browsing |
| OLD | NEW |