Index: chrome/browser/metrics/chrome_setup_metrics_provider.cc |
diff --git a/chrome/browser/metrics/chrome_setup_metrics_provider.cc b/chrome/browser/metrics/chrome_setup_metrics_provider.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e68cd43f09f5e460c4f64ae41ce6c950818333ce |
--- /dev/null |
+++ b/chrome/browser/metrics/chrome_setup_metrics_provider.cc |
@@ -0,0 +1,148 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/metrics/chrome_setup_metrics_provider.h" |
+ |
+#include <vector> |
+ |
+#include "base/command_line.h" |
+#include "base/files/file.h" |
+#include "base/files/file_util.h" |
+#include "base/files/memory_mapped_file.h" |
+#include "base/logging.h" |
+#include "base/metrics/histogram_base.h" |
+#include "base/metrics/persistent_memory_allocator.h" |
+#include "base/prefs/pref_service.h" |
+#include "base/threading/worker_pool.h" |
+#include "base/time/time.h" |
+#include "chrome/installer/util/google_update_constants.h" |
+#include "components/metrics/metrics_pref_names.h" |
+#include "components/metrics/metrics_service.h" |
+ |
+ |
+ChromeSetupMetricsProvider::ChromeSetupMetricsProvider( |
+ metrics::MetricsService* metrics_service, |
+ PrefService* local_state) |
+ : metrics_found_(0), |
+ metrics_service_(metrics_service), |
+ pref_service_(local_state), |
+ program_directory_(base::CommandLine::ForCurrentProcess()->GetProgram() |
+ .DirName()) { |
+ // Don't do any further actions if metrics_service is not valid (for testing). |
+ if (!metrics_service_) |
+ return; |
+ |
+ // Start a background check for pending setup metrics so it can be uploaded |
+ // during the initial report. |
+ bool posted = base::WorkerPool::PostTask( |
+ FROM_HERE, |
+ base::Bind(&ChromeSetupMetricsProvider::CheckForSetupMetrics, |
Alexei Svitkine (slow)
2015/12/21 16:54:53
In Chromium code, it's best practice to not have t
bcwhite
2015/12/22 12:51:30
Okay. I'm rewriting this to support multiple file
|
+ base::Unretained(this)), |
+ false); |
+ DCHECK(posted); |
+} |
+ |
+ChromeSetupMetricsProvider::~ChromeSetupMetricsProvider() { |
+ // Destruction of this object can lead to failures because of a task |
+ // posted on the Worker Pool or because the owned Memory Allocator has |
+ // been passed to the Metrics Service. Both cases can only occur if |
+ // a Metrics Service has been provided (i.e. not during testing). |
+ if (metrics_service_) { |
+ NOTREACHED(); |
+ // Removing the allocator may not be sufficient to avoid a crash (some |
+ // Histogram could still be pointing to the memory) but it's the best |
+ // that can be done. |
+ if (metrics_allocator_) |
+ metrics_service_->RemovePersistentMemorySegment(metrics_allocator_.get()); |
+ } |
+} |
+ |
+void ChromeSetupMetricsProvider::OnDidCreateMetricsLog() { |
+ if (metrics_allocator_) { |
+ // If an allocator has been created then the previous log collected all |
+ // the metrics. The allocator can be released and the preferences updated |
+ // to make sure it isn't reported again. |
+ pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeen, |
+ base::Time::Now().ToInternalValue()); |
+ if (metrics_service_) |
+ metrics_service_->RemovePersistentMemorySegment(metrics_allocator_.get()); |
Alexei Svitkine (slow)
2015/12/21 16:54:53
Can this functionality be done by a different help
bcwhite
2015/12/22 12:51:30
Not really. MetricsService is what owns the HSM a
|
+ metrics_allocator_.reset(); |
+ metrics_found_.store(false); |
+ return; |
+ } |
+ |
+ if (metrics_found_.load(std::memory_order_acquire)) { // ACQ metrics_file |
+ // A new file of setup metrics has been found. Attach to it and add it to |
+ // the list of persistent allocators that need to have metrics reported. |
+ DCHECK(metrics_file_); |
+ if (base::FilePersistentMemoryAllocator::IsFileAcceptable(*metrics_file_)) { |
+ metrics_allocator_.reset(new base::FilePersistentMemoryAllocator( |
+ metrics_file_.release(), 0, std::string())); |
+ if (!metrics_allocator_->IsCorrupt()) { |
+ if (metrics_service_) { |
+ metrics_service_->AddPersistentMemorySegment( |
+ metrics_allocator_.get()); |
+ } |
+ return; |
+ } |
+ } |
+ // Something is fundamentally wrong with the file. Ignore it. |
+ LOG(ERROR) << "Setup metrics file \"" |
+ << GetSetupMetricsFile().AsUTF8Unsafe() |
+ << "\" is not valid -- ignored."; |
+ metrics_allocator_.reset(); |
+ pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeen, |
+ base::Time::Now().ToInternalValue()); |
+ return; |
+ } |
+ |
+ // Don't do any further actions if metrics_service is not valid (for testing). |
+ if (!metrics_service_) |
+ return; |
+ |
+ // Nothing else is going on so schedule a check to see if there are new |
+ // setup metrics to load. If so, they will be reported during the next |
+ // collection run after this one. The check is run off of the worker- |
+ // pool so as to not cause delays on the main UI thread (which is currently |
+ // where metric collection is done). |
+ bool posted = base::WorkerPool::PostTask( |
+ FROM_HERE, |
+ base::Bind(&ChromeSetupMetricsProvider::CheckForSetupMetrics, |
+ base::Unretained(this)), |
+ false); |
+ DCHECK(posted); |
+} |
+ |
+base::FilePath ChromeSetupMetricsProvider::GetSetupMetricsFile() { |
+ return program_directory_.AppendASCII( |
+ google_update::kSetupHistogramAllocatorName); |
+} |
+ |
+void ChromeSetupMetricsProvider::CheckForSetupMetrics() { |
+ DCHECK(!metrics_found_.load()); |
+ DCHECK(!metrics_file_); |
+ |
+ base::File::Info info; |
+ if (!base::GetFileInfo(GetSetupMetricsFile(), &info) || |
+ info.is_directory || info.size == 0) { |
+ return; |
+ } |
+ |
+ const base::Time last_seen = base::Time::FromInternalValue( |
+ pref_service_->GetInt64(metrics::prefs::kSetupMetricsLastSeen)); |
+ if (last_seen >= info.last_modified) |
+ return; |
+ |
+ // A new file of setup metrics has been found. Map it into memory. |
+ metrics_file_.reset(new base::MemoryMappedFile()); |
+ metrics_file_->Initialize(GetSetupMetricsFile()); |
+ |
+ // Tell main thread that metrics have been found. |
+ metrics_found_.store(true, std::memory_order_release); // REL metrics_file |
+} |
+ |
+void ChromeSetupMetricsProvider::SetProgramDirectory( |
+ const base::FilePath& dir) { |
+ program_directory_ = dir; |
+} |