Chromium Code Reviews| 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; |
| +} |