Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/safe_browsing/incident_reporting_service.h" | 5 #include "chrome/browser/safe_browsing/incident_reporting_service.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); | 59 UMA_HISTOGRAM_ENUMERATION("SBIRS.Incident", type, NUM_INCIDENT_TYPES); |
| 60 } else { | 60 } else { |
| 61 DCHECK_EQ(disposition, DROPPED); | 61 DCHECK_EQ(disposition, DROPPED); |
| 62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, | 62 UMA_HISTOGRAM_ENUMERATION("SBIRS.DroppedIncident", type, |
| 63 NUM_INCIDENT_TYPES); | 63 NUM_INCIDENT_TYPES); |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 | 66 |
| 67 } // namespace | 67 } // namespace |
| 68 | 68 |
| 69 struct IncidentReportingService::ProfileContext { | 69 struct IncidentReportingService::ProfileContext { |
|
mattm
2014/06/27 21:50:32
Since the IncidentReportingService already tracks
grt (UTC plus 2)
2014/06/30 16:53:38
I'll explore this to see if it simplifies things.
grt (UTC plus 2)
2014/06/30 19:38:37
I see pros and cons. I'm inclined to keep things a
| |
| 70 ProfileContext(); | 70 ProfileContext(); |
| 71 ~ProfileContext(); | 71 ~ProfileContext(); |
| 72 | 72 |
| 73 // The incidents collected for this profile pending creation and/or upload. | 73 // The incidents collected for this profile pending creation and/or upload. |
| 74 ScopedVector<ClientIncidentReport_IncidentData> incidents; | 74 ScopedVector<ClientIncidentReport_IncidentData> incidents; |
| 75 | 75 |
| 76 // False until PROFILE_CREATED notification is received. | 76 // False until PROFILE_ADDED notification is received. |
| 77 bool created; | 77 bool added; |
| 78 | 78 |
| 79 private: | 79 private: |
| 80 DISALLOW_COPY_AND_ASSIGN(ProfileContext); | 80 DISALLOW_COPY_AND_ASSIGN(ProfileContext); |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 class IncidentReportingService::UploadContext { | 83 class IncidentReportingService::UploadContext { |
| 84 public: | 84 public: |
| 85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); | 85 explicit UploadContext(scoped_ptr<ClientIncidentReport> report); |
| 86 ~UploadContext(); | 86 ~UploadContext(); |
| 87 | 87 |
| 88 // The report being uploaded. | 88 // The report being uploaded. |
| 89 scoped_ptr<ClientIncidentReport> report; | 89 scoped_ptr<ClientIncidentReport> report; |
| 90 | 90 |
| 91 // The uploader in use. This is NULL until the CSD killswitch is checked. | 91 // The uploader in use. This is NULL until the CSD killswitch is checked. |
| 92 scoped_ptr<IncidentReportUploader> uploader; | 92 scoped_ptr<IncidentReportUploader> uploader; |
| 93 | 93 |
| 94 // The set of profiles from which incidents in |report| originated. | 94 // The set of profiles from which incidents in |report| originated. |
| 95 std::vector<Profile*> profiles; | 95 std::vector<Profile*> profiles; |
| 96 | 96 |
| 97 private: | 97 private: |
| 98 DISALLOW_COPY_AND_ASSIGN(UploadContext); | 98 DISALLOW_COPY_AND_ASSIGN(UploadContext); |
| 99 }; | 99 }; |
| 100 | 100 |
| 101 IncidentReportingService::ProfileContext::ProfileContext() : created() { | 101 IncidentReportingService::ProfileContext::ProfileContext() : added() { |
| 102 } | 102 } |
| 103 | 103 |
| 104 IncidentReportingService::ProfileContext::~ProfileContext() { | 104 IncidentReportingService::ProfileContext::~ProfileContext() { |
| 105 } | 105 } |
| 106 | 106 |
| 107 IncidentReportingService::UploadContext::UploadContext( | 107 IncidentReportingService::UploadContext::UploadContext( |
| 108 scoped_ptr<ClientIncidentReport> report) | 108 scoped_ptr<ClientIncidentReport> report) |
| 109 : report(report.Pass()) { | 109 : report(report.Pass()) { |
| 110 } | 110 } |
| 111 | 111 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 125 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), | 125 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), |
| 126 environment_collection_pending_(), | 126 environment_collection_pending_(), |
| 127 collection_timeout_pending_(), | 127 collection_timeout_pending_(), |
| 128 upload_timer_(FROM_HERE, | 128 upload_timer_(FROM_HERE, |
| 129 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), | 129 base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs), |
| 130 this, | 130 this, |
| 131 &IncidentReportingService::OnCollectionTimeout), | 131 &IncidentReportingService::OnCollectionTimeout), |
| 132 receiver_weak_ptr_factory_(this), | 132 receiver_weak_ptr_factory_(this), |
| 133 weak_ptr_factory_(this) { | 133 weak_ptr_factory_(this) { |
| 134 notification_registrar_.Add(this, | 134 notification_registrar_.Add(this, |
| 135 chrome::NOTIFICATION_PROFILE_CREATED, | 135 chrome::NOTIFICATION_PROFILE_ADDED, |
| 136 content::NotificationService::AllSources()); | 136 content::NotificationService::AllSources()); |
| 137 notification_registrar_.Add(this, | 137 notification_registrar_.Add(this, |
| 138 chrome::NOTIFICATION_PROFILE_DESTROYED, | 138 chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 139 content::NotificationService::AllSources()); | 139 content::NotificationService::AllSources()); |
| 140 } | 140 } |
| 141 | 141 |
| 142 IncidentReportingService::~IncidentReportingService() { | 142 IncidentReportingService::~IncidentReportingService() { |
| 143 CancelIncidentCollection(); | 143 CancelIncidentCollection(); |
| 144 | 144 |
| 145 // Cancel all internal asynchronous tasks. | 145 // Cancel all internal asynchronous tasks. |
| 146 weak_ptr_factory_.InvalidateWeakPtrs(); | 146 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 147 | 147 |
| 148 CancelEnvironmentCollection(); | 148 CancelEnvironmentCollection(); |
| 149 CancelDownloadCollection(); | |
| 149 CancelAllReportUploads(); | 150 CancelAllReportUploads(); |
| 150 | 151 |
| 151 STLDeleteValues(&profiles_); | 152 STLDeleteValues(&profiles_); |
| 152 } | 153 } |
| 153 | 154 |
| 154 AddIncidentCallback IncidentReportingService::GetAddIncidentCallback( | 155 AddIncidentCallback IncidentReportingService::GetAddIncidentCallback( |
| 155 Profile* profile) { | 156 Profile* profile) { |
| 156 // Force the context to be created so that incidents added before | 157 // Force the context to be created so that incidents added before |
| 157 // OnProfileCreated is called are held until the profile's preferences can be | 158 // OnProfileAdded is called are held until the profile's preferences can be |
| 158 // queried. | 159 // queried. |
| 159 ignore_result(GetOrCreateProfileContext(profile)); | 160 ignore_result(GetOrCreateProfileContext(profile)); |
| 160 | 161 |
| 161 return base::Bind(&IncidentReportingService::AddIncident, | 162 return base::Bind(&IncidentReportingService::AddIncident, |
| 162 receiver_weak_ptr_factory_.GetWeakPtr(), | 163 receiver_weak_ptr_factory_.GetWeakPtr(), |
| 163 profile); | 164 profile); |
| 164 } | 165 } |
| 165 | 166 |
| 166 scoped_ptr<TrackedPreferenceValidationDelegate> | 167 scoped_ptr<TrackedPreferenceValidationDelegate> |
| 167 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { | 168 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 181 environment_collection_task_runner_ = task_runner; | 182 environment_collection_task_runner_ = task_runner; |
| 182 } else { | 183 } else { |
| 183 collect_environment_data_fn_ = &CollectEnvironmentData; | 184 collect_environment_data_fn_ = &CollectEnvironmentData; |
| 184 environment_collection_task_runner_ = | 185 environment_collection_task_runner_ = |
| 185 content::BrowserThread::GetBlockingPool() | 186 content::BrowserThread::GetBlockingPool() |
| 186 ->GetTaskRunnerWithShutdownBehavior( | 187 ->GetTaskRunnerWithShutdownBehavior( |
| 187 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 188 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 188 } | 189 } |
| 189 } | 190 } |
| 190 | 191 |
| 191 void IncidentReportingService::OnProfileCreated(Profile* profile) { | 192 void IncidentReportingService::OnProfileAdded(Profile* profile) { |
| 192 DCHECK(thread_checker_.CalledOnValidThread()); | 193 DCHECK(thread_checker_.CalledOnValidThread()); |
| 193 | 194 |
| 195 // Track the addition of all profiles even when no report is being assembled | |
| 196 // so that the service can determine whether or not it can evaluate a | |
| 197 // profile's preferences at the time of incident addition. | |
| 194 ProfileContext* context = GetOrCreateProfileContext(profile); | 198 ProfileContext* context = GetOrCreateProfileContext(profile); |
| 195 context->created = true; | 199 context->added = true; |
| 196 | 200 |
| 197 // Drop all incidents if this profile is not participating in safe browsing. | 201 // Nothing else to do if a report is not being assembled. |
| 202 if (!report_) | |
| 203 return; | |
| 204 | |
| 205 // Drop all incidents received prior to creation if the profile is not | |
| 206 // participating in safe browsing. | |
| 198 if (!context->incidents.empty() && | 207 if (!context->incidents.empty() && |
| 199 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | 208 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { |
| 200 for (size_t i = 0; i < context->incidents.size(); ++i) { | 209 for (size_t i = 0; i < context->incidents.size(); ++i) { |
| 201 LogIncidentDataType(DROPPED, *context->incidents[i]); | 210 LogIncidentDataType(DROPPED, *context->incidents[i]); |
| 202 } | 211 } |
| 203 context->incidents.clear(); | 212 context->incidents.clear(); |
| 204 } | 213 } |
| 214 | |
| 215 // Take another stab at finding the most recent download if a report is being | |
| 216 // assembled and one hasn't been found yet (the LastDownloadFinder operates | |
| 217 // only on profiles that have been added to the ProfileManager). | |
| 218 BeginDownloadCollection(); | |
| 219 } | |
| 220 | |
| 221 scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder( | |
| 222 const LastDownloadFinder::LastDownloadCallback& callback) { | |
| 223 return LastDownloadFinder::Create(callback).Pass(); | |
| 205 } | 224 } |
| 206 | 225 |
| 207 scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload( | 226 scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload( |
| 208 const IncidentReportUploader::OnResultCallback& callback, | 227 const IncidentReportUploader::OnResultCallback& callback, |
| 209 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, | 228 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, |
| 210 const ClientIncidentReport& report) { | 229 const ClientIncidentReport& report) { |
| 211 #if 0 | |
| 212 return IncidentReportUploaderImpl::UploadReport( | 230 return IncidentReportUploaderImpl::UploadReport( |
| 213 callback, request_context_getter, report).Pass(); | 231 callback, request_context_getter, report).Pass(); |
| 214 #else | |
| 215 // TODO(grt): Remove this temporary suppression of all uploads. | |
| 216 return scoped_ptr<IncidentReportUploader>(); | |
| 217 #endif | |
| 218 } | 232 } |
| 219 | 233 |
| 220 IncidentReportingService::ProfileContext* | 234 IncidentReportingService::ProfileContext* |
| 221 IncidentReportingService::GetOrCreateProfileContext(Profile* profile) { | 235 IncidentReportingService::GetOrCreateProfileContext(Profile* profile) { |
| 222 ProfileContextCollection::iterator it = | 236 ProfileContextCollection::iterator it = |
| 223 profiles_.insert(ProfileContextCollection::value_type(profile, NULL)) | 237 profiles_.insert(ProfileContextCollection::value_type(profile, NULL)) |
| 224 .first; | 238 .first; |
| 225 if (!it->second) | 239 if (!it->second) |
| 226 it->second = new ProfileContext(); | 240 it->second = new ProfileContext(); |
| 227 return it->second; | 241 return it->second; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { | 279 scoped_ptr<ClientIncidentReport_IncidentData> incident_data) { |
| 266 DCHECK(thread_checker_.CalledOnValidThread()); | 280 DCHECK(thread_checker_.CalledOnValidThread()); |
| 267 // Incidents outside the context of a profile are not supported at the moment. | 281 // Incidents outside the context of a profile are not supported at the moment. |
| 268 DCHECK(profile); | 282 DCHECK(profile); |
| 269 | 283 |
| 270 ProfileContext* context = GetProfileContext(profile); | 284 ProfileContext* context = GetProfileContext(profile); |
| 271 // It is forbidden to call this function with a destroyed profile. | 285 // It is forbidden to call this function with a destroyed profile. |
| 272 DCHECK(context); | 286 DCHECK(context); |
| 273 | 287 |
| 274 // Drop the incident immediately if profile creation has completed and the | 288 // Drop the incident immediately if profile creation has completed and the |
| 275 // profile is not participating in safe browsing. | 289 // profile is not participating in safe browsing. Preference evaluation is |
| 276 if (context->created && | 290 // deferred until OnProfileAdded() if profile creation has not yet |
| 291 // completed. | |
| 292 if (context->added && | |
| 277 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { | 293 !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) { |
| 278 LogIncidentDataType(DROPPED, *incident_data); | 294 LogIncidentDataType(DROPPED, *incident_data); |
| 279 return; | 295 return; |
| 280 } | 296 } |
| 281 | 297 |
| 282 // Create a new report if this is the first incident ever or first since last | 298 // Start assembling a new report if this is the first incident ever or the |
| 283 // upload. | 299 // first since the last upload. |
| 284 if (!report_) { | 300 if (!report_) { |
| 285 report_.reset(new ClientIncidentReport()); | 301 report_.reset(new ClientIncidentReport()); |
| 286 first_incident_time_ = base::Time::Now(); | 302 first_incident_time_ = base::Time::Now(); |
| 287 } | 303 } |
| 288 | 304 |
| 289 // Provide time to the new incident if the caller didn't provide it. | 305 // Provide time to the new incident if the caller didn't do so. |
| 290 if (!incident_data->has_incident_time_msec()) | 306 if (!incident_data->has_incident_time_msec()) |
| 291 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); | 307 incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime()); |
| 292 | 308 |
| 293 // Take ownership of the incident. | 309 // Take ownership of the incident. |
| 294 context->incidents.push_back(incident_data.release()); | 310 context->incidents.push_back(incident_data.release()); |
| 295 | 311 |
| 296 if (!last_incident_time_.is_null()) { | 312 if (!last_incident_time_.is_null()) { |
| 297 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", | 313 UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime", |
| 298 base::TimeTicks::Now() - last_incident_time_); | 314 base::TimeTicks::Now() - last_incident_time_); |
| 299 } | 315 } |
| 300 last_incident_time_ = base::TimeTicks::Now(); | 316 last_incident_time_ = base::TimeTicks::Now(); |
| 301 | 317 |
| 302 // Persist the incident data. | 318 // Persist the incident data. |
| 303 | 319 |
| 304 // Restart the delay timer to send the report upon expiration. | 320 // Restart the delay timer to send the report upon expiration. |
| 305 collection_timeout_pending_ = true; | 321 collection_timeout_pending_ = true; |
| 306 upload_timer_.Reset(); | 322 upload_timer_.Reset(); |
| 307 | 323 |
| 308 BeginEnvironmentCollection(); | 324 BeginEnvironmentCollection(); |
| 325 BeginDownloadCollection(); | |
| 309 } | 326 } |
| 310 | 327 |
| 311 void IncidentReportingService::BeginEnvironmentCollection() { | 328 void IncidentReportingService::BeginEnvironmentCollection() { |
| 312 DCHECK(thread_checker_.CalledOnValidThread()); | 329 DCHECK(thread_checker_.CalledOnValidThread()); |
| 313 DCHECK(report_); | 330 DCHECK(report_); |
| 331 // Nothing to do if environment collection is pending or has already | |
| 332 // completed. | |
| 314 if (environment_collection_pending_ || report_->has_environment()) | 333 if (environment_collection_pending_ || report_->has_environment()) |
| 315 return; | 334 return; |
| 316 | 335 |
| 317 environment_collection_begin_ = base::TimeTicks::Now(); | 336 environment_collection_begin_ = base::TimeTicks::Now(); |
| 318 ClientIncidentReport_EnvironmentData* environment_data = | 337 ClientIncidentReport_EnvironmentData* environment_data = |
| 319 new ClientIncidentReport_EnvironmentData(); | 338 new ClientIncidentReport_EnvironmentData(); |
| 320 environment_collection_pending_ = | 339 environment_collection_pending_ = |
| 321 environment_collection_task_runner_->PostTaskAndReply( | 340 environment_collection_task_runner_->PostTaskAndReply( |
| 322 FROM_HERE, | 341 FROM_HERE, |
| 323 base::Bind(collect_environment_data_fn_, environment_data), | 342 base::Bind(collect_environment_data_fn_, environment_data), |
| 324 base::Bind(&IncidentReportingService::OnEnvironmentDataCollected, | 343 base::Bind(&IncidentReportingService::OnEnvironmentDataCollected, |
| 325 weak_ptr_factory_.GetWeakPtr(), | 344 weak_ptr_factory_.GetWeakPtr(), |
| 326 base::Passed(make_scoped_ptr(environment_data)))); | 345 base::Passed(make_scoped_ptr(environment_data)))); |
| 327 | 346 |
| 328 // Posting the task will fail if the runner has been shut down. This should | 347 // Posting the task will fail if the runner has been shut down. This should |
| 329 // never happen since the blocking pool is shut down after this service. | 348 // never happen since the blocking pool is shut down after this service. |
| 330 DCHECK(environment_collection_pending_); | 349 DCHECK(environment_collection_pending_); |
| 331 } | 350 } |
| 332 | 351 |
| 352 bool IncidentReportingService::WaitingForEnvironmentCollection() { | |
| 353 return environment_collection_pending_; | |
| 354 } | |
| 355 | |
| 333 void IncidentReportingService::CancelEnvironmentCollection() { | 356 void IncidentReportingService::CancelEnvironmentCollection() { |
| 334 environment_collection_begin_ = base::TimeTicks(); | 357 environment_collection_begin_ = base::TimeTicks(); |
| 335 environment_collection_pending_ = false; | 358 environment_collection_pending_ = false; |
| 336 if (report_) | 359 if (report_) |
| 337 report_->clear_environment(); | 360 report_->clear_environment(); |
| 338 } | 361 } |
| 339 | 362 |
| 340 void IncidentReportingService::OnEnvironmentDataCollected( | 363 void IncidentReportingService::OnEnvironmentDataCollected( |
| 341 scoped_ptr<ClientIncidentReport_EnvironmentData> environment_data) { | 364 scoped_ptr<ClientIncidentReport_EnvironmentData> environment_data) { |
| 342 DCHECK(thread_checker_.CalledOnValidThread()); | 365 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 354 | 377 |
| 355 report_->set_allocated_environment(environment_data.release()); | 378 report_->set_allocated_environment(environment_data.release()); |
| 356 | 379 |
| 357 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", | 380 UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime", |
| 358 base::TimeTicks::Now() - environment_collection_begin_); | 381 base::TimeTicks::Now() - environment_collection_begin_); |
| 359 environment_collection_begin_ = base::TimeTicks(); | 382 environment_collection_begin_ = base::TimeTicks(); |
| 360 | 383 |
| 361 UploadIfCollectionComplete(); | 384 UploadIfCollectionComplete(); |
| 362 } | 385 } |
| 363 | 386 |
| 387 bool IncidentReportingService::WaitingToCollateIncidents() { | |
| 388 return collection_timeout_pending_; | |
| 389 } | |
| 390 | |
| 364 void IncidentReportingService::CancelIncidentCollection() { | 391 void IncidentReportingService::CancelIncidentCollection() { |
| 365 collection_timeout_pending_ = false; | 392 collection_timeout_pending_ = false; |
| 366 last_incident_time_ = base::TimeTicks(); | 393 last_incident_time_ = base::TimeTicks(); |
| 367 report_.reset(); | 394 report_.reset(); |
| 368 } | 395 } |
| 369 | 396 |
| 370 void IncidentReportingService::OnCollectionTimeout() { | 397 void IncidentReportingService::OnCollectionTimeout() { |
| 371 DCHECK(thread_checker_.CalledOnValidThread()); | 398 DCHECK(thread_checker_.CalledOnValidThread()); |
| 372 | 399 |
| 373 // Exit early if collection was cancelled. | 400 // Exit early if collection was cancelled. |
| 374 if (!collection_timeout_pending_) | 401 if (!collection_timeout_pending_) |
| 375 return; | 402 return; |
| 376 | 403 |
| 377 // Wait another round if incidents have come in from a profile that has yet to | 404 // Wait another round if incidents have come in from a profile that has yet to |
| 378 // complete creation. | 405 // complete creation. |
| 379 for (ProfileContextCollection::iterator scan = profiles_.begin(); | 406 for (ProfileContextCollection::iterator scan = profiles_.begin(); |
| 380 scan != profiles_.end(); | 407 scan != profiles_.end(); |
| 381 ++scan) { | 408 ++scan) { |
| 382 if (!scan->second->created && !scan->second->incidents.empty()) { | 409 if (!scan->second->added && !scan->second->incidents.empty()) { |
| 383 upload_timer_.Reset(); | 410 upload_timer_.Reset(); |
| 384 return; | 411 return; |
| 385 } | 412 } |
| 386 } | 413 } |
| 387 | 414 |
| 388 collection_timeout_pending_ = false; | 415 collection_timeout_pending_ = false; |
| 389 | 416 |
| 390 UploadIfCollectionComplete(); | 417 UploadIfCollectionComplete(); |
| 391 } | 418 } |
| 392 | 419 |
| 393 void IncidentReportingService::CollectDownloadDetails( | 420 void IncidentReportingService::BeginDownloadCollection() { |
| 394 ClientIncidentReport_DownloadDetails* download_details) { | |
| 395 DCHECK(thread_checker_.CalledOnValidThread()); | 421 DCHECK(thread_checker_.CalledOnValidThread()); |
| 396 // TODO(grt): collect download info; http://crbug.com/383042. | 422 DCHECK(report_); |
| 423 // Nothing to do if a search for the most recent download is already pending | |
| 424 // or if one has already been found. | |
| 425 if (last_download_finder_ || report_->has_download()) | |
| 426 return; | |
| 427 | |
| 428 last_download_begin_ = base::TimeTicks::Now(); | |
| 429 last_download_finder_ = CreateDownloadFinder( | |
| 430 base::Bind(&IncidentReportingService::OnLastDownloadFound, | |
| 431 weak_ptr_factory_.GetWeakPtr())); | |
| 432 // No instance is returned if there are no eligible loaded profiles. Another | |
| 433 // search will be attempted in OnProfileAdded() if another profile appears on | |
| 434 // the scene. | |
| 435 if (!last_download_finder_) | |
| 436 last_download_begin_ = base::TimeTicks(); | |
| 437 } | |
| 438 | |
| 439 bool IncidentReportingService::WaitingForMostRecentDownload() { | |
| 440 DCHECK(report_); // Only call this when a report is being assembled. | |
| 441 // The easy case: not waiting if a download has already been found. | |
| 442 if (report_->has_download()) | |
| 443 return false; | |
| 444 // The next easy case: waiting if the finder is operating. | |
| 445 if (last_download_finder_) | |
| 446 return true; | |
| 447 // The harder case: waiting if a profile has not yet been added. | |
| 448 for (ProfileContextCollection::const_iterator scan = profiles_.begin(); | |
| 449 scan != profiles_.end(); | |
| 450 ++scan) { | |
| 451 if (!scan->second->added) | |
| 452 return true; | |
| 453 } | |
| 454 // There is no most recent download and there's nothing more to wait for. | |
| 455 return false; | |
| 456 } | |
| 457 | |
| 458 void IncidentReportingService::CancelDownloadCollection() { | |
| 459 last_download_finder_.reset(); | |
| 460 last_download_begin_ = base::TimeTicks(); | |
| 461 if (report_) | |
| 462 report_->clear_download(); | |
| 463 } | |
| 464 | |
| 465 void IncidentReportingService::OnLastDownloadFound( | |
| 466 scoped_ptr<ClientIncidentReport_DownloadDetails> last_download) { | |
| 467 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 468 DCHECK(report_); | |
| 469 | |
| 470 UMA_HISTOGRAM_TIMES("SBIRS.DownloadCollectionTime", | |
| 471 base::TimeTicks::Now() - last_download_begin_); | |
| 472 last_download_begin_ = base::TimeTicks(); | |
| 473 | |
| 474 // Harvest the finder. | |
| 475 last_download_finder_.reset(); | |
| 476 | |
| 477 if (last_download) | |
| 478 report_->set_allocated_download(last_download.release()); | |
| 479 | |
| 480 UploadIfCollectionComplete(); | |
| 397 } | 481 } |
| 398 | 482 |
| 399 void IncidentReportingService::UploadIfCollectionComplete() { | 483 void IncidentReportingService::UploadIfCollectionComplete() { |
| 400 DCHECK(report_); | 484 DCHECK(report_); |
| 401 // Bail out if there are still outstanding collection tasks. | 485 // Bail out if there are still outstanding collection tasks. Completion of any |
| 402 if (environment_collection_pending_ || collection_timeout_pending_) | 486 // of these will start another upload attempt. |
| 487 if (WaitingForEnvironmentCollection() || | |
| 488 WaitingToCollateIncidents() || | |
| 489 WaitingForMostRecentDownload()) { | |
| 403 return; | 490 return; |
| 491 } | |
| 404 | 492 |
| 405 // Take ownership of the report and clear things for future reports. | 493 // Take ownership of the report and clear things for future reports. |
| 406 scoped_ptr<ClientIncidentReport> report(report_.Pass()); | 494 scoped_ptr<ClientIncidentReport> report(report_.Pass()); |
| 407 last_incident_time_ = base::TimeTicks(); | 495 last_incident_time_ = base::TimeTicks(); |
| 408 | 496 |
| 497 // Drop the report if no executable download was found. | |
| 498 if (!report->has_download()) { | |
| 499 UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult", | |
| 500 IncidentReportUploader::UPLOAD_NO_DOWNLOAD, | |
| 501 IncidentReportUploader::NUM_UPLOAD_RESULTS); | |
| 502 return; | |
| 503 } | |
| 504 | |
| 409 ClientIncidentReport_EnvironmentData_Process* process = | 505 ClientIncidentReport_EnvironmentData_Process* process = |
| 410 report->mutable_environment()->mutable_process(); | 506 report->mutable_environment()->mutable_process(); |
| 411 | 507 |
| 412 // Not all platforms have a metrics reporting preference. | 508 // Not all platforms have a metrics reporting preference. |
| 413 if (g_browser_process->local_state()->FindPreference( | 509 if (g_browser_process->local_state()->FindPreference( |
| 414 prefs::kMetricsReportingEnabled)) { | 510 prefs::kMetricsReportingEnabled)) { |
| 415 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( | 511 process->set_metrics_consent(g_browser_process->local_state()->GetBoolean( |
| 416 prefs::kMetricsReportingEnabled)); | 512 prefs::kMetricsReportingEnabled)); |
| 417 } | 513 } |
| 418 | 514 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 if (result == IncidentReportUploader::UPLOAD_SUCCESS) | 655 if (result == IncidentReportUploader::UPLOAD_SUCCESS) |
| 560 HandleResponse(*upload); | 656 HandleResponse(*upload); |
| 561 // else retry? | 657 // else retry? |
| 562 } | 658 } |
| 563 | 659 |
| 564 void IncidentReportingService::Observe( | 660 void IncidentReportingService::Observe( |
| 565 int type, | 661 int type, |
| 566 const content::NotificationSource& source, | 662 const content::NotificationSource& source, |
| 567 const content::NotificationDetails& details) { | 663 const content::NotificationDetails& details) { |
| 568 switch (type) { | 664 switch (type) { |
| 569 case chrome::NOTIFICATION_PROFILE_CREATED: { | 665 case chrome::NOTIFICATION_PROFILE_ADDED: { |
| 570 Profile* profile = content::Source<Profile>(source).ptr(); | 666 Profile* profile = content::Source<Profile>(source).ptr(); |
| 571 if (!profile->IsOffTheRecord()) | 667 if (!profile->IsOffTheRecord()) |
| 572 OnProfileCreated(profile); | 668 OnProfileAdded(profile); |
| 573 break; | 669 break; |
| 574 } | 670 } |
| 575 case chrome::NOTIFICATION_PROFILE_DESTROYED: { | 671 case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
| 576 Profile* profile = content::Source<Profile>(source).ptr(); | 672 Profile* profile = content::Source<Profile>(source).ptr(); |
| 577 if (!profile->IsOffTheRecord()) | 673 if (!profile->IsOffTheRecord()) |
| 578 OnProfileDestroyed(profile); | 674 OnProfileDestroyed(profile); |
| 579 break; | 675 break; |
| 580 } | 676 } |
| 581 default: | 677 default: |
| 582 break; | 678 break; |
| 583 } | 679 } |
| 584 } | 680 } |
| 585 | 681 |
| 586 } // namespace safe_browsing | 682 } // namespace safe_browsing |
| OLD | NEW |