Index: chrome/browser/safe_browsing/incident_reporting_service.cc |
diff --git a/chrome/browser/safe_browsing/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting_service.cc |
index 6c8ce1b9f562fb94fc295ca70e1b3993c8c8d856..fc08e92453f93819c8a85f0b2b25892ca6f47829 100644 |
--- a/chrome/browser/safe_browsing/incident_reporting_service.cc |
+++ b/chrome/browser/safe_browsing/incident_reporting_service.cc |
@@ -70,6 +70,9 @@ struct PersistentIncidentState { |
// The amount of time the service will wait to collate incidents. |
const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute |
+// The amount of time between running delayed analysis callbacks. |
+const int64 kDefaultCallbackMs = 1000 * 20; |
+ |
// Returns the number of incidents contained in |incident|. The result is |
// expected to be 1. Used in DCHECKs. |
size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) { |
@@ -225,6 +228,9 @@ IncidentReportingService::IncidentReportingService( |
base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), |
this, |
&IncidentReportingService::OnCollectionTimeout), |
+ delayed_analysis_callbacks_( |
+ base::TimeDelta::FromMilliseconds(kDefaultCallbackMs), |
+ content::BrowserThread::GetBlockingPool()), |
receiver_weak_ptr_factory_(this), |
weak_ptr_factory_(this) { |
notification_registrar_.Add(this, |
@@ -270,6 +276,17 @@ IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { |
new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); |
} |
+void IncidentReportingService::RegisterDelayedAnalysisCallback( |
+ const DelayedAnalysisCallback& callback) { |
+ delayed_analysis_callbacks_.RegisterCallback( |
+ base::Bind(callback, GetAddIncidentCallback(NULL))); |
+ |
+ // Start running the callbacks if any profiles are participating in safe |
+ // browsing. |
+ if (FindEligibleProfile()) |
+ delayed_analysis_callbacks_.Start(); |
+} |
+ |
void IncidentReportingService::SetCollectEnvironmentHook( |
CollectEnvironmentDataFn collect_environment_data_hook, |
const scoped_refptr<base::TaskRunner>& task_runner) { |
@@ -294,17 +311,23 @@ void IncidentReportingService::OnProfileAdded(Profile* profile) { |
ProfileContext* context = GetOrCreateProfileContext(profile); |
context->added = true; |
+ const bool safe_browsing_enabled = |
+ profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled); |
+ |
+ // Start processing delayed analysis callbacks if this new profile |
+ // participates in safe browsing. |
+ if (safe_browsing_enabled) |
+ delayed_analysis_callbacks_.Start(); |
+ |
// Nothing else to do if a report is not being assembled. |
if (!report_) |
return; |
- // Drop all incidents received prior to creation if the profile is not |
- // participating in safe browsing. |
- if (!context->incidents.empty() && |
- !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { |
- for (size_t i = 0; i < context->incidents.size(); ++i) { |
+ // Drop all incidents associated with this profile that were received prior to |
+ // its addition if the profile is not participating in safe browsing. |
+ if (!context->incidents.empty() && !safe_browsing_enabled) { |
+ for (size_t i = 0; i < context->incidents.size(); ++i) |
LogIncidentDataType(DROPPED, *context->incidents[i]); |
- } |
context->incidents.clear(); |
} |
@@ -362,17 +385,39 @@ void IncidentReportingService::OnProfileDestroyed(Profile* profile) { |
uploads_[i]->profiles_to_state.erase(profile); |
} |
+Profile* IncidentReportingService::FindEligibleProfile() const { |
+ Profile* candidate = NULL; |
+ for (ProfileContextCollection::const_iterator scan = profiles_.begin(); |
+ scan != profiles_.end(); |
+ ++scan) { |
+ // Skip over profiles that have yet to be added to the profile manager. |
+ // This will also skip over the NULL-profile context used to hold |
+ // process-wide incidents. |
+ if (!scan->second->added) |
+ continue; |
+ PrefService* prefs = scan->first->GetPrefs(); |
+ if (prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { |
+ candidate = scan->first; |
+ break; |
+ } |
+ if (!candidate && prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) |
+ candidate = scan->first; |
+ } |
+ return candidate; |
+} |
+ |
void IncidentReportingService::AddIncident( |
Profile* profile, |
scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- // Incidents outside the context of a profile are not supported at the moment. |
- DCHECK(profile); |
DCHECK_EQ(1U, CountIncidents(*incident_data)); |
ProfileContext* context = GetProfileContext(profile); |
// It is forbidden to call this function with a destroyed profile. |
DCHECK(context); |
+ // If this is a process-wide incident, the context must not indicate that the |
+ // profile (which is NULL) has been added to the profile manager. |
+ DCHECK(profile || !context->added); |
// Drop the incident immediately if profile creation has completed and the |
// profile is not participating in safe browsing. Preference evaluation is |
@@ -490,12 +535,14 @@ void IncidentReportingService::OnCollectionTimeout() { |
if (!collection_timeout_pending_) |
return; |
- // Wait another round if incidents have come in from a profile that has yet to |
- // complete creation. |
+ // Wait another round if profile-bound incidents have come in from a profile |
+ // that has yet to complete creation. |
for (ProfileContextCollection::iterator scan = profiles_.begin(); |
scan != profiles_.end(); |
++scan) { |
- if (!scan->second->added && !scan->second->incidents.empty()) { |
+ if (scan->first && |
+ !scan->second->added && |
+ !scan->second->incidents.empty()) { |
upload_timer_.Reset(); |
return; |
} |
@@ -601,8 +648,28 @@ void IncidentReportingService::UploadIfCollectionComplete() { |
prefs::kMetricsReportingEnabled)); |
} |
- // Check for extended consent in any profile while collecting incidents. |
- process->set_extended_consent(false); |
+ // Find a profile suitable for tracking process-wide incidents. |
+ Profile* analyses_profile = FindEligibleProfile(); |
+ process->set_extended_consent( |
+ analyses_profile ? analyses_profile->GetPrefs()->GetBoolean( |
+ prefs::kSafeBrowsingExtendedReportingEnabled) : |
+ false); |
+ |
+ // Associate process-wide incidents with the analyses profile. |
+ ProfileContext* null_context = GetProfileContext(NULL); |
+ if (null_context && analyses_profile) { |
+ DCHECK(!null_context->incidents.empty()); |
+ ProfileContext* analyses_context = GetProfileContext(analyses_profile); |
+ // Move the incidents to the target context. |
+ analyses_context->incidents.insert(analyses_context->incidents.end(), |
+ null_context->incidents.begin(), |
+ null_context->incidents.end()); |
+ null_context->incidents.weak_clear(); |
+ // Delete the process-wide context. |
+ delete null_context; |
+ profiles_.erase(NULL); |
+ } |
+ |
// Collect incidents across all profiles participating in safe browsing. Drop |
// incidents if the profile stopped participating before collection completed. |
// Prune previously submitted incidents. |
@@ -612,12 +679,11 @@ void IncidentReportingService::UploadIfCollectionComplete() { |
for (ProfileContextCollection::iterator scan = profiles_.begin(); |
scan != profiles_.end(); |
++scan) { |
+ // Bypass process-wide incidents that have not yet been associated with a |
+ // profile. |
+ if (!scan->first) |
+ continue; |
PrefService* prefs = scan->first->GetPrefs(); |
- if (process && |
- prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { |
- process->set_extended_consent(true); |
- process = NULL; // Don't check any more once one is found. |
- } |
ProfileContext* context = scan->second; |
if (context->incidents.empty()) |
continue; |