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

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

Issue 441453002: Support for process-wide incidents in the safe browsing incident reporting service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 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>
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // The key for a specific instance of an incident. 63 // The key for a specific instance of an incident.
64 std::string key; 64 std::string key;
65 65
66 // A hash digest representing a specific instance of an incident. 66 // A hash digest representing a specific instance of an incident.
67 uint32_t digest; 67 uint32_t digest;
68 }; 68 };
69 69
70 // The amount of time the service will wait to collate incidents. 70 // The amount of time the service will wait to collate incidents.
71 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute 71 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute
72 72
73 // The amount of time between running delayed analysis callbacks.
74 const int64 kDefaultCallbackMs = 1000 * 20;
75
73 // Returns the number of incidents contained in |incident|. The result is 76 // Returns the number of incidents contained in |incident|. The result is
74 // expected to be 1. Used in DCHECKs. 77 // expected to be 1. Used in DCHECKs.
75 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) { 78 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) {
76 size_t result = 0; 79 size_t result = 0;
77 if (incident.has_tracked_preference()) 80 if (incident.has_tracked_preference())
78 ++result; 81 ++result;
79 // Add detection for new incident types here. 82 // Add detection for new incident types here.
80 return result; 83 return result;
81 } 84 }
82 85
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 environment_collection_task_runner_( 221 environment_collection_task_runner_(
219 content::BrowserThread::GetBlockingPool() 222 content::BrowserThread::GetBlockingPool()
220 ->GetTaskRunnerWithShutdownBehavior( 223 ->GetTaskRunnerWithShutdownBehavior(
221 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), 224 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
222 environment_collection_pending_(), 225 environment_collection_pending_(),
223 collection_timeout_pending_(), 226 collection_timeout_pending_(),
224 upload_timer_(FROM_HERE, 227 upload_timer_(FROM_HERE,
225 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), 228 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs),
226 this, 229 this,
227 &IncidentReportingService::OnCollectionTimeout), 230 &IncidentReportingService::OnCollectionTimeout),
231 delayed_analysis_callbacks_(
232 base::TimeDelta::FromMilliseconds(kDefaultCallbackMs),
233 content::BrowserThread::GetBlockingPool()),
228 receiver_weak_ptr_factory_(this), 234 receiver_weak_ptr_factory_(this),
229 weak_ptr_factory_(this) { 235 weak_ptr_factory_(this) {
230 notification_registrar_.Add(this, 236 notification_registrar_.Add(this,
231 chrome::NOTIFICATION_PROFILE_ADDED, 237 chrome::NOTIFICATION_PROFILE_ADDED,
232 content::NotificationService::AllSources()); 238 content::NotificationService::AllSources());
233 notification_registrar_.Add(this, 239 notification_registrar_.Add(this,
234 chrome::NOTIFICATION_PROFILE_DESTROYED, 240 chrome::NOTIFICATION_PROFILE_DESTROYED,
235 content::NotificationService::AllSources()); 241 content::NotificationService::AllSources());
236 } 242 }
237 243
(...skipping 25 matching lines...) Expand all
263 scoped_ptr<TrackedPreferenceValidationDelegate> 269 scoped_ptr<TrackedPreferenceValidationDelegate>
264 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { 270 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) {
265 DCHECK(thread_checker_.CalledOnValidThread()); 271 DCHECK(thread_checker_.CalledOnValidThread());
266 272
267 if (profile->IsOffTheRecord()) 273 if (profile->IsOffTheRecord())
268 return scoped_ptr<TrackedPreferenceValidationDelegate>(); 274 return scoped_ptr<TrackedPreferenceValidationDelegate>();
269 return scoped_ptr<TrackedPreferenceValidationDelegate>( 275 return scoped_ptr<TrackedPreferenceValidationDelegate>(
270 new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); 276 new PreferenceValidationDelegate(GetAddIncidentCallback(profile)));
271 } 277 }
272 278
279 void IncidentReportingService::RegisterDelayedAnalysisCallback(
280 const DelayedAnalysisCallback& callback) {
281 delayed_analysis_callbacks_.RegisterCallback(
282 base::Bind(callback, GetAddIncidentCallback(NULL)));
283
284 // Start running the callbacks if any profiles are participating in safe
285 // browsing.
286 if (FindEligibleProfile())
287 delayed_analysis_callbacks_.Start();
288 }
289
273 void IncidentReportingService::SetCollectEnvironmentHook( 290 void IncidentReportingService::SetCollectEnvironmentHook(
274 CollectEnvironmentDataFn collect_environment_data_hook, 291 CollectEnvironmentDataFn collect_environment_data_hook,
275 const scoped_refptr<base::TaskRunner>& task_runner) { 292 const scoped_refptr<base::TaskRunner>& task_runner) {
276 if (collect_environment_data_hook) { 293 if (collect_environment_data_hook) {
277 collect_environment_data_fn_ = collect_environment_data_hook; 294 collect_environment_data_fn_ = collect_environment_data_hook;
278 environment_collection_task_runner_ = task_runner; 295 environment_collection_task_runner_ = task_runner;
279 } else { 296 } else {
280 collect_environment_data_fn_ = &CollectEnvironmentData; 297 collect_environment_data_fn_ = &CollectEnvironmentData;
281 environment_collection_task_runner_ = 298 environment_collection_task_runner_ =
282 content::BrowserThread::GetBlockingPool() 299 content::BrowserThread::GetBlockingPool()
283 ->GetTaskRunnerWithShutdownBehavior( 300 ->GetTaskRunnerWithShutdownBehavior(
284 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 301 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
285 } 302 }
286 } 303 }
287 304
288 void IncidentReportingService::OnProfileAdded(Profile* profile) { 305 void IncidentReportingService::OnProfileAdded(Profile* profile) {
289 DCHECK(thread_checker_.CalledOnValidThread()); 306 DCHECK(thread_checker_.CalledOnValidThread());
290 307
291 // Track the addition of all profiles even when no report is being assembled 308 // Track the addition of all profiles even when no report is being assembled
292 // so that the service can determine whether or not it can evaluate a 309 // so that the service can determine whether or not it can evaluate a
293 // profile's preferences at the time of incident addition. 310 // profile's preferences at the time of incident addition.
294 ProfileContext* context = GetOrCreateProfileContext(profile); 311 ProfileContext* context = GetOrCreateProfileContext(profile);
295 context->added = true; 312 context->added = true;
296 313
314 const bool safe_browsing_enabled =
315 profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled);
316
317 // Start processing delayed analysis callbacks if this new profile
318 // participates in safe browsing.
319 if (safe_browsing_enabled)
320 delayed_analysis_callbacks_.Start();
321
297 // Nothing else to do if a report is not being assembled. 322 // Nothing else to do if a report is not being assembled.
298 if (!report_) 323 if (!report_)
299 return; 324 return;
300 325
301 // Drop all incidents received prior to creation if the profile is not 326 // Drop all incidents associated with this profile that were received prior to
302 // participating in safe browsing. 327 // its addition if the profile is not participating in safe browsing.
303 if (!context->incidents.empty() && 328 if (!context->incidents.empty() && !safe_browsing_enabled) {
304 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { 329 for (size_t i = 0; i < context->incidents.size(); ++i)
305 for (size_t i = 0; i < context->incidents.size(); ++i) {
306 LogIncidentDataType(DROPPED, *context->incidents[i]); 330 LogIncidentDataType(DROPPED, *context->incidents[i]);
307 }
308 context->incidents.clear(); 331 context->incidents.clear();
309 } 332 }
310 333
311 // Take another stab at finding the most recent download if a report is being 334 // Take another stab at finding the most recent download if a report is being
312 // assembled and one hasn't been found yet (the LastDownloadFinder operates 335 // assembled and one hasn't been found yet (the LastDownloadFinder operates
313 // only on profiles that have been added to the ProfileManager). 336 // only on profiles that have been added to the ProfileManager).
314 BeginDownloadCollection(); 337 BeginDownloadCollection();
315 } 338 }
316 339
317 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( 340 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder(
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 // Forget about this profile. Incidents not yet sent for upload are lost. 378 // Forget about this profile. Incidents not yet sent for upload are lost.
356 // No new incidents will be accepted for it. 379 // No new incidents will be accepted for it.
357 delete it->second; 380 delete it->second;
358 profiles_.erase(it); 381 profiles_.erase(it);
359 382
360 // Remove the association with this profile from all pending uploads. 383 // Remove the association with this profile from all pending uploads.
361 for (size_t i = 0; i < uploads_.size(); ++i) 384 for (size_t i = 0; i < uploads_.size(); ++i)
362 uploads_[i]->profiles_to_state.erase(profile); 385 uploads_[i]->profiles_to_state.erase(profile);
363 } 386 }
364 387
388 Profile* IncidentReportingService::FindEligibleProfile() const {
389 Profile* candidate = NULL;
390 for (ProfileContextCollection::const_iterator scan = profiles_.begin();
391 scan != profiles_.end();
392 ++scan) {
393 // Skip over profiles that have yet to be added to the profile manager.
394 // This will also skip over the NULL-profile context used to hold
395 // process-wide incidents.
396 if (!scan->second->added)
397 continue;
398 PrefService* prefs = scan->first->GetPrefs();
399 if (prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
400 candidate = scan->first;
401 break;
402 }
403 if (!candidate && prefs->GetBoolean(prefs::kSafeBrowsingEnabled))
404 candidate = scan->first;
405 }
406 return candidate;
407 }
408
365 void IncidentReportingService::AddIncident( 409 void IncidentReportingService::AddIncident(
366 Profile* profile, 410 Profile* profile,
367 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 411 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
368 DCHECK(thread_checker_.CalledOnValidThread()); 412 DCHECK(thread_checker_.CalledOnValidThread());
369 // Incidents outside the context of a profile are not supported at the moment.
370 DCHECK(profile);
371 DCHECK_EQ(1U, CountIncidents(*incident_data)); 413 DCHECK_EQ(1U, CountIncidents(*incident_data));
372 414
373 ProfileContext* context = GetProfileContext(profile); 415 ProfileContext* context = GetProfileContext(profile);
374 // It is forbidden to call this function with a destroyed profile. 416 // It is forbidden to call this function with a destroyed profile.
375 DCHECK(context); 417 DCHECK(context);
418 // If this is a process-wide incident, the context must not indicate that the
419 // profile (which is NULL) has been added to the profile manager.
420 DCHECK(profile || !context->added);
376 421
377 // Drop the incident immediately if profile creation has completed and the 422 // Drop the incident immediately if profile creation has completed and the
378 // profile is not participating in safe browsing. Preference evaluation is 423 // profile is not participating in safe browsing. Preference evaluation is
379 // deferred until OnProfileAdded() if profile creation has not yet 424 // deferred until OnProfileAdded() if profile creation has not yet
380 // completed. 425 // completed.
381 if (context->added && 426 if (context->added &&
382 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { 427 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
383 LogIncidentDataType(DROPPED, *incident_data); 428 LogIncidentDataType(DROPPED, *incident_data);
384 return; 429 return;
385 } 430 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 report_.reset(); 528 report_.reset();
484 } 529 }
485 530
486 void IncidentReportingService::OnCollectionTimeout() { 531 void IncidentReportingService::OnCollectionTimeout() {
487 DCHECK(thread_checker_.CalledOnValidThread()); 532 DCHECK(thread_checker_.CalledOnValidThread());
488 533
489 // Exit early if collection was cancelled. 534 // Exit early if collection was cancelled.
490 if (!collection_timeout_pending_) 535 if (!collection_timeout_pending_)
491 return; 536 return;
492 537
493 // Wait another round if incidents have come in from a profile that has yet to 538 // Wait another round if profile-bound incidents have come in from a profile
494 // complete creation. 539 // that has yet to complete creation.
495 for (ProfileContextCollection::iterator scan = profiles_.begin(); 540 for (ProfileContextCollection::iterator scan = profiles_.begin();
496 scan != profiles_.end(); 541 scan != profiles_.end();
497 ++scan) { 542 ++scan) {
498 if (!scan->second->added && !scan->second->incidents.empty()) { 543 if (scan->first &&
544 !scan->second->added &&
545 !scan->second->incidents.empty()) {
499 upload_timer_.Reset(); 546 upload_timer_.Reset();
500 return; 547 return;
501 } 548 }
502 } 549 }
503 550
504 collection_timeout_pending_ = false; 551 collection_timeout_pending_ = false;
505 552
506 UploadIfCollectionComplete(); 553 UploadIfCollectionComplete();
507 } 554 }
508 555
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 ClientIncidentReport_EnvironmentData_Process* process = 641 ClientIncidentReport_EnvironmentData_Process* process =
595 report->mutable_environment()->mutable_process(); 642 report->mutable_environment()->mutable_process();
596 643
597 // Not all platforms have a metrics reporting preference. 644 // Not all platforms have a metrics reporting preference.
598 if (g_browser_process->local_state()->FindPreference( 645 if (g_browser_process->local_state()->FindPreference(
599 prefs::kMetricsReportingEnabled)) { 646 prefs::kMetricsReportingEnabled)) {
600 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 647 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
601 prefs::kMetricsReportingEnabled)); 648 prefs::kMetricsReportingEnabled));
602 } 649 }
603 650
604 // Check for extended consent in any profile while collecting incidents. 651 // Find a profile suitable for tracking process-wide incidents.
605 process->set_extended_consent(false); 652 Profile* analyses_profile = FindEligibleProfile();
653 process->set_extended_consent(
654 analyses_profile ? analyses_profile->GetPrefs()->GetBoolean(
655 prefs::kSafeBrowsingExtendedReportingEnabled) :
656 false);
657
658 // Associate process-wide incidents with the analyses profile.
659 ProfileContext* null_context = GetProfileContext(NULL);
660 if (null_context && analyses_profile) {
661 DCHECK(!null_context->incidents.empty());
662 ProfileContext* analyses_context = GetProfileContext(analyses_profile);
663 // Move the incidents to the target context.
664 analyses_context->incidents.insert(analyses_context->incidents.end(),
665 null_context->incidents.begin(),
666 null_context->incidents.end());
667 null_context->incidents.weak_clear();
668 // Delete the process-wide context.
669 delete null_context;
670 profiles_.erase(NULL);
671 }
672
606 // Collect incidents across all profiles participating in safe browsing. Drop 673 // Collect incidents across all profiles participating in safe browsing. Drop
607 // incidents if the profile stopped participating before collection completed. 674 // incidents if the profile stopped participating before collection completed.
608 // Prune previously submitted incidents. 675 // Prune previously submitted incidents.
609 // Associate the profiles and their incident data with the upload. 676 // Associate the profiles and their incident data with the upload.
610 size_t prune_count = 0; 677 size_t prune_count = 0;
611 UploadContext::PersistentIncidentStateCollection profiles_to_state; 678 UploadContext::PersistentIncidentStateCollection profiles_to_state;
612 for (ProfileContextCollection::iterator scan = profiles_.begin(); 679 for (ProfileContextCollection::iterator scan = profiles_.begin();
613 scan != profiles_.end(); 680 scan != profiles_.end();
614 ++scan) { 681 ++scan) {
682 // Bypass process-wide incidents that have not yet been associated with a
683 // profile.
684 if (!scan->first)
685 continue;
615 PrefService* prefs = scan->first->GetPrefs(); 686 PrefService* prefs = scan->first->GetPrefs();
616 if (process &&
617 prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
618 process->set_extended_consent(true);
619 process = NULL; // Don't check any more once one is found.
620 }
621 ProfileContext* context = scan->second; 687 ProfileContext* context = scan->second;
622 if (context->incidents.empty()) 688 if (context->incidents.empty())
623 continue; 689 continue;
624 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 690 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
625 for (size_t i = 0; i < context->incidents.size(); ++i) { 691 for (size_t i = 0; i < context->incidents.size(); ++i) {
626 LogIncidentDataType(DROPPED, *context->incidents[i]); 692 LogIncidentDataType(DROPPED, *context->incidents[i]);
627 } 693 }
628 context->incidents.clear(); 694 context->incidents.clear();
629 continue; 695 continue;
630 } 696 }
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 if (!profile->IsOffTheRecord()) 859 if (!profile->IsOffTheRecord())
794 OnProfileDestroyed(profile); 860 OnProfileDestroyed(profile);
795 break; 861 break;
796 } 862 }
797 default: 863 default:
798 break; 864 break;
799 } 865 }
800 } 866 }
801 867
802 } // namespace safe_browsing 868 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698