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 <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/prefs/scoped_user_pref_update.h" |
15 #include "base/process/process_info.h" | 15 #include "base/process/process_info.h" |
16 #include "base/single_thread_task_runner.h" | |
16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
19 #include "base/thread_task_runner_handle.h" | |
18 #include "base/threading/sequenced_worker_pool.h" | 20 #include "base/threading/sequenced_worker_pool.h" |
19 #include "base/values.h" | 21 #include "base/values.h" |
20 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/browser_process.h" |
21 #include "chrome/browser/chrome_notification_types.h" | 23 #include "chrome/browser/chrome_notification_types.h" |
22 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" | 24 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h" |
23 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
24 #include "chrome/browser/safe_browsing/database_manager.h" | 26 #include "chrome/browser/safe_browsing/database_manager.h" |
25 #include "chrome/browser/safe_browsing/environment_data_collection.h" | 27 #include "chrome/browser/safe_browsing/environment_data_collection.h" |
26 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" | 28 #include "chrome/browser/safe_browsing/incident_report_uploader_impl.h" |
27 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" | 29 #include "chrome/browser/safe_browsing/preference_validation_delegate.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 // The key for a specific instance of an incident. | 65 // The key for a specific instance of an incident. |
64 std::string key; | 66 std::string key; |
65 | 67 |
66 // A hash digest representing a specific instance of an incident. | 68 // A hash digest representing a specific instance of an incident. |
67 uint32_t digest; | 69 uint32_t digest; |
68 }; | 70 }; |
69 | 71 |
70 // The amount of time the service will wait to collate incidents. | 72 // The amount of time the service will wait to collate incidents. |
71 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute | 73 const int64 kDefaultUploadDelayMs = 1000 * 60; // one minute |
72 | 74 |
75 // The amount of time between running delayed analysis callbacks. | |
76 const int64 kDefaultCallbackMs = 1000 * 20; | |
robertshield
2014/08/05 21:26:28
how about kDefaultCallbackIntervalMs ?
grt (UTC plus 2)
2014/08/06 02:37:31
Done.
| |
77 | |
73 // Returns the number of incidents contained in |incident|. The result is | 78 // Returns the number of incidents contained in |incident|. The result is |
74 // expected to be 1. Used in DCHECKs. | 79 // expected to be 1. Used in DCHECKs. |
75 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) { | 80 size_t CountIncidents(const ClientIncidentReport_IncidentData& incident) { |
76 size_t result = 0; | 81 size_t result = 0; |
77 if (incident.has_tracked_preference()) | 82 if (incident.has_tracked_preference()) |
78 ++result; | 83 ++result; |
79 // Add detection for new incident types here. | 84 // Add detection for new incident types here. |
80 return result; | 85 return result; |
81 } | 86 } |
82 | 87 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string, | 155 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string, |
151 &type_dict)) { | 156 &type_dict)) { |
152 type_dict = new base::DictionaryValue(); | 157 type_dict = new base::DictionaryValue(); |
153 incidents_sent->SetWithoutPathExpansion(type_string, type_dict); | 158 incidents_sent->SetWithoutPathExpansion(type_string, type_dict); |
154 } | 159 } |
155 type_dict->SetStringWithoutPathExpansion(data.key, | 160 type_dict->SetStringWithoutPathExpansion(data.key, |
156 base::UintToString(data.digest)); | 161 base::UintToString(data.digest)); |
157 } | 162 } |
158 } | 163 } |
159 | 164 |
165 // Runs |callback| on the thread to which |thread_runner| belongs. The callback | |
166 // is run immediately if this function is called on |thread_runner|'s thread. | |
167 void AddIncidentOnOriginThread( | |
168 const AddIncidentCallback& callback, | |
169 scoped_refptr<base::SingleThreadTaskRunner> thread_runner, | |
170 scoped_ptr<ClientIncidentReport_IncidentData> incident) { | |
171 if (thread_runner->BelongsToCurrentThread()) | |
172 callback.Run(incident.Pass()); | |
173 else | |
174 thread_runner->PostTask(FROM_HERE, | |
175 base::Bind(callback, base::Passed(&incident))); | |
176 } | |
177 | |
160 } // namespace | 178 } // namespace |
161 | 179 |
162 struct IncidentReportingService::ProfileContext { | 180 struct IncidentReportingService::ProfileContext { |
163 ProfileContext(); | 181 ProfileContext(); |
164 ~ProfileContext(); | 182 ~ProfileContext(); |
165 | 183 |
166 // The incidents collected for this profile pending creation and/or upload. | 184 // The incidents collected for this profile pending creation and/or upload. |
167 ScopedVector<ClientIncidentReport_IncidentData> incidents; | 185 ScopedVector<ClientIncidentReport_IncidentData> incidents; |
168 | 186 |
169 // False until PROFILE_ADDED notification is received. | 187 // False until PROFILE_ADDED notification is received. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) | 231 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) |
214 : database_manager_(safe_browsing_service ? | 232 : database_manager_(safe_browsing_service ? |
215 safe_browsing_service->database_manager() : NULL), | 233 safe_browsing_service->database_manager() : NULL), |
216 url_request_context_getter_(request_context_getter), | 234 url_request_context_getter_(request_context_getter), |
217 collect_environment_data_fn_(&CollectEnvironmentData), | 235 collect_environment_data_fn_(&CollectEnvironmentData), |
218 environment_collection_task_runner_( | 236 environment_collection_task_runner_( |
219 content::BrowserThread::GetBlockingPool() | 237 content::BrowserThread::GetBlockingPool() |
220 ->GetTaskRunnerWithShutdownBehavior( | 238 ->GetTaskRunnerWithShutdownBehavior( |
221 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), | 239 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), |
222 environment_collection_pending_(), | 240 environment_collection_pending_(), |
223 collection_timeout_pending_(), | 241 collation_timeout_pending_(), |
224 upload_timer_(FROM_HERE, | 242 collation_timer_(FROM_HERE, |
225 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), | 243 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), |
226 this, | 244 this, |
227 &IncidentReportingService::OnCollectionTimeout), | 245 &IncidentReportingService::OnCollationTimeout), |
246 delayed_analysis_callbacks_( | |
247 base::TimeDelta::FromMilliseconds(kDefaultCallbackMs), | |
248 content::BrowserThread::GetBlockingPool()), | |
228 receiver_weak_ptr_factory_(this), | 249 receiver_weak_ptr_factory_(this), |
229 weak_ptr_factory_(this) { | 250 weak_ptr_factory_(this) { |
230 notification_registrar_.Add(this, | 251 notification_registrar_.Add(this, |
231 chrome::NOTIFICATION_PROFILE_ADDED, | 252 chrome::NOTIFICATION_PROFILE_ADDED, |
232 content::NotificationService::AllSources()); | 253 content::NotificationService::AllSources()); |
233 notification_registrar_.Add(this, | 254 notification_registrar_.Add(this, |
234 chrome::NOTIFICATION_PROFILE_DESTROYED, | 255 chrome::NOTIFICATION_PROFILE_DESTROYED, |
235 content::NotificationService::AllSources()); | 256 content::NotificationService::AllSources()); |
236 } | 257 } |
237 | 258 |
(...skipping 25 matching lines...) Expand all Loading... | |
263 scoped_ptr<TrackedPreferenceValidationDelegate> | 284 scoped_ptr<TrackedPreferenceValidationDelegate> |
264 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { | 285 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { |
265 DCHECK(thread_checker_.CalledOnValidThread()); | 286 DCHECK(thread_checker_.CalledOnValidThread()); |
266 | 287 |
267 if (profile->IsOffTheRecord()) | 288 if (profile->IsOffTheRecord()) |
268 return scoped_ptr<TrackedPreferenceValidationDelegate>(); | 289 return scoped_ptr<TrackedPreferenceValidationDelegate>(); |
269 return scoped_ptr<TrackedPreferenceValidationDelegate>( | 290 return scoped_ptr<TrackedPreferenceValidationDelegate>( |
270 new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); | 291 new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); |
271 } | 292 } |
272 | 293 |
294 void IncidentReportingService::RegisterDelayedAnalysisCallback( | |
295 const DelayedAnalysisCallback& callback) { | |
296 DCHECK(thread_checker_.CalledOnValidThread()); | |
297 | |
298 // |callback| will be run on the blocking pool, so it will likely run the | |
299 // AddIncidentCallback there as well. Bounce the run of that callback back to | |
300 // the main thread via AddIncidentOnOriginThread. | |
robertshield
2014/08/05 21:26:28
s/main/current ?
grt (UTC plus 2)
2014/08/06 02:37:31
Done.
| |
301 delayed_analysis_callbacks_.RegisterCallback( | |
302 base::Bind(callback, | |
303 base::Bind(&AddIncidentOnOriginThread, | |
304 GetAddIncidentCallback(NULL), | |
305 base::ThreadTaskRunnerHandle::Get()))); | |
306 | |
307 // Start running the callbacks if any profiles are participating in safe | |
308 // browsing. If none are now, running will commence if/when a participaing | |
309 // profile is added. | |
310 if (FindEligibleProfile()) | |
311 delayed_analysis_callbacks_.Start(); | |
312 } | |
313 | |
273 void IncidentReportingService::SetCollectEnvironmentHook( | 314 void IncidentReportingService::SetCollectEnvironmentHook( |
274 CollectEnvironmentDataFn collect_environment_data_hook, | 315 CollectEnvironmentDataFn collect_environment_data_hook, |
275 const scoped_refptr<base::TaskRunner>& task_runner) { | 316 const scoped_refptr<base::TaskRunner>& task_runner) { |
276 if (collect_environment_data_hook) { | 317 if (collect_environment_data_hook) { |
277 collect_environment_data_fn_ = collect_environment_data_hook; | 318 collect_environment_data_fn_ = collect_environment_data_hook; |
278 environment_collection_task_runner_ = task_runner; | 319 environment_collection_task_runner_ = task_runner; |
279 } else { | 320 } else { |
280 collect_environment_data_fn_ = &CollectEnvironmentData; | 321 collect_environment_data_fn_ = &CollectEnvironmentData; |
281 environment_collection_task_runner_ = | 322 environment_collection_task_runner_ = |
282 content::BrowserThread::GetBlockingPool() | 323 content::BrowserThread::GetBlockingPool() |
283 ->GetTaskRunnerWithShutdownBehavior( | 324 ->GetTaskRunnerWithShutdownBehavior( |
284 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 325 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
285 } | 326 } |
286 } | 327 } |
287 | 328 |
288 void IncidentReportingService::OnProfileAdded(Profile* profile) { | 329 void IncidentReportingService::OnProfileAdded(Profile* profile) { |
289 DCHECK(thread_checker_.CalledOnValidThread()); | 330 DCHECK(thread_checker_.CalledOnValidThread()); |
290 | 331 |
291 // Track the addition of all profiles even when no report is being assembled | 332 // 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 | 333 // so that the service can determine whether or not it can evaluate a |
293 // profile's preferences at the time of incident addition. | 334 // profile's preferences at the time of incident addition. |
294 ProfileContext* context = GetOrCreateProfileContext(profile); | 335 ProfileContext* context = GetOrCreateProfileContext(profile); |
295 context->added = true; | 336 context->added = true; |
296 | 337 |
338 const bool safe_browsing_enabled = | |
339 profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled); | |
340 | |
341 // Start processing delayed analysis callbacks if this new profile | |
342 // participates in safe browsing. | |
robertshield
2014/08/05 21:26:28
Re-mention here how Start() is idempotent for repe
grt (UTC plus 2)
2014/08/06 02:37:31
Done.
| |
343 if (safe_browsing_enabled) | |
344 delayed_analysis_callbacks_.Start(); | |
345 | |
346 // Start a new report if this profile participates in safe browsing and there | |
347 // are process-wide incidents. | |
348 if (safe_browsing_enabled && GetProfileContext(NULL)) | |
349 BeginReportProcessing(); | |
350 | |
351 // TODO(grt): register for pref change notifications to start delayed analysis | |
352 // and/or report processing if sb is currently disabled but subsequently | |
353 // enabled. | |
354 | |
297 // Nothing else to do if a report is not being assembled. | 355 // Nothing else to do if a report is not being assembled. |
298 if (!report_) | 356 if (!report_) |
299 return; | 357 return; |
300 | 358 |
301 // Drop all incidents received prior to creation if the profile is not | 359 // Drop all incidents associated with this profile that were received prior to |
302 // participating in safe browsing. | 360 // its addition if the profile is not participating in safe browsing. |
303 if (!context->incidents.empty() && | 361 if (!context->incidents.empty() && !safe_browsing_enabled) { |
304 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | 362 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]); | 363 LogIncidentDataType(DROPPED, *context->incidents[i]); |
307 } | |
308 context->incidents.clear(); | 364 context->incidents.clear(); |
309 } | 365 } |
310 | 366 |
311 // Take another stab at finding the most recent download if a report is being | 367 // 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 | 368 // assembled and one hasn't been found yet (the LastDownloadFinder operates |
313 // only on profiles that have been added to the ProfileManager). | 369 // only on profiles that have been added to the ProfileManager). |
314 BeginDownloadCollection(); | 370 BeginDownloadCollection(); |
315 } | 371 } |
316 | 372 |
317 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( | 373 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 // Forget about this profile. Incidents not yet sent for upload are lost. | 411 // Forget about this profile. Incidents not yet sent for upload are lost. |
356 // No new incidents will be accepted for it. | 412 // No new incidents will be accepted for it. |
357 delete it->second; | 413 delete it->second; |
358 profiles_.erase(it); | 414 profiles_.erase(it); |
359 | 415 |
360 // Remove the association with this profile from all pending uploads. | 416 // Remove the association with this profile from all pending uploads. |
361 for (size_t i = 0; i < uploads_.size(); ++i) | 417 for (size_t i = 0; i < uploads_.size(); ++i) |
362 uploads_[i]->profiles_to_state.erase(profile); | 418 uploads_[i]->profiles_to_state.erase(profile); |
363 } | 419 } |
364 | 420 |
421 Profile* IncidentReportingService::FindEligibleProfile() const { | |
422 Profile* candidate = NULL; | |
423 for (ProfileContextCollection::const_iterator scan = profiles_.begin(); | |
424 scan != profiles_.end(); | |
425 ++scan) { | |
426 // Skip over profiles that have yet to be added to the profile manager. | |
427 // This will also skip over the NULL-profile context used to hold | |
428 // process-wide incidents. | |
429 if (!scan->second->added) | |
430 continue; | |
431 PrefService* prefs = scan->first->GetPrefs(); | |
432 if (prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) { | |
mattm
2014/08/06 02:10:17
Need to check prefs::kSafeBrowsingEnabled too (ext
grt (UTC plus 2)
2014/08/06 02:37:31
Done.
| |
433 candidate = scan->first; | |
434 break; | |
435 } | |
436 if (!candidate && prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) | |
437 candidate = scan->first; | |
438 } | |
439 return candidate; | |
440 } | |
441 | |
365 void IncidentReportingService::AddIncident( | 442 void IncidentReportingService::AddIncident( |
366 Profile* profile, | 443 Profile* profile, |
367 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { | 444 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { |
368 DCHECK(thread_checker_.CalledOnValidThread()); | 445 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)); | 446 DCHECK_EQ(1U, CountIncidents(*incident_data)); |
372 | 447 |
373 ProfileContext* context = GetProfileContext(profile); | 448 ProfileContext* context = GetProfileContext(profile); |
374 // It is forbidden to call this function with a destroyed profile. | 449 // It is forbidden to call this function with a destroyed profile. |
375 DCHECK(context); | 450 DCHECK(context); |
451 // If this is a process-wide incident, the context must not indicate that the | |
452 // profile (which is NULL) has been added to the profile manager. | |
453 DCHECK(profile || !context->added); | |
376 | 454 |
377 // Drop the incident immediately if profile creation has completed and the | 455 // Drop the incident immediately if the profile has already been added to the |
378 // profile is not participating in safe browsing. Preference evaluation is | 456 // manager and is not participating in safe browsing. Preference evaluation is |
379 // deferred until OnProfileAdded() if profile creation has not yet | 457 // deferred until OnProfileAdded() otherwise. |
380 // completed. | |
381 if (context->added && | 458 if (context->added && |
382 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | 459 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { |
383 LogIncidentDataType(DROPPED, *incident_data); | 460 LogIncidentDataType(DROPPED, *incident_data); |
384 return; | 461 return; |
385 } | 462 } |
386 | 463 |
387 // Start assembling a new report if this is the first incident ever or the | |
388 // first since the last upload. | |
389 if (!report_) { | |
390 report_.reset(new ClientIncidentReport()); | |
391 first_incident_time_ = base::Time::Now(); | |
392 } | |
393 | |
394 // Provide time to the new incident if the caller didn't do so. | 464 // Provide time to the new incident if the caller didn't do so. |
395 if (!incident_data->has_incident_time_msec()) | 465 if (!incident_data->has_incident_time_msec()) |
396 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); | 466 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); |
397 | 467 |
398 // Take ownership of the incident. | 468 // Take ownership of the incident. |
399 context->incidents.push_back(incident_data.release()); | 469 context->incidents.push_back(incident_data.release()); |
400 | 470 |
471 // Remember when the first incident for this report arrived. | |
472 if (first_incident_time_.is_null()) | |
473 first_incident_time_ = base::Time::Now(); | |
474 // Log the time between the previous incident and this one. | |
401 if (!last_incident_time_.is_null()) { | 475 if (!last_incident_time_.is_null()) { |
402 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", | 476 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", |
403 base::TimeTicks::Now() - last_incident_time_); | 477 base::TimeTicks::Now() - last_incident_time_); |
404 } | 478 } |
405 last_incident_time_ = base::TimeTicks::Now(); | 479 last_incident_time_ = base::TimeTicks::Now(); |
406 | 480 |
407 // Persist the incident data. | 481 // Persist the incident data. |
408 | 482 |
409 // Restart the delay timer to send the report upon expiration. | 483 // Start assembling a new report if this is the first incident ever or the |
410 collection_timeout_pending_ = true; | 484 // first since the last upload. |
411 upload_timer_.Reset(); | 485 BeginReportProcessing(); |
486 } | |
412 | 487 |
488 void IncidentReportingService::BeginReportProcessing() { | |
489 DCHECK(thread_checker_.CalledOnValidThread()); | |
490 | |
491 // Createa a new report if needed. | |
mattm
2014/08/06 02:10:17
Createa
grt (UTC plus 2)
2014/08/06 02:37:31
Done.
| |
492 if (!report_) | |
493 report_.reset(new ClientIncidentReport()); | |
494 | |
495 // Ensure that collection tasks are running (calls are idempotent). | |
496 BeginIncidentCollation(); | |
413 BeginEnvironmentCollection(); | 497 BeginEnvironmentCollection(); |
414 BeginDownloadCollection(); | 498 BeginDownloadCollection(); |
415 } | 499 } |
416 | 500 |
501 void IncidentReportingService::BeginIncidentCollation() { | |
502 // Restart the delay timer to send the report upon expiration. | |
503 collation_timeout_pending_ = true; | |
504 collation_timer_.Reset(); | |
505 } | |
506 | |
417 void IncidentReportingService::BeginEnvironmentCollection() { | 507 void IncidentReportingService::BeginEnvironmentCollection() { |
418 DCHECK(thread_checker_.CalledOnValidThread()); | 508 DCHECK(thread_checker_.CalledOnValidThread()); |
419 DCHECK(report_); | 509 DCHECK(report_); |
420 // Nothing to do if environment collection is pending or has already | 510 // Nothing to do if environment collection is pending or has already |
421 // completed. | 511 // completed. |
422 if (environment_collection_pending_ || report_->has_environment()) | 512 if (environment_collection_pending_ || report_->has_environment()) |
423 return; | 513 return; |
424 | 514 |
425 environment_collection_begin_ = base::TimeTicks::Now(); | 515 environment_collection_begin_ = base::TimeTicks::Now(); |
426 ClientIncidentReport_EnvironmentData* environment_data = | 516 ClientIncidentReport_EnvironmentData* environment_data = |
(...skipping 28 matching lines...) Expand all Loading... | |
455 DCHECK(environment_collection_pending_); | 545 DCHECK(environment_collection_pending_); |
456 DCHECK(report_ && !report_->has_environment()); | 546 DCHECK(report_ && !report_->has_environment()); |
457 environment_collection_pending_ = false; | 547 environment_collection_pending_ = false; |
458 | 548 |
459 // CurrentProcessInfo::CreationTime() is missing on some platforms. | 549 // CurrentProcessInfo::CreationTime() is missing on some platforms. |
460 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) | 550 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) |
461 base::TimeDelta uptime = | 551 base::TimeDelta uptime = |
462 first_incident_time_ - base::CurrentProcessInfo::CreationTime(); | 552 first_incident_time_ - base::CurrentProcessInfo::CreationTime(); |
463 environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds()); | 553 environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds()); |
464 #endif | 554 #endif |
465 first_incident_time_ = base::Time(); | |
466 | 555 |
467 report_->set_allocated_environment(environment_data.release()); | 556 report_->set_allocated_environment(environment_data.release()); |
468 | 557 |
469 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", | 558 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", |
470 base::TimeTicks::Now() - environment_collection_begin_); | 559 base::TimeTicks::Now() - environment_collection_begin_); |
471 environment_collection_begin_ = base::TimeTicks(); | 560 environment_collection_begin_ = base::TimeTicks(); |
472 | 561 |
473 UploadIfCollectionComplete(); | 562 UploadIfCollectionComplete(); |
474 } | 563 } |
475 | 564 |
476 bool IncidentReportingService::WaitingToCollateIncidents() { | 565 bool IncidentReportingService::WaitingToCollateIncidents() { |
477 return collection_timeout_pending_; | 566 return collation_timeout_pending_; |
478 } | 567 } |
479 | 568 |
480 void IncidentReportingService::CancelIncidentCollection() { | 569 void IncidentReportingService::CancelIncidentCollection() { |
481 collection_timeout_pending_ = false; | 570 collation_timeout_pending_ = false; |
482 last_incident_time_ = base::TimeTicks(); | 571 last_incident_time_ = base::TimeTicks(); |
483 report_.reset(); | 572 report_.reset(); |
484 } | 573 } |
485 | 574 |
486 void IncidentReportingService::OnCollectionTimeout() { | 575 void IncidentReportingService::OnCollationTimeout() { |
487 DCHECK(thread_checker_.CalledOnValidThread()); | 576 DCHECK(thread_checker_.CalledOnValidThread()); |
488 | 577 |
489 // Exit early if collection was cancelled. | 578 // Exit early if collection was cancelled. |
490 if (!collection_timeout_pending_) | 579 if (!collation_timeout_pending_) |
491 return; | 580 return; |
492 | 581 |
493 // Wait another round if incidents have come in from a profile that has yet to | 582 // Wait another round if profile-bound incidents have come in from a profile |
494 // complete creation. | 583 // that has yet to complete creation. |
495 for (ProfileContextCollection::iterator scan = profiles_.begin(); | 584 for (ProfileContextCollection::iterator scan = profiles_.begin(); |
496 scan != profiles_.end(); | 585 scan != profiles_.end(); |
497 ++scan) { | 586 ++scan) { |
498 if (!scan->second->added && !scan->second->incidents.empty()) { | 587 if (scan->first && !scan->second->added && |
499 upload_timer_.Reset(); | 588 !scan->second->incidents.empty()) { |
589 collation_timer_.Reset(); | |
500 return; | 590 return; |
501 } | 591 } |
502 } | 592 } |
503 | 593 |
504 collection_timeout_pending_ = false; | 594 collation_timeout_pending_ = false; |
505 | 595 |
506 UploadIfCollectionComplete(); | 596 UploadIfCollectionComplete(); |
507 } | 597 } |
508 | 598 |
509 void IncidentReportingService::BeginDownloadCollection() { | 599 void IncidentReportingService::BeginDownloadCollection() { |
510 DCHECK(thread_checker_.CalledOnValidThread()); | 600 DCHECK(thread_checker_.CalledOnValidThread()); |
511 DCHECK(report_); | 601 DCHECK(report_); |
512 // Nothing to do if a search for the most recent download is already pending | 602 // Nothing to do if a search for the most recent download is already pending |
513 // or if one has already been found. | 603 // or if one has already been found. |
514 if (last_download_finder_ || report_->has_download()) | 604 if (last_download_finder_ || report_->has_download()) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
574 // Bail out if there are still outstanding collection tasks. Completion of any | 664 // Bail out if there are still outstanding collection tasks. Completion of any |
575 // of these will start another upload attempt. | 665 // of these will start another upload attempt. |
576 if (WaitingForEnvironmentCollection() || | 666 if (WaitingForEnvironmentCollection() || |
577 WaitingToCollateIncidents() || | 667 WaitingToCollateIncidents() || |
578 WaitingForMostRecentDownload()) { | 668 WaitingForMostRecentDownload()) { |
579 return; | 669 return; |
580 } | 670 } |
581 | 671 |
582 // Take ownership of the report and clear things for future reports. | 672 // Take ownership of the report and clear things for future reports. |
583 scoped_ptr<ClientIncidentReport> report(report_.Pass()); | 673 scoped_ptr<ClientIncidentReport> report(report_.Pass()); |
674 first_incident_time_ = base::Time(); | |
584 last_incident_time_ = base::TimeTicks(); | 675 last_incident_time_ = base::TimeTicks(); |
585 | 676 |
586 // Drop the report if no executable download was found. | 677 // Drop the report if no executable download was found. |
587 if (!report->has_download()) { | 678 if (!report->has_download()) { |
588 UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", | 679 UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", |
589 IncidentReportUploader::UPLOAD_NO_DOWNLOAD, | 680 IncidentReportUploader::UPLOAD_NO_DOWNLOAD, |
590 IncidentReportUploader::NUM_UPLOAD_RESULTS); | 681 IncidentReportUploader::NUM_UPLOAD_RESULTS); |
591 return; | 682 return; |
592 } | 683 } |
593 | 684 |
594 ClientIncidentReport_EnvironmentData_Process* process = | 685 ClientIncidentReport_EnvironmentData_Process* process = |
595 report->mutable_environment()->mutable_process(); | 686 report->mutable_environment()->mutable_process(); |
596 | 687 |
597 // Not all platforms have a metrics reporting preference. | 688 // Not all platforms have a metrics reporting preference. |
598 if (g_browser_process->local_state()->FindPreference( | 689 if (g_browser_process->local_state()->FindPreference( |
599 prefs::kMetricsReportingEnabled)) { | 690 prefs::kMetricsReportingEnabled)) { |
600 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( | 691 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( |
601 prefs::kMetricsReportingEnabled)); | 692 prefs::kMetricsReportingEnabled)); |
602 } | 693 } |
603 | 694 |
604 // Check for extended consent in any profile while collecting incidents. | 695 // Find a profile suitable for tracking process-wide incidents. |
605 process->set_extended_consent(false); | 696 Profile* analyses_profile = FindEligibleProfile(); |
mattm
2014/08/06 02:10:17
is "analyses" intentional here? (vs analysis)
grt (UTC plus 2)
2014/08/06 02:37:31
Yeah, it's the profile used for the plural analyse
| |
697 process->set_extended_consent( | |
698 analyses_profile ? analyses_profile->GetPrefs()->GetBoolean( | |
699 prefs::kSafeBrowsingExtendedReportingEnabled) : | |
700 false); | |
701 | |
702 // Associate process-wide incidents with the analyses profile. | |
703 ProfileContext* null_context = GetProfileContext(NULL); | |
704 if (null_context && analyses_profile) { | |
705 DCHECK(!null_context->incidents.empty()); | |
706 ProfileContext* analyses_context = GetProfileContext(analyses_profile); | |
707 // Move the incidents to the target context. | |
708 analyses_context->incidents.insert(analyses_context->incidents.end(), | |
709 null_context->incidents.begin(), | |
710 null_context->incidents.end()); | |
711 null_context->incidents.weak_clear(); | |
712 // Delete the process-wide context. | |
713 delete null_context; | |
714 profiles_.erase(NULL); | |
mattm
2014/08/06 02:10:17
Does this mean no more process-wide incidents can
grt (UTC plus 2)
2014/08/06 02:37:31
Nice catch. Any added after this should go into a
| |
715 } | |
716 | |
606 // Collect incidents across all profiles participating in safe browsing. Drop | 717 // Collect incidents across all profiles participating in safe browsing. Drop |
607 // incidents if the profile stopped participating before collection completed. | 718 // incidents if the profile stopped participating before collection completed. |
608 // Prune previously submitted incidents. | 719 // Prune previously submitted incidents. |
609 // Associate the profiles and their incident data with the upload. | 720 // Associate the profiles and their incident data with the upload. |
610 size_t prune_count = 0; | 721 size_t prune_count = 0; |
611 UploadContext::PersistentIncidentStateCollection profiles_to_state; | 722 UploadContext::PersistentIncidentStateCollection profiles_to_state; |
612 for (ProfileContextCollection::iterator scan = profiles_.begin(); | 723 for (ProfileContextCollection::iterator scan = profiles_.begin(); |
613 scan != profiles_.end(); | 724 scan != profiles_.end(); |
614 ++scan) { | 725 ++scan) { |
726 // Bypass process-wide incidents that have not yet been associated with a | |
727 // profile. | |
728 if (!scan->first) | |
729 continue; | |
615 PrefService* prefs = scan->first->GetPrefs(); | 730 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; | 731 ProfileContext* context = scan->second; |
622 if (context->incidents.empty()) | 732 if (context->incidents.empty()) |
623 continue; | 733 continue; |
624 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { | 734 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { |
625 for (size_t i = 0; i < context->incidents.size(); ++i) { | 735 for (size_t i = 0; i < context->incidents.size(); ++i) { |
626 LogIncidentDataType(DROPPED, *context->incidents[i]); | 736 LogIncidentDataType(DROPPED, *context->incidents[i]); |
627 } | 737 } |
628 context->incidents.clear(); | 738 context->incidents.clear(); |
629 continue; | 739 continue; |
630 } | 740 } |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
793 if (!profile->IsOffTheRecord()) | 903 if (!profile->IsOffTheRecord()) |
794 OnProfileDestroyed(profile); | 904 OnProfileDestroyed(profile); |
795 break; | 905 break; |
796 } | 906 } |
797 default: | 907 default: |
798 break; | 908 break; |
799 } | 909 } |
800 } | 910 } |
801 | 911 |
802 } // namespace safe_browsing | 912 } // namespace safe_browsing |
OLD | NEW |