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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
6 
7 #include <math.h>
8 #include <stddef.h>
9 
10 #include <algorithm>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/bind.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/process/process.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string_util.h"
22 #include "base/task/post_task.h"
23 #include "base/task/task_traits.h"
24 #include "base/task/thread_pool.h"
25 #include "base/threading/thread_task_runner_handle.h"
26 #include "build/branding_buildflags.h"
27 #include "build/build_config.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/profiles/profile_manager.h"
32 #include "chrome/browser/safe_browsing/incident_reporting/environment_data_collection.h"
33 #include "chrome/browser/safe_browsing/incident_reporting/extension_data_collection.h"
34 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
35 #include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
36 #include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h"
37 #include "chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h"
38 #include "chrome/browser/safe_browsing/incident_reporting/state_store.h"
39 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
40 #include "chrome/common/pref_names.h"
41 #include "components/prefs/pref_service.h"
42 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
43 #include "components/safe_browsing/core/features.h"
44 #include "components/safe_browsing/core/proto/csd.pb.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/download_item_utils.h"
47 #include "services/network/public/cpp/shared_url_loader_factory.h"
48 #include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
49 
50 namespace safe_browsing {
51 
52 const base::Feature kIncidentReportingEnableUpload {
53   "IncidentReportingEnableUpload",
54 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
55       base::FEATURE_ENABLED_BY_DEFAULT
56 #else
57       base::FEATURE_DISABLED_BY_DEFAULT
58 #endif
59 };
60 
61 namespace {
62 
63 // The action taken for an incident; used for user metrics (see
64 // LogIncidentDataType).
65 enum IncidentDisposition {
66   RECEIVED,
67   DROPPED,
68   ACCEPTED,
69   PRUNED,
70   DISCARDED,
71   NO_DOWNLOAD,
72   NUM_DISPOSITIONS
73 };
74 
75 // The state persisted for a specific instance of an incident to enable pruning
76 // of previously-reported incidents.
77 struct PersistentIncidentState {
78   // The type of the incident.
79   IncidentType type;
80 
81   // The key for a specific instance of an incident.
82   std::string key;
83 
84   // A hash digest representing a specific instance of an incident.
85   uint32_t digest;
86 };
87 
88 // The amount of time the service will wait to collate incidents.
89 const int64_t kDefaultUploadDelayMs = 1000 * 60;  // one minute
90 
91 // The amount of time between running delayed analysis callbacks.
92 const int64_t kDefaultCallbackIntervalMs = 1000 * 20;
93 
94 // Logs the type of incident in |incident_data| to a user metrics histogram.
LogIncidentDataType(IncidentDisposition disposition,const Incident & incident)95 void LogIncidentDataType(IncidentDisposition disposition,
96                          const Incident& incident) {
97   static const char* const kHistogramNames[] = {
98       "SBIRS.ReceivedIncident",
99       "SBIRS.DroppedIncident",
100       "SBIRS.Incident",
101       "SBIRS.PrunedIncident",
102       "SBIRS.DiscardedIncident",
103       "SBIRS.NoDownloadIncident",
104   };
105   static_assert(base::size(kHistogramNames) == NUM_DISPOSITIONS,
106                 "Keep kHistogramNames in sync with enum IncidentDisposition.");
107   DCHECK_GE(disposition, 0);
108   DCHECK_LT(disposition, NUM_DISPOSITIONS);
109   base::LinearHistogram::FactoryGet(
110       kHistogramNames[disposition],
111       1,  // minimum
112       static_cast<int32_t>(IncidentType::NUM_TYPES),  // maximum
113       static_cast<size_t>(IncidentType::NUM_TYPES) + 1,  // bucket_count
114       base::HistogramBase::kUmaTargetedHistogramFlag)->Add(
115           static_cast<int32_t>(incident.GetType()));
116 }
117 
118 // Computes the persistent state for an incident.
ComputeIncidentState(const Incident & incident)119 PersistentIncidentState ComputeIncidentState(const Incident& incident) {
120   PersistentIncidentState state = {
121     incident.GetType(),
122     incident.GetKey(),
123     incident.ComputeDigest(),
124   };
125   return state;
126 }
127 
128 // Returns a task runner for blocking tasks in the background.
GetBackgroundTaskRunner()129 scoped_refptr<base::TaskRunner> GetBackgroundTaskRunner() {
130   return base::ThreadPool::CreateTaskRunner(
131       {base::TaskPriority::BEST_EFFORT,
132        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()});
133 }
134 
135 }  // namespace
136 
137 struct IncidentReportingService::ProfileContext {
138   ProfileContext();
139   ~ProfileContext();
140 
141   // Returns true if the profile has incidents to be uploaded or cleared.
142   bool HasIncidents() const;
143 
144   // The incidents collected for this profile pending creation and/or upload.
145   // Will contain null values for pruned incidents.
146   std::vector<std::unique_ptr<Incident>> incidents;
147 
148   // The incidents data of which should be cleared.
149   std::vector<std::unique_ptr<Incident>> incidents_to_clear;
150 
151   // State storage for this profile; null until OnProfileAdded is called.
152   std::unique_ptr<StateStore> state_store;
153 
154   // False until OnProfileAdded is called.
155   bool added;
156 
157  private:
158   DISALLOW_COPY_AND_ASSIGN(ProfileContext);
159 };
160 
161 class IncidentReportingService::UploadContext {
162  public:
163   typedef std::map<ProfileContext*, std::vector<PersistentIncidentState>>
164       PersistentIncidentStateCollection;
165 
166   explicit UploadContext(std::unique_ptr<ClientIncidentReport> report);
167   ~UploadContext();
168 
169   // The report being uploaded.
170   std::unique_ptr<ClientIncidentReport> report;
171 
172   // The uploader in use.
173   std::unique_ptr<IncidentReportUploader> uploader;
174 
175   // A mapping of profile contexts to the data to be persisted upon successful
176   // upload.
177   PersistentIncidentStateCollection profiles_to_state;
178 
179  private:
180   DISALLOW_COPY_AND_ASSIGN(UploadContext);
181 };
182 
183 // An IncidentReceiver that is weakly-bound to the service and transparently
184 // bounces process-wide incidents back to the main thread for handling.
185 class IncidentReportingService::Receiver : public IncidentReceiver {
186  public:
187   explicit Receiver(const base::WeakPtr<IncidentReportingService>& service);
188   ~Receiver() override;
189 
190   // IncidentReceiver methods:
191   void AddIncidentForProfile(Profile* profile,
192                              std::unique_ptr<Incident> incident) override;
193   void AddIncidentForProcess(std::unique_ptr<Incident> incident) override;
194   void ClearIncidentForProcess(std::unique_ptr<Incident> incident) override;
195 
196  private:
197   static void AddIncidentOnMainThread(
198       const base::WeakPtr<IncidentReportingService>& service,
199       Profile* profile,
200       std::unique_ptr<Incident> incident);
201   static void ClearIncidentOnMainThread(
202       const base::WeakPtr<IncidentReportingService>& service,
203       Profile* profile,
204       std::unique_ptr<Incident> incident);
205 
206   base::WeakPtr<IncidentReportingService> service_;
207   scoped_refptr<base::SingleThreadTaskRunner> thread_runner_;
208 
209   DISALLOW_COPY_AND_ASSIGN(Receiver);
210 };
211 
Receiver(const base::WeakPtr<IncidentReportingService> & service)212 IncidentReportingService::Receiver::Receiver(
213     const base::WeakPtr<IncidentReportingService>& service)
214     : service_(service),
215       thread_runner_(base::ThreadTaskRunnerHandle::Get()) {
216 }
217 
~Receiver()218 IncidentReportingService::Receiver::~Receiver() {
219 }
220 
AddIncidentForProfile(Profile * profile,std::unique_ptr<Incident> incident)221 void IncidentReportingService::Receiver::AddIncidentForProfile(
222     Profile* profile,
223     std::unique_ptr<Incident> incident) {
224   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
225   DCHECK(profile);
226   AddIncidentOnMainThread(service_, profile, std::move(incident));
227 }
228 
AddIncidentForProcess(std::unique_ptr<Incident> incident)229 void IncidentReportingService::Receiver::AddIncidentForProcess(
230     std::unique_ptr<Incident> incident) {
231   if (thread_runner_->BelongsToCurrentThread()) {
232     AddIncidentOnMainThread(service_, nullptr, std::move(incident));
233   } else {
234     thread_runner_->PostTask(
235         FROM_HERE,
236         base::BindOnce(
237             &IncidentReportingService::Receiver::AddIncidentOnMainThread,
238             service_, nullptr, std::move(incident)));
239   }
240 }
241 
ClearIncidentForProcess(std::unique_ptr<Incident> incident)242 void IncidentReportingService::Receiver::ClearIncidentForProcess(
243     std::unique_ptr<Incident> incident) {
244   if (thread_runner_->BelongsToCurrentThread()) {
245     ClearIncidentOnMainThread(service_, nullptr, std::move(incident));
246   } else {
247     thread_runner_->PostTask(
248         FROM_HERE,
249         base::BindOnce(
250             &IncidentReportingService::Receiver::ClearIncidentOnMainThread,
251             service_, nullptr, std::move(incident)));
252   }
253 }
254 
HasIncidentsToUpload() const255 bool IncidentReportingService::HasIncidentsToUpload() const {
256   for (const auto& profile_and_context : profiles_) {
257     if (!profile_and_context.second->incidents.empty())
258       return true;
259   }
260   return false;
261 }
262 
263 // static
AddIncidentOnMainThread(const base::WeakPtr<IncidentReportingService> & service,Profile * profile,std::unique_ptr<Incident> incident)264 void IncidentReportingService::Receiver::AddIncidentOnMainThread(
265     const base::WeakPtr<IncidentReportingService>& service,
266     Profile* profile,
267     std::unique_ptr<Incident> incident) {
268   if (service)
269     service->AddIncident(profile, std::move(incident));
270   else
271     LogIncidentDataType(DISCARDED, *incident);
272 }
273 
274 // static
ClearIncidentOnMainThread(const base::WeakPtr<IncidentReportingService> & service,Profile * profile,std::unique_ptr<Incident> incident)275 void IncidentReportingService::Receiver::ClearIncidentOnMainThread(
276     const base::WeakPtr<IncidentReportingService>& service,
277     Profile* profile,
278     std::unique_ptr<Incident> incident) {
279   if (service)
280     service->ClearIncident(profile, std::move(incident));
281 }
282 
ProfileContext()283 IncidentReportingService::ProfileContext::ProfileContext() : added(false) {
284 }
285 
~ProfileContext()286 IncidentReportingService::ProfileContext::~ProfileContext() {
287   for (const auto& incident : incidents) {
288     if (incident)
289       LogIncidentDataType(DISCARDED, *incident);
290   }
291 }
292 
HasIncidents() const293 bool IncidentReportingService::ProfileContext::HasIncidents() const {
294   return !incidents.empty() || !incidents_to_clear.empty();
295 }
296 
UploadContext(std::unique_ptr<ClientIncidentReport> report)297 IncidentReportingService::UploadContext::UploadContext(
298     std::unique_ptr<ClientIncidentReport> report)
299     : report(std::move(report)) {}
300 
~UploadContext()301 IncidentReportingService::UploadContext::~UploadContext() {
302 }
303 
304 // static
IsEnabledForProfile(Profile * profile)305 bool IncidentReportingService::IsEnabledForProfile(Profile* profile) {
306   if (profile->IsOffTheRecord())
307     return false;
308   if (!IsSafeBrowsingEnabled(*profile->GetPrefs()))
309     return false;
310   return IsExtendedReportingEnabled(*profile->GetPrefs());
311 }
312 
IncidentReportingService(SafeBrowsingService * safe_browsing_service)313 IncidentReportingService::IncidentReportingService(
314     SafeBrowsingService* safe_browsing_service)
315     : IncidentReportingService(
316           safe_browsing_service,
317           base::TimeDelta::FromMilliseconds(kDefaultCallbackIntervalMs),
318           GetBackgroundTaskRunner()) {
319   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
320   DownloadProtectionService* download_protection_service =
321       (safe_browsing_service
322            ? safe_browsing_service->download_protection_service()
323            : nullptr);
324   if (download_protection_service) {
325     client_download_request_subscription_ =
326         download_protection_service->RegisterClientDownloadRequestCallback(
327             base::BindRepeating(
328                 &IncidentReportingService::OnClientDownloadRequest,
329                 base::Unretained(this)));
330   }
331 }
332 
~IncidentReportingService()333 IncidentReportingService::~IncidentReportingService() {
334   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
335   CancelIncidentCollection();
336 
337   // Cancel all internal asynchronous tasks.
338   weak_ptr_factory_.InvalidateWeakPtrs();
339 
340   CancelEnvironmentCollection();
341   CancelDownloadCollection();
342   CancelAllReportUploads();
343 
344   if (g_browser_process->profile_manager())
345     g_browser_process->profile_manager()->RemoveObserver(this);
346 
347   for (const auto& profile_and_context : profiles_) {
348     Profile* profile = profile_and_context.first;
349     if (profile)
350       profile->RemoveObserver(this);
351   }
352 }
353 
354 std::unique_ptr<IncidentReceiver>
GetIncidentReceiver()355 IncidentReportingService::GetIncidentReceiver() {
356   return std::make_unique<Receiver>(receiver_weak_ptr_factory_.GetWeakPtr());
357 }
358 
359 std::unique_ptr<prefs::mojom::TrackedPreferenceValidationDelegate>
CreatePreferenceValidationDelegate(Profile * profile)360 IncidentReportingService::CreatePreferenceValidationDelegate(Profile* profile) {
361   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
362 
363   if (profile->IsOffTheRecord())
364     return std::unique_ptr<prefs::mojom::TrackedPreferenceValidationDelegate>();
365   return std::make_unique<PreferenceValidationDelegate>(profile,
366                                                         GetIncidentReceiver());
367 }
368 
RegisterDelayedAnalysisCallback(DelayedAnalysisCallback callback)369 void IncidentReportingService::RegisterDelayedAnalysisCallback(
370     DelayedAnalysisCallback callback) {
371   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
372 
373   // |callback| will be run on the blocking pool. The receiver will bounce back
374   // to the origin thread if needed.
375   delayed_analysis_callbacks_.RegisterCallback(
376       base::BindOnce(std::move(callback), base::Passed(GetIncidentReceiver())));
377 
378   // Start running the callbacks if any profiles are participating in safe
379   // browsing extended reporting. If none are now, running will commence if/when
380   // such a profile is added.
381   if (FindEligibleProfile())
382     delayed_analysis_callbacks_.Start();
383 }
384 
AddDownloadManager(content::DownloadManager * download_manager)385 void IncidentReportingService::AddDownloadManager(
386     content::DownloadManager* download_manager) {
387   download_metadata_manager_.AddDownloadManager(download_manager);
388 }
389 
IncidentReportingService(SafeBrowsingService * safe_browsing_service,base::TimeDelta delayed_task_interval,const scoped_refptr<base::TaskRunner> & delayed_task_runner)390 IncidentReportingService::IncidentReportingService(
391     SafeBrowsingService* safe_browsing_service,
392     base::TimeDelta delayed_task_interval,
393     const scoped_refptr<base::TaskRunner>& delayed_task_runner)
394     : url_loader_factory_(nullptr),
395       collect_environment_data_fn_(&CollectEnvironmentData),
396       environment_collection_task_runner_(GetBackgroundTaskRunner()),
397       collation_timer_(FROM_HERE,
398                        base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs),
399                        this,
400                        &IncidentReportingService::OnCollationTimeout),
401       delayed_analysis_callbacks_(delayed_task_interval, delayed_task_runner) {
402   if (base::FeatureList::IsEnabled(kSafeBrowsingRemoveCookies)) {
403     url_loader_factory_ = g_browser_process->shared_url_loader_factory();
404   } else if (safe_browsing_service) {
405     url_loader_factory_ = safe_browsing_service->GetURLLoaderFactory();
406   }
407   if (g_browser_process->profile_manager())
408     g_browser_process->profile_manager()->AddObserver(this);
409 }
410 
SetCollectEnvironmentHook(CollectEnvironmentDataFn collect_environment_data_hook,const scoped_refptr<base::TaskRunner> & task_runner)411 void IncidentReportingService::SetCollectEnvironmentHook(
412     CollectEnvironmentDataFn collect_environment_data_hook,
413     const scoped_refptr<base::TaskRunner>& task_runner) {
414   if (collect_environment_data_hook) {
415     collect_environment_data_fn_ = collect_environment_data_hook;
416     environment_collection_task_runner_ = task_runner;
417   } else {
418     collect_environment_data_fn_ = &CollectEnvironmentData;
419     environment_collection_task_runner_ = GetBackgroundTaskRunner();
420   }
421 }
422 
DoExtensionCollection(ClientIncidentReport_ExtensionData * extension_data)423 void IncidentReportingService::DoExtensionCollection(
424     ClientIncidentReport_ExtensionData* extension_data) {
425   CollectExtensionData(extension_data);
426 }
427 
OnProfileAdded(Profile * profile)428 void IncidentReportingService::OnProfileAdded(Profile* profile) {
429   // Handle the addition of a new profile to the ProfileManager. Create a new
430   // context for |profile| if one does not exist, drop any received incidents
431   // for the profile if the profile is not participating in safe browsing
432   // extended reporting, and initiate a new search for the most recent download
433   // if a report is being assembled and the most recent has not been found.
434   // Note that |profile| is assumed to outlive |this|.
435 
436   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
437 
438   // Track the addition of all profiles even when no report is being assembled
439   // so that the service can determine whether or not it can evaluate a
440   // profile's preferences at the time of incident addition.
441   ProfileContext* context = GetOrCreateProfileContext(profile);
442   DCHECK(!context->added);
443   context->added = true;
444   context->state_store = std::make_unique<StateStore>(profile);
445   bool enabled_for_profile = IsEnabledForProfile(profile);
446 
447   // Drop all incidents associated with this profile that were received prior to
448   // its addition if incident reporting is not enabled for it.
449   if (!context->incidents.empty() && !enabled_for_profile) {
450     for (const auto& incident : context->incidents)
451       LogIncidentDataType(DROPPED, *incident);
452     context->incidents.clear();
453   }
454 
455   if (enabled_for_profile) {
456     // Start processing delayed analysis callbacks if incident reporting is
457     // enabled for this new profile. Start is idempotent, so this is safe even
458     // if they're already running.
459     delayed_analysis_callbacks_.Start();
460 
461     // Start a new report if there are process-wide incidents, or incidents for
462     // this profile.
463     if ((GetProfileContext(nullptr) &&
464          GetProfileContext(nullptr)->HasIncidents()) ||
465         context->HasIncidents()) {
466       BeginReportProcessing();
467     }
468   }
469 
470   // TODO(grt): register for pref change notifications to start delayed analysis
471   // and/or report processing if sb is currently disabled but subsequently
472   // enabled.
473 
474   // Nothing else to do if a report is not being assembled.
475   if (!report_)
476     return;
477 
478   // Environment collection is deferred until at least one profile for which the
479   // service is enabled is added. Re-initiate collection now in case this is the
480   // first such profile.
481   BeginEnvironmentCollection();
482   // Take another stab at finding the most recent download if a report is being
483   // assembled and one hasn't been found yet (the LastDownloadFinder operates
484   // only on profiles that have been added to the ProfileManager).
485   BeginDownloadCollection();
486 }
487 
OnProfileWillBeDestroyed(Profile * profile)488 void IncidentReportingService::OnProfileWillBeDestroyed(Profile* profile) {
489   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
490 
491   profile->RemoveObserver(this);
492 
493   auto it = profiles_.find(profile);
494   DCHECK(it != profiles_.end());
495 
496   // Take ownership of the context.
497   std::unique_ptr<ProfileContext> context = std::move(it->second);
498 
499   // TODO(grt): Persist incidents for upload on future profile load.
500 
501   // Remove the association with this profile context from all pending uploads.
502   for (const auto& upload : uploads_)
503     upload->profiles_to_state.erase(context.get());
504 
505   // Forget about this profile. Incidents not yet sent for upload are lost.
506   // No new incidents will be accepted for it.
507   profiles_.erase(it);
508 }
509 
510 std::unique_ptr<LastDownloadFinder>
CreateDownloadFinder(LastDownloadFinder::LastDownloadCallback callback)511 IncidentReportingService::CreateDownloadFinder(
512     LastDownloadFinder::LastDownloadCallback callback) {
513   return LastDownloadFinder::Create(
514       base::BindRepeating(&DownloadMetadataManager::GetDownloadDetails,
515                           base::Unretained(&download_metadata_manager_)),
516       std::move(callback));
517 }
518 
519 std::unique_ptr<IncidentReportUploader>
StartReportUpload(IncidentReportUploader::OnResultCallback callback,const ClientIncidentReport & report)520 IncidentReportingService::StartReportUpload(
521     IncidentReportUploader::OnResultCallback callback,
522     const ClientIncidentReport& report) {
523   return IncidentReportUploaderImpl::UploadReport(std::move(callback),
524                                                   url_loader_factory_, report);
525 }
526 
IsProcessingReport() const527 bool IncidentReportingService::IsProcessingReport() const {
528   return report_ != nullptr;
529 }
530 
531 IncidentReportingService::ProfileContext*
GetOrCreateProfileContext(Profile * profile)532 IncidentReportingService::GetOrCreateProfileContext(Profile* profile) {
533   std::unique_ptr<ProfileContext>& context = profiles_[profile];
534   if (!context) {
535     context = std::make_unique<ProfileContext>();
536     if (profile)
537       profile->AddObserver(this);
538   }
539   return context.get();
540 }
541 
542 IncidentReportingService::ProfileContext*
GetProfileContext(Profile * profile)543 IncidentReportingService::GetProfileContext(Profile* profile) {
544   auto it = profiles_.find(profile);
545   return it != profiles_.end() ? it->second.get() : nullptr;
546 }
547 
FindEligibleProfile() const548 Profile* IncidentReportingService::FindEligibleProfile() const {
549   for (const auto& scan : profiles_) {
550     // Skip over profiles that have yet to be added to the profile manager.
551     // This will also skip over the NULL-profile context used to hold
552     // process-wide incidents.
553     if (!scan.second->added)
554       continue;
555 
556     if (IsEnabledForProfile(scan.first))
557       return scan.first;
558   }
559 
560   return nullptr;
561 }
562 
AddIncident(Profile * profile,std::unique_ptr<Incident> incident)563 void IncidentReportingService::AddIncident(Profile* profile,
564                                            std::unique_ptr<Incident> incident) {
565   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
566 
567   // Ignore incidents from off-the-record profiles.
568   if (profile && profile->IsOffTheRecord())
569     return;
570 
571   ProfileContext* context = GetOrCreateProfileContext(profile);
572   // If this is a process-wide incident, the context must not indicate that the
573   // profile (which is NULL) has been added to the profile manager.
574   DCHECK(profile || !context->added);
575 
576   LogIncidentDataType(RECEIVED, *incident);
577 
578   // Drop the incident immediately if the profile has already been added to the
579   // manager and does not have incident reporting enabled. Preference evaluation
580   // is deferred until OnProfileAdded() otherwise.
581   if (context->added && !IsEnabledForProfile(profile)) {
582     LogIncidentDataType(DROPPED, *incident);
583     return;
584   }
585 
586   // Take ownership of the incident.
587   context->incidents.push_back(std::move(incident));
588 
589   // Remember when the first incident for this report arrived.
590   if (first_incident_time_.is_null())
591     first_incident_time_ = base::Time::Now();
592   // Log the time between the previous incident and this one.
593   if (!last_incident_time_.is_null()) {
594     UMA_HISTOGRAM_TIMES("SBIRS.InterIncidentTime",
595                         base::TimeTicks::Now() - last_incident_time_);
596   }
597   last_incident_time_ = base::TimeTicks::Now();
598 
599   // Persist the incident data.
600 
601   // Start assembling a new report if this is the first incident ever or the
602   // first since the last upload.
603   BeginReportProcessing();
604 }
605 
ClearIncident(Profile * profile,std::unique_ptr<Incident> incident)606 void IncidentReportingService::ClearIncident(
607     Profile* profile,
608     std::unique_ptr<Incident> incident) {
609   ProfileContext* context = GetOrCreateProfileContext(profile);
610   context->incidents_to_clear.push_back(std::move(incident));
611   // Begin processing to handle cleared incidents following collation.
612   BeginReportProcessing();
613 }
614 
BeginReportProcessing()615 void IncidentReportingService::BeginReportProcessing() {
616   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
617 
618   // Creates a new report if needed.
619   if (!report_)
620     report_.reset(new ClientIncidentReport());
621 
622   // Ensure that collection tasks are running (calls are idempotent).
623   BeginIncidentCollation();
624   BeginEnvironmentCollection();
625   BeginDownloadCollection();
626 }
627 
BeginIncidentCollation()628 void IncidentReportingService::BeginIncidentCollation() {
629   // Restart the delay timer to send the report upon expiration.
630   collation_timeout_pending_ = true;
631   collation_timer_.Reset();
632 }
633 
WaitingToCollateIncidents()634 bool IncidentReportingService::WaitingToCollateIncidents() {
635   return collation_timeout_pending_;
636 }
637 
CancelIncidentCollection()638 void IncidentReportingService::CancelIncidentCollection() {
639   collation_timeout_pending_ = false;
640   last_incident_time_ = base::TimeTicks();
641   report_.reset();
642 }
643 
OnCollationTimeout()644 void IncidentReportingService::OnCollationTimeout() {
645   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
646 
647   // Exit early if collection was cancelled.
648   if (!collation_timeout_pending_)
649     return;
650 
651   // Wait another round if profile-bound incidents have come in from a profile
652   // that has yet to complete creation.
653   for (const auto& scan : profiles_) {
654     if (scan.first && !scan.second->added && scan.second->HasIncidents()) {
655       collation_timer_.Reset();
656       return;
657     }
658   }
659 
660   collation_timeout_pending_ = false;
661 
662   ProcessIncidentsIfCollectionComplete();
663 }
664 
BeginEnvironmentCollection()665 void IncidentReportingService::BeginEnvironmentCollection() {
666   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
667   DCHECK(report_);
668   // Nothing to do if environment collection is pending or has already
669   // completed, if there are no incidents to process, or if there is no eligible
670   // profile.
671   if (environment_collection_pending_ || report_->has_environment() ||
672       !HasIncidentsToUpload() || !FindEligibleProfile()) {
673     return;
674   }
675 
676   environment_collection_begin_ = base::TimeTicks::Now();
677   ClientIncidentReport_EnvironmentData* environment_data =
678       new ClientIncidentReport_EnvironmentData();
679   environment_collection_pending_ =
680       environment_collection_task_runner_->PostTaskAndReply(
681           FROM_HERE,
682           base::BindOnce(collect_environment_data_fn_, environment_data),
683           base::BindOnce(&IncidentReportingService::OnEnvironmentDataCollected,
684                          weak_ptr_factory_.GetWeakPtr(),
685                          base::WrapUnique(environment_data)));
686 
687   // Posting the task will fail if the runner has been shut down. This should
688   // never happen since the blocking pool is shut down after this service.
689   DCHECK(environment_collection_pending_);
690 }
691 
WaitingForEnvironmentCollection()692 bool IncidentReportingService::WaitingForEnvironmentCollection() {
693   return environment_collection_pending_;
694 }
695 
CancelEnvironmentCollection()696 void IncidentReportingService::CancelEnvironmentCollection() {
697   environment_collection_begin_ = base::TimeTicks();
698   environment_collection_pending_ = false;
699   if (report_)
700     report_->clear_environment();
701 }
702 
OnEnvironmentDataCollected(std::unique_ptr<ClientIncidentReport_EnvironmentData> environment_data)703 void IncidentReportingService::OnEnvironmentDataCollected(
704     std::unique_ptr<ClientIncidentReport_EnvironmentData> environment_data) {
705   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
706   DCHECK(environment_collection_pending_);
707   DCHECK(report_ && !report_->has_environment());
708   environment_collection_pending_ = false;
709 
710 // Process::Current().CreationTime() is missing on some platforms.
711 #if defined(OS_MAC) || defined(OS_WIN) || defined(OS_LINUX) || defined(OS_BSD) || \
712     defined(OS_CHROMEOS)
713   base::TimeDelta uptime =
714       first_incident_time_ - base::Process::Current().CreationTime();
715   environment_data->mutable_process()->set_uptime_msec(uptime.InMilliseconds());
716 #endif
717 
718   report_->set_allocated_environment(environment_data.release());
719 
720   UMA_HISTOGRAM_TIMES("SBIRS.EnvCollectionTime",
721                       base::TimeTicks::Now() - environment_collection_begin_);
722   environment_collection_begin_ = base::TimeTicks();
723 
724   ProcessIncidentsIfCollectionComplete();
725 }
726 
BeginDownloadCollection()727 void IncidentReportingService::BeginDownloadCollection() {
728   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
729   DCHECK(report_);
730   // Nothing to do if a search for the most recent download is already pending,
731   // if one has already been found, or if there are no incidents to process.
732   if (last_download_finder_ || report_->has_download() ||
733       !HasIncidentsToUpload()) {
734     return;
735   }
736 
737   last_download_begin_ = base::TimeTicks::Now();
738   last_download_finder_ = CreateDownloadFinder(
739       base::BindOnce(&IncidentReportingService::OnLastDownloadFound,
740                      weak_ptr_factory_.GetWeakPtr()));
741   // No instance is returned if there are no eligible loaded profiles. Another
742   // search will be attempted in OnProfileAdded() if another profile appears on
743   // the scene.
744   if (!last_download_finder_)
745     last_download_begin_ = base::TimeTicks();
746 }
747 
WaitingForMostRecentDownload()748 bool IncidentReportingService::WaitingForMostRecentDownload() {
749   DCHECK(report_);  // Only call this when a report is being assembled.
750   // The easy case: not waiting if a download has already been found.
751   if (report_->has_download())
752     return false;
753   // The next easy case: waiting if the finder is operating.
754   if (last_download_finder_)
755     return true;
756   // Harder case 1: not waiting if there are no incidents to upload (only
757   // incidents to clear).
758   if (!HasIncidentsToUpload())
759     return false;
760   // Harder case 2: waiting if a non-NULL profile has not yet been added.
761   for (const auto& scan : profiles_) {
762     if (scan.first && !scan.second->added)
763       return true;
764   }
765   // There is no most recent download and there's nothing more to wait for.
766   return false;
767 }
768 
CancelDownloadCollection()769 void IncidentReportingService::CancelDownloadCollection() {
770   last_download_finder_.reset();
771   last_download_begin_ = base::TimeTicks();
772   if (report_)
773     report_->clear_download();
774 }
775 
OnLastDownloadFound(std::unique_ptr<ClientIncidentReport_DownloadDetails> last_binary_download,std::unique_ptr<ClientIncidentReport_NonBinaryDownloadDetails> last_non_binary_download)776 void IncidentReportingService::OnLastDownloadFound(
777     std::unique_ptr<ClientIncidentReport_DownloadDetails> last_binary_download,
778     std::unique_ptr<ClientIncidentReport_NonBinaryDownloadDetails>
779         last_non_binary_download) {
780   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
781   DCHECK(report_);
782 
783   UMA_HISTOGRAM_TIMES("SBIRS.FindDownloadedBinaryTime",
784                       base::TimeTicks::Now() - last_download_begin_);
785   last_download_begin_ = base::TimeTicks();
786 
787   // Harvest the finder.
788   last_download_finder_.reset();
789 
790   if (last_binary_download)
791     report_->set_allocated_download(last_binary_download.release());
792 
793   if (last_non_binary_download) {
794     report_->set_allocated_non_binary_download(
795         last_non_binary_download.release());
796   }
797 
798   ProcessIncidentsIfCollectionComplete();
799 }
800 
ProcessIncidentsIfCollectionComplete()801 void IncidentReportingService::ProcessIncidentsIfCollectionComplete() {
802   DCHECK(report_);
803   // Bail out if there are still outstanding collection tasks. Completion of any
804   // of these will start another upload attempt.
805   if (WaitingForEnvironmentCollection() || WaitingToCollateIncidents() ||
806       WaitingForMostRecentDownload()) {
807     return;
808   }
809 
810   // Take ownership of the report and clear things for future reports.
811   std::unique_ptr<ClientIncidentReport> report(std::move(report_));
812   first_incident_time_ = base::Time();
813   last_incident_time_ = base::TimeTicks();
814 
815   ClientIncidentReport_EnvironmentData_Process* process =
816       report->mutable_environment()->mutable_process();
817 
818   process->set_metrics_consent(
819       ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled());
820 
821   // Associate process-wide incidents with any eligible profile. If there is no
822   // eligible profile, drop the incidents.
823   ProfileContext* null_context = GetProfileContext(nullptr);
824   if (null_context && null_context->HasIncidents()) {
825     Profile* eligible_profile = FindEligibleProfile();
826     if (eligible_profile) {
827       ProfileContext* eligible_context = GetProfileContext(eligible_profile);
828       // Move the incidents to the target context.
829       for (auto& incident : null_context->incidents) {
830         eligible_context->incidents.push_back(std::move(incident));
831       }
832       null_context->incidents.clear();
833       for (auto& incident : null_context->incidents_to_clear)
834         eligible_context->incidents_to_clear.push_back(std::move(incident));
835       null_context->incidents_to_clear.clear();
836     } else {
837       for (const auto& incident : null_context->incidents)
838         LogIncidentDataType(DROPPED, *incident);
839       null_context->incidents.clear();
840     }
841   }
842 
843   // Clear incidents data where needed.
844   for (auto& profile_and_context : profiles_) {
845     // Bypass process-wide incidents that have not yet been associated with a
846     // profile and profiles with no incidents to clear.
847     if (!profile_and_context.first ||
848         profile_and_context.second->incidents_to_clear.empty()) {
849       continue;
850     }
851     ProfileContext* context = profile_and_context.second.get();
852     StateStore::Transaction transaction(context->state_store.get());
853     for (const auto& incident : context->incidents_to_clear)
854       transaction.Clear(incident->GetType(), incident->GetKey());
855     context->incidents_to_clear.clear();
856   }
857   // Abandon report if there are no incidents to upload.
858   if (!HasIncidentsToUpload())
859     return;
860 
861   bool has_download =
862       report->has_download() || report->has_non_binary_download();
863 
864   // Collect incidents across all profiles participating in safe browsing
865   // extended reporting.
866   // Associate the profile contexts and their incident data with the upload.
867   UploadContext::PersistentIncidentStateCollection profiles_to_state;
868   for (auto& profile_and_context : profiles_) {
869     // Bypass process-wide incidents that have not yet been associated with a
870     // profile.
871     if (!profile_and_context.first)
872       continue;
873     ProfileContext* context = profile_and_context.second.get();
874     if (context->incidents.empty())
875       continue;
876     // Drop all incidents collected for the profile if it stopped participating
877     // before collection completed.
878     if (!IsEnabledForProfile(profile_and_context.first)) {
879       for (const auto& incident : context->incidents)
880         LogIncidentDataType(DROPPED, *incident);
881       context->incidents.clear();
882       continue;
883     }
884     StateStore::Transaction transaction(context->state_store.get());
885     std::vector<PersistentIncidentState> states;
886     // Prep persistent data and prune any incidents already sent.
887     for (const auto& incident : context->incidents) {
888       const PersistentIncidentState state = ComputeIncidentState(*incident);
889       if (context->state_store->HasBeenReported(state.type, state.key,
890                                                 state.digest)) {
891         LogIncidentDataType(PRUNED, *incident);
892       } else if (!has_download) {
893         LogIncidentDataType(NO_DOWNLOAD, *incident);
894         // Drop the incident and mark for future pruning since no executable
895         // download was found.
896         transaction.MarkAsReported(state.type, state.key, state.digest);
897       } else {
898         LogIncidentDataType(ACCEPTED, *incident);
899         // Ownership of the payload is passed to the report.
900         ClientIncidentReport_IncidentData* data =
901             incident->TakePayload().release();
902         DCHECK(data->has_incident_time_msec());
903         report->mutable_incident()->AddAllocated(data);
904         data = nullptr;
905         states.push_back(state);
906       }
907     }
908     context->incidents.clear();
909     profiles_to_state[context].swap(states);
910   }
911 
912   const int count = report->incident_size();
913 
914   // Abandon the request if all incidents were pruned or otherwise dropped.
915   if (!count) {
916     if (!has_download) {
917       UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult",
918                                 IncidentReportUploader::UPLOAD_NO_DOWNLOAD,
919                                 IncidentReportUploader::NUM_UPLOAD_RESULTS);
920     }
921     return;
922   }
923   // Perform final synchronous collection tasks for the report.
924   DoExtensionCollection(report->mutable_extension_data());
925 
926   std::unique_ptr<UploadContext> context(new UploadContext(std::move(report)));
927   context->profiles_to_state.swap(profiles_to_state);
928   UploadContext* temp_context = context.get();
929   uploads_.push_back(std::move(context));
930   IncidentReportingService::UploadReportIfUploadingEnabled(temp_context);
931 }
932 
CancelAllReportUploads()933 void IncidentReportingService::CancelAllReportUploads() {
934   for (size_t i = 0; i < uploads_.size(); ++i) {
935     UMA_HISTOGRAM_ENUMERATION("SBIRS.UploadResult",
936                               IncidentReportUploader::UPLOAD_CANCELLED,
937                               IncidentReportUploader::NUM_UPLOAD_RESULTS);
938   }
939   uploads_.clear();
940 }
941 
UploadReportIfUploadingEnabled(UploadContext * context)942 void IncidentReportingService::UploadReportIfUploadingEnabled(
943     UploadContext* context) {
944   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
945 
946   if (!base::FeatureList::IsEnabled(kIncidentReportingEnableUpload)) {
947     OnReportUploadResult(context, IncidentReportUploader::UPLOAD_SUPPRESSED,
948                          std::unique_ptr<ClientIncidentResponse>());
949     return;
950   }
951 
952   // Initiate the upload.
953   context->uploader = StartReportUpload(
954       base::BindOnce(&IncidentReportingService::OnReportUploadResult,
955                      weak_ptr_factory_.GetWeakPtr(), context),
956       *context->report);
957   if (!context->uploader) {
958     OnReportUploadResult(context,
959                          IncidentReportUploader::UPLOAD_INVALID_REQUEST,
960                          std::unique_ptr<ClientIncidentResponse>());
961   }
962 }
963 
HandleResponse(const UploadContext & context)964 void IncidentReportingService::HandleResponse(const UploadContext& context) {
965   // Mark each incident as reported in its corresponding profile's state store.
966   for (const auto& context_and_states : context.profiles_to_state) {
967     StateStore::Transaction transaction(
968         context_and_states.first->state_store.get());
969     for (const auto& state : context_and_states.second)
970       transaction.MarkAsReported(state.type, state.key, state.digest);
971   }
972 }
973 
OnReportUploadResult(UploadContext * context,IncidentReportUploader::Result result,std::unique_ptr<ClientIncidentResponse> response)974 void IncidentReportingService::OnReportUploadResult(
975     UploadContext* context,
976     IncidentReportUploader::Result result,
977     std::unique_ptr<ClientIncidentResponse> response) {
978   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
979 
980   UMA_HISTOGRAM_ENUMERATION(
981       "SBIRS.UploadResult", result, IncidentReportUploader::NUM_UPLOAD_RESULTS);
982 
983   // The upload is no longer outstanding, so take ownership of the context (from
984   // the collection of outstanding uploads) in this scope.
985   auto it =
986       std::find_if(uploads_.begin(), uploads_.end(),
987                    [context](const std::unique_ptr<UploadContext>& value) {
988                      return value.get() == context;
989                    });
990   DCHECK(it != uploads_.end());
991   std::unique_ptr<UploadContext> upload(std::move(*it));
992   uploads_.erase(it);
993 
994   if (result == IncidentReportUploader::UPLOAD_SUCCESS)
995     HandleResponse(*upload);
996   // else retry?
997 }
998 
OnClientDownloadRequest(download::DownloadItem * download,const ClientDownloadRequest * request)999 void IncidentReportingService::OnClientDownloadRequest(
1000     download::DownloadItem* download,
1001     const ClientDownloadRequest* request) {
1002   if (content::DownloadItemUtils::GetBrowserContext(download) &&
1003       !content::DownloadItemUtils::GetBrowserContext(download)
1004            ->IsOffTheRecord()) {
1005     download_metadata_manager_.SetRequest(download, request);
1006   }
1007 }
1008 
1009 }  // namespace safe_browsing
1010