| 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   66  |   66  | 
|   67 }  // namespace |   67 }  // namespace | 
|   68  |   68  | 
|   69 struct IncidentReportingService::ProfileContext { |   69 struct IncidentReportingService::ProfileContext { | 
|   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.FindDownloadedBinaryTime", | 
 |  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 |