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

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: new test plus other review comments 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/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
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 kDefaultCallbackIntervalMs = 1000 * 20;
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
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
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(kDefaultCallbackIntervalMs),
248 content::BrowserThread::GetBlockingPool()
249 ->GetTaskRunnerWithShutdownBehavior(
250 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
228 receiver_weak_ptr_factory_(this), 251 receiver_weak_ptr_factory_(this),
229 weak_ptr_factory_(this) { 252 weak_ptr_factory_(this) {
230 notification_registrar_.Add(this, 253 notification_registrar_.Add(this,
231 chrome::NOTIFICATION_PROFILE_ADDED, 254 chrome::NOTIFICATION_PROFILE_ADDED,
232 content::NotificationService::AllSources()); 255 content::NotificationService::AllSources());
233 notification_registrar_.Add(this, 256 notification_registrar_.Add(this,
234 chrome::NOTIFICATION_PROFILE_DESTROYED, 257 chrome::NOTIFICATION_PROFILE_DESTROYED,
235 content::NotificationService::AllSources()); 258 content::NotificationService::AllSources());
236 } 259 }
237 260
(...skipping 25 matching lines...) Expand all
263 scoped_ptr<TrackedPreferenceValidationDelegate> 286 scoped_ptr<TrackedPreferenceValidationDelegate>
264 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { 287 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) {
265 DCHECK(thread_checker_.CalledOnValidThread()); 288 DCHECK(thread_checker_.CalledOnValidThread());
266 289
267 if (profile->IsOffTheRecord()) 290 if (profile->IsOffTheRecord())
268 return scoped_ptr<TrackedPreferenceValidationDelegate>(); 291 return scoped_ptr<TrackedPreferenceValidationDelegate>();
269 return scoped_ptr<TrackedPreferenceValidationDelegate>( 292 return scoped_ptr<TrackedPreferenceValidationDelegate>(
270 new PreferenceValidationDelegate(GetAddIncidentCallback(profile))); 293 new PreferenceValidationDelegate(GetAddIncidentCallback(profile)));
271 } 294 }
272 295
296 void IncidentReportingService::RegisterDelayedAnalysisCallback(
297 const DelayedAnalysisCallback& callback) {
298 DCHECK(thread_checker_.CalledOnValidThread());
299
300 // |callback| will be run on the blocking pool, so it will likely run the
301 // AddIncidentCallback there as well. Bounce the run of that callback back to
302 // the current thread via AddIncidentOnOriginThread.
303 delayed_analysis_callbacks_.RegisterCallback(
304 base::Bind(callback,
305 base::Bind(&AddIncidentOnOriginThread,
306 GetAddIncidentCallback(NULL),
307 base::ThreadTaskRunnerHandle::Get())));
308
309 // Start running the callbacks if any profiles are participating in safe
310 // browsing. If none are now, running will commence if/when a participaing
311 // profile is added.
312 if (FindEligibleProfile())
313 delayed_analysis_callbacks_.Start();
314 }
315
316 IncidentReportingService::IncidentReportingService(
317 SafeBrowsingService* safe_browsing_service,
318 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
319 base::TimeDelta delayed_task_interval,
320 const scoped_refptr<base::TaskRunner>& delayed_task_runner)
321 : database_manager_(safe_browsing_service ?
322 safe_browsing_service->database_manager() : NULL),
323 url_request_context_getter_(request_context_getter),
324 collect_environment_data_fn_(&CollectEnvironmentData),
325 environment_collection_task_runner_(
326 content::BrowserThread::GetBlockingPool()
327 ->GetTaskRunnerWithShutdownBehavior(
328 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
329 environment_collection_pending_(),
330 collation_timeout_pending_(),
331 collation_timer_(FROM_HERE,
332 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs),
333 this,
334 &IncidentReportingService::OnCollationTimeout),
335 delayed_analysis_callbacks_(delayed_task_interval, delayed_task_runner),
336 receiver_weak_ptr_factory_(this),
337 weak_ptr_factory_(this) {
338 notification_registrar_.Add(this,
339 chrome::NOTIFICATION_PROFILE_ADDED,
340 content::NotificationService::AllSources());
341 notification_registrar_.Add(this,
342 chrome::NOTIFICATION_PROFILE_DESTROYED,
343 content::NotificationService::AllSources());
344 }
345
273 void IncidentReportingService::SetCollectEnvironmentHook( 346 void IncidentReportingService::SetCollectEnvironmentHook(
274 CollectEnvironmentDataFn collect_environment_data_hook, 347 CollectEnvironmentDataFn collect_environment_data_hook,
275 const scoped_refptr<base::TaskRunner>& task_runner) { 348 const scoped_refptr<base::TaskRunner>& task_runner) {
276 if (collect_environment_data_hook) { 349 if (collect_environment_data_hook) {
277 collect_environment_data_fn_ = collect_environment_data_hook; 350 collect_environment_data_fn_ = collect_environment_data_hook;
278 environment_collection_task_runner_ = task_runner; 351 environment_collection_task_runner_ = task_runner;
279 } else { 352 } else {
280 collect_environment_data_fn_ = &CollectEnvironmentData; 353 collect_environment_data_fn_ = &CollectEnvironmentData;
281 environment_collection_task_runner_ = 354 environment_collection_task_runner_ =
282 content::BrowserThread::GetBlockingPool() 355 content::BrowserThread::GetBlockingPool()
283 ->GetTaskRunnerWithShutdownBehavior( 356 ->GetTaskRunnerWithShutdownBehavior(
284 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); 357 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
285 } 358 }
286 } 359 }
287 360
288 void IncidentReportingService::OnProfileAdded(Profile* profile) { 361 void IncidentReportingService::OnProfileAdded(Profile* profile) {
289 DCHECK(thread_checker_.CalledOnValidThread()); 362 DCHECK(thread_checker_.CalledOnValidThread());
290 363
291 // Track the addition of all profiles even when no report is being assembled 364 // 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 365 // so that the service can determine whether or not it can evaluate a
293 // profile's preferences at the time of incident addition. 366 // profile's preferences at the time of incident addition.
294 ProfileContext* context = GetOrCreateProfileContext(profile); 367 ProfileContext* context = GetOrCreateProfileContext(profile);
295 context->added = true; 368 context->added = true;
296 369
370 const bool safe_browsing_enabled =
371 profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled);
372
373 // Start processing delayed analysis callbacks if this new profile
374 // participates in safe browsing. Start is idempotent, so this is safe even if
375 // they're already running.
376 if (safe_browsing_enabled)
377 delayed_analysis_callbacks_.Start();
378
379 // Start a new report if this profile participates in safe browsing and there
380 // are process-wide incidents.
381 if (safe_browsing_enabled && GetProfileContext(NULL))
382 BeginReportProcessing();
383
384 // TODO(grt): register for pref change notifications to start delayed analysis
385 // and/or report processing if sb is currently disabled but subsequently
386 // enabled.
387
297 // Nothing else to do if a report is not being assembled. 388 // Nothing else to do if a report is not being assembled.
298 if (!report_) 389 if (!report_)
299 return; 390 return;
300 391
301 // Drop all incidents received prior to creation if the profile is not 392 // Drop all incidents associated with this profile that were received prior to
302 // participating in safe browsing. 393 // its addition if the profile is not participating in safe browsing.
303 if (!context->incidents.empty() && 394 if (!context->incidents.empty() && !safe_browsing_enabled) {
304 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { 395 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]); 396 LogIncidentDataType(DROPPED, *context->incidents[i]);
307 }
308 context->incidents.clear(); 397 context->incidents.clear();
309 } 398 }
310 399
311 // Take another stab at finding the most recent download if a report is being 400 // 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 401 // assembled and one hasn't been found yet (the LastDownloadFinder operates
313 // only on profiles that have been added to the ProfileManager). 402 // only on profiles that have been added to the ProfileManager).
314 BeginDownloadCollection(); 403 BeginDownloadCollection();
315 } 404 }
316 405
317 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( 406 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. 444 // Forget about this profile. Incidents not yet sent for upload are lost.
356 // No new incidents will be accepted for it. 445 // No new incidents will be accepted for it.
357 delete it->second; 446 delete it->second;
358 profiles_.erase(it); 447 profiles_.erase(it);
359 448
360 // Remove the association with this profile from all pending uploads. 449 // Remove the association with this profile from all pending uploads.
361 for (size_t i = 0; i < uploads_.size(); ++i) 450 for (size_t i = 0; i < uploads_.size(); ++i)
362 uploads_[i]->profiles_to_state.erase(profile); 451 uploads_[i]->profiles_to_state.erase(profile);
363 } 452 }
364 453
454 Profile* IncidentReportingService::FindEligibleProfile() const {
455 Profile* candidate = NULL;
456 for (ProfileContextCollection::const_iterator scan = profiles_.begin();
457 scan != profiles_.end();
458 ++scan) {
459 // Skip over profiles that have yet to be added to the profile manager.
460 // This will also skip over the NULL-profile context used to hold
461 // process-wide incidents.
462 if (!scan->second->added)
463 continue;
464 PrefService* prefs = scan->first->GetPrefs();
465 if (prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
466 if (!candidate)
467 candidate = scan->first;
468 if (prefs->GetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled)) {
469 candidate = scan->first;
470 break;
471 }
472 }
473 }
474 return candidate;
475 }
476
365 void IncidentReportingService::AddIncident( 477 void IncidentReportingService::AddIncident(
366 Profile* profile, 478 Profile* profile,
367 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { 479 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) {
368 DCHECK(thread_checker_.CalledOnValidThread()); 480 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)); 481 DCHECK_EQ(1U, CountIncidents(*incident_data));
372 482
373 ProfileContext* context = GetProfileContext(profile); 483 ProfileContext* context = GetProfileContext(profile);
374 // It is forbidden to call this function with a destroyed profile. 484 // It is forbidden to call this function with a destroyed profile.
375 DCHECK(context); 485 DCHECK(context);
486 // If this is a process-wide incident, the context must not indicate that the
487 // profile (which is NULL) has been added to the profile manager.
488 DCHECK(profile || !context->added);
376 489
377 // Drop the incident immediately if profile creation has completed and the 490 // Drop the incident immediately if the profile has already been added to the
378 // profile is not participating in safe browsing. Preference evaluation is 491 // manager and is not participating in safe browsing. Preference evaluation is
379 // deferred until OnProfileAdded() if profile creation has not yet 492 // deferred until OnProfileAdded() otherwise.
380 // completed.
381 if (context->added && 493 if (context->added &&
382 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { 494 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
383 LogIncidentDataType(DROPPED, *incident_data); 495 LogIncidentDataType(DROPPED, *incident_data);
384 return; 496 return;
385 } 497 }
386 498
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. 499 // Provide time to the new incident if the caller didn't do so.
395 if (!incident_data->has_incident_time_msec()) 500 if (!incident_data->has_incident_time_msec())
396 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); 501 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime());
397 502
398 // Take ownership of the incident. 503 // Take ownership of the incident.
399 context->incidents.push_back(incident_data.release()); 504 context->incidents.push_back(incident_data.release());
400 505
506 // Remember when the first incident for this report arrived.
507 if (first_incident_time_.is_null())
508 first_incident_time_ = base::Time::Now();
509 // Log the time between the previous incident and this one.
401 if (!last_incident_time_.is_null()) { 510 if (!last_incident_time_.is_null()) {
402 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", 511 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime",
403 base::TimeTicks::Now() - last_incident_time_); 512 base::TimeTicks::Now() - last_incident_time_);
404 } 513 }
405 last_incident_time_ = base::TimeTicks::Now(); 514 last_incident_time_ = base::TimeTicks::Now();
406 515
407 // Persist the incident data. 516 // Persist the incident data.
408 517
409 // Restart the delay timer to send the report upon expiration. 518 // Start assembling a new report if this is the first incident ever or the
410 collection_timeout_pending_ = true; 519 // first since the last upload.
411 upload_timer_.Reset(); 520 BeginReportProcessing();
521 }
412 522
523 void IncidentReportingService::BeginReportProcessing() {
524 DCHECK(thread_checker_.CalledOnValidThread());
525
526 // Creates a new report if needed.
527 if (!report_)
528 report_.reset(new ClientIncidentReport());
529
530 // Ensure that collection tasks are running (calls are idempotent).
531 BeginIncidentCollation();
413 BeginEnvironmentCollection(); 532 BeginEnvironmentCollection();
414 BeginDownloadCollection(); 533 BeginDownloadCollection();
415 } 534 }
416 535
536 void IncidentReportingService::BeginIncidentCollation() {
537 // Restart the delay timer to send the report upon expiration.
538 collation_timeout_pending_ = true;
539 collation_timer_.Reset();
540 }
541
417 void IncidentReportingService::BeginEnvironmentCollection() { 542 void IncidentReportingService::BeginEnvironmentCollection() {
418 DCHECK(thread_checker_.CalledOnValidThread()); 543 DCHECK(thread_checker_.CalledOnValidThread());
419 DCHECK(report_); 544 DCHECK(report_);
420 // Nothing to do if environment collection is pending or has already 545 // Nothing to do if environment collection is pending or has already
421 // completed. 546 // completed.
422 if (environment_collection_pending_ || report_->has_environment()) 547 if (environment_collection_pending_ || report_->has_environment())
423 return; 548 return;
424 549
425 environment_collection_begin_ = base::TimeTicks::Now(); 550 environment_collection_begin_ = base::TimeTicks::Now();
426 ClientIncidentReport_EnvironmentData* environment_data = 551 ClientIncidentReport_EnvironmentData* environment_data =
(...skipping 28 matching lines...) Expand all
455 DCHECK(environment_collection_pending_); 580 DCHECK(environment_collection_pending_);
456 DCHECK(report_ && !report_->has_environment()); 581 DCHECK(report_ && !report_->has_environment());
457 environment_collection_pending_ = false; 582 environment_collection_pending_ = false;
458 583
459 // CurrentProcessInfo::CreationTime() is missing on some platforms. 584 // CurrentProcessInfo::CreationTime() is missing on some platforms.
460 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) 585 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
461 base::TimeDelta uptime = 586 base::TimeDelta uptime =
462 first_incident_time_ - base::CurrentProcessInfo::CreationTime(); 587 first_incident_time_ - base::CurrentProcessInfo::CreationTime();
463 environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds()); 588 environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds());
464 #endif 589 #endif
465 first_incident_time_ = base::Time();
466 590
467 report_->set_allocated_environment(environment_data.release()); 591 report_->set_allocated_environment(environment_data.release());
468 592
469 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", 593 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime",
470 base::TimeTicks::Now() - environment_collection_begin_); 594 base::TimeTicks::Now() - environment_collection_begin_);
471 environment_collection_begin_ = base::TimeTicks(); 595 environment_collection_begin_ = base::TimeTicks();
472 596
473 UploadIfCollectionComplete(); 597 UploadIfCollectionComplete();
474 } 598 }
475 599
476 bool IncidentReportingService::WaitingToCollateIncidents() { 600 bool IncidentReportingService::WaitingToCollateIncidents() {
477 return collection_timeout_pending_; 601 return collation_timeout_pending_;
478 } 602 }
479 603
480 void IncidentReportingService::CancelIncidentCollection() { 604 void IncidentReportingService::CancelIncidentCollection() {
481 collection_timeout_pending_ = false; 605 collation_timeout_pending_ = false;
482 last_incident_time_ = base::TimeTicks(); 606 last_incident_time_ = base::TimeTicks();
483 report_.reset(); 607 report_.reset();
484 } 608 }
485 609
486 void IncidentReportingService::OnCollectionTimeout() { 610 void IncidentReportingService::OnCollationTimeout() {
487 DCHECK(thread_checker_.CalledOnValidThread()); 611 DCHECK(thread_checker_.CalledOnValidThread());
488 612
489 // Exit early if collection was cancelled. 613 // Exit early if collection was cancelled.
490 if (!collection_timeout_pending_) 614 if (!collation_timeout_pending_)
491 return; 615 return;
492 616
493 // Wait another round if incidents have come in from a profile that has yet to 617 // Wait another round if profile-bound incidents have come in from a profile
494 // complete creation. 618 // that has yet to complete creation.
495 for (ProfileContextCollection::iterator scan = profiles_.begin(); 619 for (ProfileContextCollection::iterator scan = profiles_.begin();
496 scan != profiles_.end(); 620 scan != profiles_.end();
497 ++scan) { 621 ++scan) {
498 if (!scan->second->added && !scan->second->incidents.empty()) { 622 if (scan->first && !scan->second->added &&
499 upload_timer_.Reset(); 623 !scan->second->incidents.empty()) {
624 collation_timer_.Reset();
500 return; 625 return;
501 } 626 }
502 } 627 }
503 628
504 collection_timeout_pending_ = false; 629 collation_timeout_pending_ = false;
505 630
506 UploadIfCollectionComplete(); 631 UploadIfCollectionComplete();
507 } 632 }
508 633
509 void IncidentReportingService::BeginDownloadCollection() { 634 void IncidentReportingService::BeginDownloadCollection() {
510 DCHECK(thread_checker_.CalledOnValidThread()); 635 DCHECK(thread_checker_.CalledOnValidThread());
511 DCHECK(report_); 636 DCHECK(report_);
512 // Nothing to do if a search for the most recent download is already pending 637 // Nothing to do if a search for the most recent download is already pending
513 // or if one has already been found. 638 // or if one has already been found.
514 if (last_download_finder_ || report_->has_download()) 639 if (last_download_finder_ || report_->has_download())
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 // Bail out if there are still outstanding collection tasks. Completion of any 699 // Bail out if there are still outstanding collection tasks. Completion of any
575 // of these will start another upload attempt. 700 // of these will start another upload attempt.
576 if (WaitingForEnvironmentCollection() || 701 if (WaitingForEnvironmentCollection() ||
577 WaitingToCollateIncidents() || 702 WaitingToCollateIncidents() ||
578 WaitingForMostRecentDownload()) { 703 WaitingForMostRecentDownload()) {
579 return; 704 return;
580 } 705 }
581 706
582 // Take ownership of the report and clear things for future reports. 707 // Take ownership of the report and clear things for future reports.
583 scoped_ptr<ClientIncidentReport> report(report_.Pass()); 708 scoped_ptr<ClientIncidentReport> report(report_.Pass());
709 first_incident_time_ = base::Time();
584 last_incident_time_ = base::TimeTicks(); 710 last_incident_time_ = base::TimeTicks();
585 711
586 // Drop the report if no executable download was found. 712 // Drop the report if no executable download was found.
587 if (!report->has_download()) { 713 if (!report->has_download()) {
588 UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", 714 UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult",
589 IncidentReportUploader::UPLOAD_NO_DOWNLOAD, 715 IncidentReportUploader::UPLOAD_NO_DOWNLOAD,
590 IncidentReportUploader::NUM_UPLOAD_RESULTS); 716 IncidentReportUploader::NUM_UPLOAD_RESULTS);
591 return; 717 return;
592 } 718 }
593 719
594 ClientIncidentReport_EnvironmentData_Process* process = 720 ClientIncidentReport_EnvironmentData_Process* process =
595 report->mutable_environment()->mutable_process(); 721 report->mutable_environment()->mutable_process();
596 722
597 // Not all platforms have a metrics reporting preference. 723 // Not all platforms have a metrics reporting preference.
598 if (g_browser_process->local_state()->FindPreference( 724 if (g_browser_process->local_state()->FindPreference(
599 prefs::kMetricsReportingEnabled)) { 725 prefs::kMetricsReportingEnabled)) {
600 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( 726 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean(
601 prefs::kMetricsReportingEnabled)); 727 prefs::kMetricsReportingEnabled));
602 } 728 }
603 729
604 // Check for extended consent in any profile while collecting incidents. 730 // Find the profile that benefits from the strongest protections.
605 process->set_extended_consent(false); 731 Profile* eligible_profile = FindEligibleProfile();
732 process->set_extended_consent(
733 eligible_profile ? eligible_profile->GetPrefs()->GetBoolean(
734 prefs::kSafeBrowsingExtendedReportingEnabled) :
735 false);
736
737 // Associate process-wide incidents with the profile that benefits from the
738 // strongest safe browsing protections.
739 ProfileContext* null_context = GetProfileContext(NULL);
740 if (null_context && !null_context->incidents.empty() && eligible_profile) {
741 ProfileContext* eligible_context = GetProfileContext(eligible_profile);
742 // Move the incidents to the target context.
743 eligible_context->incidents.insert(eligible_context->incidents.end(),
744 null_context->incidents.begin(),
745 null_context->incidents.end());
746 null_context->incidents.weak_clear();
747 }
748
606 // Collect incidents across all profiles participating in safe browsing. Drop 749 // Collect incidents across all profiles participating in safe browsing. Drop
607 // incidents if the profile stopped participating before collection completed. 750 // incidents if the profile stopped participating before collection completed.
608 // Prune previously submitted incidents. 751 // Prune previously submitted incidents.
609 // Associate the profiles and their incident data with the upload. 752 // Associate the profiles and their incident data with the upload.
610 size_t prune_count = 0; 753 size_t prune_count = 0;
611 UploadContext::PersistentIncidentStateCollection profiles_to_state; 754 UploadContext::PersistentIncidentStateCollection profiles_to_state;
612 for (ProfileContextCollection::iterator scan = profiles_.begin(); 755 for (ProfileContextCollection::iterator scan = profiles_.begin();
613 scan != profiles_.end(); 756 scan != profiles_.end();
614 ++scan) { 757 ++scan) {
758 // Bypass process-wide incidents that have not yet been associated with a
759 // profile.
760 if (!scan->first)
761 continue;
615 PrefService* prefs = scan->first->GetPrefs(); 762 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; 763 ProfileContext* context = scan->second;
622 if (context->incidents.empty()) 764 if (context->incidents.empty())
623 continue; 765 continue;
624 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) { 766 if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled)) {
625 for (size_t i = 0; i < context->incidents.size(); ++i) { 767 for (size_t i = 0; i < context->incidents.size(); ++i) {
626 LogIncidentDataType(DROPPED, *context->incidents[i]); 768 LogIncidentDataType(DROPPED, *context->incidents[i]);
627 } 769 }
628 context->incidents.clear(); 770 context->incidents.clear();
629 continue; 771 continue;
630 } 772 }
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 if (!profile->IsOffTheRecord()) 935 if (!profile->IsOffTheRecord())
794 OnProfileDestroyed(profile); 936 OnProfileDestroyed(profile);
795 break; 937 break;
796 } 938 }
797 default: 939 default:
798 break; 940 break;
799 } 941 }
800 } 942 }
801 943
802 } // namespace safe_browsing 944 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698