| Index: chrome/browser/safe_browsing/incident_reporting_service.cc
|
| ===================================================================
|
| --- chrome/browser/safe_browsing/incident_reporting_service.cc (revision 281829)
|
| +++ chrome/browser/safe_browsing/incident_reporting_service.cc (working copy)
|
| @@ -73,8 +73,8 @@
|
| // The incidents collected for this profile pending creation and/or upload.
|
| ScopedVector<ClientIncidentReport_IncidentData> incidents;
|
|
|
| - // False until PROFILE_CREATED notification is received.
|
| - bool created;
|
| + // False until PROFILE_ADDED notification is received.
|
| + bool added;
|
|
|
| private:
|
| DISALLOW_COPY_AND_ASSIGN(ProfileContext);
|
| @@ -98,7 +98,7 @@
|
| DISALLOW_COPY_AND_ASSIGN(UploadContext);
|
| };
|
|
|
| -IncidentReportingService::ProfileContext::ProfileContext() : created() {
|
| +IncidentReportingService::ProfileContext::ProfileContext() : added() {
|
| }
|
|
|
| IncidentReportingService::ProfileContext::~ProfileContext() {
|
| @@ -132,7 +132,7 @@
|
| receiver_weak_ptr_factory_(this),
|
| weak_ptr_factory_(this) {
|
| notification_registrar_.Add(this,
|
| - chrome::NOTIFICATION_PROFILE_CREATED,
|
| + chrome::NOTIFICATION_PROFILE_ADDED,
|
| content::NotificationService::AllSources());
|
| notification_registrar_.Add(this,
|
| chrome::NOTIFICATION_PROFILE_DESTROYED,
|
| @@ -146,6 +146,7 @@
|
| weak_ptr_factory_.InvalidateWeakPtrs();
|
|
|
| CancelEnvironmentCollection();
|
| + CancelDownloadCollection();
|
| CancelAllReportUploads();
|
|
|
| STLDeleteValues(&profiles_);
|
| @@ -154,7 +155,7 @@
|
| AddIncidentCallback IncidentReportingService::GetAddIncidentCallback(
|
| Profile* profile) {
|
| // Force the context to be created so that incidents added before
|
| - // OnProfileCreated is called are held until the profile's preferences can be
|
| + // OnProfileAdded is called are held until the profile's preferences can be
|
| // queried.
|
| ignore_result(GetOrCreateProfileContext(profile));
|
|
|
| @@ -188,13 +189,21 @@
|
| }
|
| }
|
|
|
| -void IncidentReportingService::OnProfileCreated(Profile* profile) {
|
| +void IncidentReportingService::OnProfileAdded(Profile* profile) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| + // Track the addition of all profiles even when no report is being assembled
|
| + // so that the service can determine whether or not it can evaluate a
|
| + // profile's preferences at the time of incident addition.
|
| ProfileContext* context = GetOrCreateProfileContext(profile);
|
| - context->created = true;
|
| + context->added = true;
|
|
|
| - // Drop all incidents if this profile is not participating in safe browsing.
|
| + // Nothing else to do if a report is not being assembled.
|
| + if (!report_)
|
| + return;
|
| +
|
| + // Drop all incidents received prior to creation if the profile is not
|
| + // participating in safe browsing.
|
| if (!context->incidents.empty() &&
|
| !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
|
| for (size_t i = 0; i < context->incidents.size(); ++i) {
|
| @@ -202,19 +211,24 @@
|
| }
|
| context->incidents.clear();
|
| }
|
| +
|
| + // Take another stab at finding the most recent download if a report is being
|
| + // assembled and one hasn't been found yet (the LastDownloadFinder operates
|
| + // only on profiles that have been added to the ProfileManager).
|
| + BeginDownloadCollection();
|
| }
|
|
|
| +scoped_ptr<LastDownloadFinder> IncidentReportingService::CreateDownloadFinder(
|
| + const LastDownloadFinder::LastDownloadCallback& callback) {
|
| + return LastDownloadFinder::Create(callback).Pass();
|
| +}
|
| +
|
| scoped_ptr<IncidentReportUploader> IncidentReportingService::StartReportUpload(
|
| const IncidentReportUploader::OnResultCallback& callback,
|
| const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
|
| const ClientIncidentReport& report) {
|
| -#if 0
|
| return IncidentReportUploaderImpl::UploadReport(
|
| callback, request_context_getter, report).Pass();
|
| -#else
|
| - // TODO(grt): Remove this temporary suppression of all uploads.
|
| - return scoped_ptr<IncidentReportUploader>();
|
| -#endif
|
| }
|
|
|
| IncidentReportingService::ProfileContext*
|
| @@ -272,21 +286,23 @@
|
| DCHECK(context);
|
|
|
| // Drop the incident immediately if profile creation has completed and the
|
| - // profile is not participating in safe browsing.
|
| - if (context->created &&
|
| + // profile is not participating in safe browsing. Preference evaluation is
|
| + // deferred until OnProfileAdded() if profile creation has not yet
|
| + // completed.
|
| + if (context->added &&
|
| !profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
|
| LogIncidentDataType(DROPPED, *incident_data);
|
| return;
|
| }
|
|
|
| - // Create a new report if this is the first incident ever or first since last
|
| - // upload.
|
| + // Start assembling a new report if this is the first incident ever or the
|
| + // first since the last upload.
|
| if (!report_) {
|
| report_.reset(new ClientIncidentReport());
|
| first_incident_time_ = base::Time::Now();
|
| }
|
|
|
| - // Provide time to the new incident if the caller didn't provide it.
|
| + // Provide time to the new incident if the caller didn't do so.
|
| if (!incident_data->has_incident_time_msec())
|
| incident_data->set_incident_time_msec(base::Time::Now().ToJavaTime());
|
|
|
| @@ -306,11 +322,14 @@
|
| upload_timer_.Reset();
|
|
|
| BeginEnvironmentCollection();
|
| + BeginDownloadCollection();
|
| }
|
|
|
| void IncidentReportingService::BeginEnvironmentCollection() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(report_);
|
| + // Nothing to do if environment collection is pending or has already
|
| + // completed.
|
| if (environment_collection_pending_ || report_->has_environment())
|
| return;
|
|
|
| @@ -330,6 +349,10 @@
|
| DCHECK(environment_collection_pending_);
|
| }
|
|
|
| +bool IncidentReportingService::WaitingForEnvironmentCollection() {
|
| + return environment_collection_pending_;
|
| +}
|
| +
|
| void IncidentReportingService::CancelEnvironmentCollection() {
|
| environment_collection_begin_ = base::TimeTicks();
|
| environment_collection_pending_ = false;
|
| @@ -361,6 +384,10 @@
|
| UploadIfCollectionComplete();
|
| }
|
|
|
| +bool IncidentReportingService::WaitingToCollateIncidents() {
|
| + return collection_timeout_pending_;
|
| +}
|
| +
|
| void IncidentReportingService::CancelIncidentCollection() {
|
| collection_timeout_pending_ = false;
|
| last_incident_time_ = base::TimeTicks();
|
| @@ -379,7 +406,7 @@
|
| for (ProfileContextCollection::iterator scan = profiles_.begin();
|
| scan != profiles_.end();
|
| ++scan) {
|
| - if (!scan->second->created && !scan->second->incidents.empty()) {
|
| + if (!scan->second->added && !scan->second->incidents.empty()) {
|
| upload_timer_.Reset();
|
| return;
|
| }
|
| @@ -390,22 +417,91 @@
|
| UploadIfCollectionComplete();
|
| }
|
|
|
| -void IncidentReportingService::CollectDownloadDetails(
|
| - ClientIncidentReport_DownloadDetails* download_details) {
|
| +void IncidentReportingService::BeginDownloadCollection() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - // TODO(grt): collect download info; http://crbug.com/383042.
|
| + DCHECK(report_);
|
| + // Nothing to do if a search for the most recent download is already pending
|
| + // or if one has already been found.
|
| + if (last_download_finder_ || report_->has_download())
|
| + return;
|
| +
|
| + last_download_begin_ = base::TimeTicks::Now();
|
| + last_download_finder_ = CreateDownloadFinder(
|
| + base::Bind(&IncidentReportingService::OnLastDownloadFound,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + // No instance is returned if there are no eligible loaded profiles. Another
|
| + // search will be attempted in OnProfileAdded() if another profile appears on
|
| + // the scene.
|
| + if (!last_download_finder_)
|
| + last_download_begin_ = base::TimeTicks();
|
| }
|
|
|
| +bool IncidentReportingService::WaitingForMostRecentDownload() {
|
| + DCHECK(report_); // Only call this when a report is being assembled.
|
| + // The easy case: not waiting if a download has already been found.
|
| + if (report_->has_download())
|
| + return false;
|
| + // The next easy case: waiting if the finder is operating.
|
| + if (last_download_finder_)
|
| + return true;
|
| + // The harder case: waiting if a profile has not yet been added.
|
| + for (ProfileContextCollection::const_iterator scan = profiles_.begin();
|
| + scan != profiles_.end();
|
| + ++scan) {
|
| + if (!scan->second->added)
|
| + return true;
|
| + }
|
| + // There is no most recent download and there's nothing more to wait for.
|
| + return false;
|
| +}
|
| +
|
| +void IncidentReportingService::CancelDownloadCollection() {
|
| + last_download_finder_.reset();
|
| + last_download_begin_ = base::TimeTicks();
|
| + if (report_)
|
| + report_->clear_download();
|
| +}
|
| +
|
| +void IncidentReportingService::OnLastDownloadFound(
|
| + scoped_ptr<ClientIncidentReport_DownloadDetails> last_download) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(report_);
|
| +
|
| + UMA_HISTOGRAM_TIMES("SBIRS.FindDownloadedBinaryTime",
|
| + base::TimeTicks::Now() - last_download_begin_);
|
| + last_download_begin_ = base::TimeTicks();
|
| +
|
| + // Harvest the finder.
|
| + last_download_finder_.reset();
|
| +
|
| + if (last_download)
|
| + report_->set_allocated_download(last_download.release());
|
| +
|
| + UploadIfCollectionComplete();
|
| +}
|
| +
|
| void IncidentReportingService::UploadIfCollectionComplete() {
|
| DCHECK(report_);
|
| - // Bail out if there are still outstanding collection tasks.
|
| - if (environment_collection_pending_ || collection_timeout_pending_)
|
| + // Bail out if there are still outstanding collection tasks. Completion of any
|
| + // of these will start another upload attempt.
|
| + if (WaitingForEnvironmentCollection() ||
|
| + WaitingToCollateIncidents() ||
|
| + WaitingForMostRecentDownload()) {
|
| return;
|
| + }
|
|
|
| // Take ownership of the report and clear things for future reports.
|
| scoped_ptr<ClientIncidentReport> report(report_.Pass());
|
| last_incident_time_ = base::TimeTicks();
|
|
|
| + // Drop the report if no executable download was found.
|
| + if (!report->has_download()) {
|
| + UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult",
|
| + IncidentReportUploader::UPLOAD_NO_DOWNLOAD,
|
| + IncidentReportUploader::NUM_UPLOAD_RESULTS);
|
| + return;
|
| + }
|
| +
|
| ClientIncidentReport_EnvironmentData_Process* process =
|
| report->mutable_environment()->mutable_process();
|
|
|
| @@ -566,10 +662,10 @@
|
| const content::NotificationSource& source,
|
| const content::NotificationDetails& details) {
|
| switch (type) {
|
| - case chrome::NOTIFICATION_PROFILE_CREATED: {
|
| + case chrome::NOTIFICATION_PROFILE_ADDED: {
|
| Profile* profile = content::Source<Profile>(source).ptr();
|
| if (!profile->IsOffTheRecord())
|
| - OnProfileCreated(profile);
|
| + OnProfileAdded(profile);
|
| break;
|
| }
|
| case chrome::NOTIFICATION_PROFILE_DESTROYED: {
|
|
|