summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorblundell@chromium.org <blundell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-22 13:49:39 +0000
committerblundell@chromium.org <blundell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-22 13:49:39 +0000
commit66d176ad38d72eabc969893b2b09ad6759109836 (patch)
treeb49f61dcb41744b0fab09f0a7893dd84e940d1f8 /components
parent5a23d6986317ab9018521c3eaa87957a214d189d (diff)
downloadchromium_src-66d176ad38d72eabc969893b2b09ad6759109836.zip
chromium_src-66d176ad38d72eabc969893b2b09ad6759109836.tar.gz
chromium_src-66d176ad38d72eabc969893b2b09ad6759109836.tar.bz2
Move ClonedInstallDetector and MachineIdProvider into the metrics component
cloned_install_detector_unittest is left in //chrome at the current time as it still has //chrome-level dependencies. BUG=374212 R=isherman@chromium.org TBR=thakis Review URL: https://codereview.chromium.org/290033003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272172 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/components_tests.gyp1
-rw-r--r--components/metrics.gypi10
-rw-r--r--components/metrics/cloned_install_detector.cc98
-rw-r--r--components/metrics/cloned_install_detector.h59
-rw-r--r--components/metrics/machine_id_provider.h46
-rw-r--r--components/metrics/machine_id_provider_stub.cc24
-rw-r--r--components/metrics/machine_id_provider_win.cc117
-rw-r--r--components/metrics/machine_id_provider_win_unittest.cc23
-rw-r--r--components/metrics/metrics_pref_names.cc8
-rw-r--r--components/metrics/metrics_pref_names.h2
10 files changed, 388 insertions, 0 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 64cf12b..c6928eb 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -104,6 +104,7 @@
'keyed_service/content/browser_context_dependency_manager_unittest.cc',
'keyed_service/core/dependency_graph_unittest.cc',
'language_usage_metrics/language_usage_metrics_unittest.cc',
+ 'metrics/machine_id_provider_win_unittest.cc',
'metrics/metrics_hashes_unittest.cc',
'metrics/metrics_log_base_unittest.cc',
'metrics/metrics_log_manager_unittest.cc',
diff --git a/components/metrics.gypi b/components/metrics.gypi
index 850ecd09..fd79d50 100644
--- a/components/metrics.gypi
+++ b/components/metrics.gypi
@@ -16,6 +16,11 @@
],
'sources': [
'metrics/metrics_provider.h',
+ 'metrics/cloned_install_detector.cc',
+ 'metrics/cloned_install_detector.h',
+ 'metrics/machine_id_provider.h',
+ 'metrics/machine_id_provider_stub.cc',
+ 'metrics/machine_id_provider_win.cc',
'metrics/metrics_hashes.cc',
'metrics/metrics_hashes.h',
'metrics/metrics_log_base.cc',
@@ -38,6 +43,11 @@
'metrics_chromeos',
],
}],
+ ['OS=="win"', {
+ 'sources!': [
+ 'metrics/machine_id_provider_stub.cc',
+ ],
+ }],
],
},
{
diff --git a/components/metrics/cloned_install_detector.cc b/components/metrics/cloned_install_detector.cc
new file mode 100644
index 0000000..b93e6e6
--- /dev/null
+++ b/components/metrics/cloned_install_detector.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 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 "components/metrics/cloned_install_detector.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
+#include "components/metrics/cloned_install_detector.h"
+#include "components/metrics/machine_id_provider.h"
+#include "components/metrics/metrics_hashes.h"
+#include "components/metrics/metrics_pref_names.h"
+
+namespace metrics {
+
+namespace {
+
+uint32 HashRawId(const std::string& value) {
+ uint64 hash = metrics::HashMetricName(value);
+
+ // Only use 24 bits from the 64-bit hash.
+ return hash & ((1 << 24) - 1);
+}
+
+// State of the generated machine id in relation to the previously stored value.
+// Note: UMA histogram enum - don't re-order or remove entries
+enum MachineIdState {
+ ID_GENERATION_FAILED,
+ ID_NO_STORED_VALUE,
+ ID_CHANGED,
+ ID_UNCHANGED,
+ ID_ENUM_SIZE
+};
+
+// Logs the state of generating a machine id and comparing it to a stored value.
+void LogMachineIdState(MachineIdState state) {
+ UMA_HISTOGRAM_ENUMERATION("UMA.MachineIdState", state, ID_ENUM_SIZE);
+}
+
+} // namespace
+
+ClonedInstallDetector::ClonedInstallDetector(MachineIdProvider* raw_id_provider)
+ : raw_id_provider_(raw_id_provider), weak_ptr_factory_(this) {
+}
+
+ClonedInstallDetector::~ClonedInstallDetector() {
+}
+
+void ClonedInstallDetector::CheckForClonedInstall(
+ PrefService* local_state,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ base::PostTaskAndReplyWithResult(
+ task_runner.get(),
+ FROM_HERE,
+ base::Bind(&metrics::MachineIdProvider::GetMachineId, raw_id_provider_),
+ base::Bind(&metrics::ClonedInstallDetector::SaveMachineId,
+ weak_ptr_factory_.GetWeakPtr(),
+ local_state));
+}
+
+void ClonedInstallDetector::SaveMachineId(PrefService* local_state,
+ std::string raw_id) {
+ if (raw_id.empty()) {
+ LogMachineIdState(ID_GENERATION_FAILED);
+ local_state->ClearPref(prefs::kMetricsMachineId);
+ return;
+ }
+
+ int hashed_id = HashRawId(raw_id);
+
+ MachineIdState id_state = ID_NO_STORED_VALUE;
+ if (local_state->HasPrefPath(prefs::kMetricsMachineId)) {
+ if (local_state->GetInteger(prefs::kMetricsMachineId) != hashed_id) {
+ id_state = ID_CHANGED;
+ // TODO(jwd): Use a callback to set the reset pref. That way
+ // ClonedInstallDetector doesn't need to know about this pref.
+ local_state->SetBoolean(prefs::kMetricsResetIds, true);
+ } else {
+ id_state = ID_UNCHANGED;
+ }
+ }
+
+ LogMachineIdState(id_state);
+
+ local_state->SetInteger(prefs::kMetricsMachineId, hashed_id);
+}
+
+// static
+void ClonedInstallDetector::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterIntegerPref(prefs::kMetricsMachineId, 0);
+}
+
+} // namespace metrics
diff --git a/components/metrics/cloned_install_detector.h b/components/metrics/cloned_install_detector.h
new file mode 100644
index 0000000..065cb49
--- /dev/null
+++ b/components/metrics/cloned_install_detector.h
@@ -0,0 +1,59 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_METRICS_CLONED_INSTALL_DETECTOR_H_
+#define COMPONENTS_METRICS_CLONED_INSTALL_DETECTOR_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace metrics {
+
+class MachineIdProvider;
+
+// A class for detecting if an install is cloned. It does this by detecting
+// when the hardware running Chrome changes.
+class ClonedInstallDetector {
+ public:
+ explicit ClonedInstallDetector(MachineIdProvider* raw_id_provider);
+ virtual ~ClonedInstallDetector();
+
+ // Posts a task to |task_runner| to generate a machine ID and store it to a
+ // local state pref. If the newly generated ID is different than the
+ // previously stored one, then the install is considered cloned. The ID is a
+ // 24-bit value based off of machine characteristics. This value should never
+ // be sent over the network.
+ // TODO(jwd): Implement change detection.
+ void CheckForClonedInstall(
+ PrefService* local_state,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ClonedInstallDetectorTest, SaveId);
+ FRIEND_TEST_ALL_PREFIXES(ClonedInstallDetectorTest, DetectClone);
+
+ // Converts raw_id into a 24-bit hash and stores the hash in |local_state|.
+ // |raw_id| is not a const ref because it's passed from a cross-thread post
+ // task.
+ void SaveMachineId(PrefService* local_state, std::string raw_id);
+
+ scoped_refptr<MachineIdProvider> raw_id_provider_;
+ base::WeakPtrFactory<ClonedInstallDetector> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClonedInstallDetector);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CLONED_INSTALL_DETECTOR_H_
diff --git a/components/metrics/machine_id_provider.h b/components/metrics/machine_id_provider.h
new file mode 100644
index 0000000..d7fcc44
--- /dev/null
+++ b/components/metrics/machine_id_provider.h
@@ -0,0 +1,46 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_METRICS_MACHINE_ID_PROVIDER_H_
+#define COMPONENTS_METRICS_MACHINE_ID_PROVIDER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace metrics {
+
+// Provides machine characteristics used as a machine id. The implementation is
+// platform specific with a default implementation that gives an empty id. The
+// class is ref-counted thread safe so it can be used to post to the FILE thread
+// and communicate back to the UI thread.
+// This raw machine id should not be stored or transmitted over the network.
+// TODO(jwd): Simplify implementation to get rid of the need for
+// RefCountedThreadSafe (crbug.com/354882).
+class MachineIdProvider : public base::RefCountedThreadSafe<MachineIdProvider> {
+ public:
+ // Get a string containing machine characteristics, to be used as a machine
+ // id. The implementation is platform specific, with a default implementation
+ // returning an empty string.
+ // The return value should not be stored to disk or transmitted.
+ std::string GetMachineId();
+
+ // Returns a pointer to a new MachineIdProvider or NULL if there is no
+ // provider implemented on a given platform. This is done to avoid posting a
+ // task to the FILE thread on platforms with no implementation.
+ static MachineIdProvider* CreateInstance();
+
+ private:
+ friend class base::RefCountedThreadSafe<MachineIdProvider>;
+
+ MachineIdProvider();
+ virtual ~MachineIdProvider();
+
+ DISALLOW_COPY_AND_ASSIGN(MachineIdProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_MACHINE_ID_PROVIDER_H_
diff --git a/components/metrics/machine_id_provider_stub.cc b/components/metrics/machine_id_provider_stub.cc
new file mode 100644
index 0000000..626f2b7
--- /dev/null
+++ b/components/metrics/machine_id_provider_stub.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 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 "components/metrics/machine_id_provider.h"
+
+namespace metrics {
+
+MachineIdProvider::MachineIdProvider() {
+}
+
+MachineIdProvider::~MachineIdProvider() {
+}
+
+// static
+MachineIdProvider* MachineIdProvider::CreateInstance() {
+ return NULL;
+}
+
+std::string MachineIdProvider::GetMachineId() {
+ return std::string();
+}
+
+} // namespace metrics
diff --git a/components/metrics/machine_id_provider_win.cc b/components/metrics/machine_id_provider_win.cc
new file mode 100644
index 0000000..777151a
--- /dev/null
+++ b/components/metrics/machine_id_provider_win.cc
@@ -0,0 +1,117 @@
+// Copyright 2014 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 "components/metrics/machine_id_provider.h"
+
+#include <windows.h>
+#include <winioctl.h>
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_handle.h"
+
+namespace metrics {
+
+MachineIdProvider::MachineIdProvider() {
+}
+
+MachineIdProvider::~MachineIdProvider() {
+}
+
+// On windows, the machine id is based on the serial number of the drive Chrome
+// is running from.
+std::string MachineIdProvider::GetMachineId() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ // Use the program's path to get the drive used for the machine id. This means
+ // that whenever the underlying drive changes, it's considered a new machine.
+ // This is fine as we do not support migrating Chrome installs to new drives.
+ base::FilePath executable_path;
+
+ if (!PathService::Get(base::FILE_EXE, &executable_path)) {
+ NOTREACHED();
+ return std::string();
+ }
+
+ std::vector<base::FilePath::StringType> path_components;
+ executable_path.GetComponents(&path_components);
+ if (path_components.empty()) {
+ NOTREACHED();
+ return std::string();
+ }
+ base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0];
+
+ base::win::ScopedHandle drive_handle(
+ CreateFile(drive_name.c_str(),
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL));
+
+ STORAGE_PROPERTY_QUERY query = {};
+ query.PropertyId = StorageDeviceProperty;
+ query.QueryType = PropertyStandardQuery;
+
+ // Perform an initial query to get the number of bytes being returned.
+ DWORD bytes_returned;
+ STORAGE_DESCRIPTOR_HEADER header = {};
+ BOOL status = DeviceIoControl(drive_handle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &query,
+ sizeof(STORAGE_PROPERTY_QUERY),
+ &header,
+ sizeof(STORAGE_DESCRIPTOR_HEADER),
+ &bytes_returned,
+ NULL);
+
+ if (!status)
+ return std::string();
+
+ // Query for the actual serial number.
+ std::vector<int8> output_buf(header.Size);
+ status = DeviceIoControl(drive_handle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &query,
+ sizeof(STORAGE_PROPERTY_QUERY),
+ &output_buf[0],
+ output_buf.size(),
+ &bytes_returned,
+ NULL);
+
+ if (!status)
+ return std::string();
+
+ const STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
+ reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&output_buf[0]);
+
+ // The serial number is stored in the |output_buf| as a null-terminated
+ // string starting at the specified offset.
+ const DWORD offset = device_descriptor->SerialNumberOffset;
+ if (offset >= output_buf.size())
+ return std::string();
+
+ // Make sure that the null-terminator exists.
+ const std::vector<int8>::iterator serial_number_begin =
+ output_buf.begin() + offset;
+ const std::vector<int8>::iterator null_location =
+ std::find(serial_number_begin, output_buf.end(), '\0');
+ if (null_location == output_buf.end())
+ return std::string();
+
+ const char* serial_number =
+ reinterpret_cast<const char*>(&output_buf[offset]);
+
+ return std::string(serial_number);
+}
+
+// static
+MachineIdProvider* MachineIdProvider::CreateInstance() {
+ return new MachineIdProvider();
+}
+
+} // namespace metrics
diff --git a/components/metrics/machine_id_provider_win_unittest.cc b/components/metrics/machine_id_provider_win_unittest.cc
new file mode 100644
index 0000000..44917d0
--- /dev/null
+++ b/components/metrics/machine_id_provider_win_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 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 "components/metrics/machine_id_provider.h"
+
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+TEST(MachineIdProviderTest, GetId) {
+ scoped_refptr<MachineIdProvider> provider(
+ MachineIdProvider::CreateInstance());
+ std::string id1 = provider->GetMachineId();
+
+ EXPECT_NE(std::string(), id1);
+
+ std::string id2 = provider->GetMachineId();
+ EXPECT_EQ(id1, id2);
+}
+
+} // namespace metrics
diff --git a/components/metrics/metrics_pref_names.cc b/components/metrics/metrics_pref_names.cc
index 92a1890..e0b358a1 100644
--- a/components/metrics/metrics_pref_names.cc
+++ b/components/metrics/metrics_pref_names.cc
@@ -13,6 +13,10 @@ namespace prefs {
const char kMetricsInitialLogs[] =
"user_experience_metrics.initial_logs_as_protobufs";
+// A machine ID used to detect when underlying hardware changes. It is only
+// stored locally and never transmitted in metrics reports.
+const char kMetricsMachineId[] = "user_experience_metrics.machine_id";
+
// Array of strings that are each UMA logs that were not sent because the
// browser terminated before these accumulated metrics could be sent. These
// logs typically include histograms and memory reports, as well as ongoing
@@ -20,5 +24,9 @@ const char kMetricsInitialLogs[] =
const char kMetricsOngoingLogs[] =
"user_experience_metrics.ongoing_logs_as_protobufs";
+// Boolean that indicates a cloned install has been detected and the metrics
+// client id and low entropy source should be reset.
+const char kMetricsResetIds[] = "user_experience_metrics.reset_metrics_ids";
+
} // namespace prefs
} // namespace metrics
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h
index 750d58d..4c799c7 100644
--- a/components/metrics/metrics_pref_names.h
+++ b/components/metrics/metrics_pref_names.h
@@ -11,7 +11,9 @@ namespace prefs {
// Alphabetical list of preference names specific to the metrics
// component. Keep alphabetized, and document each in the .cc file.
extern const char kMetricsInitialLogs[];
+extern const char kMetricsMachineId[];
extern const char kMetricsOngoingLogs[];
+extern const char kMetricsResetIds[];
} // namespace prefs
} // namespace metrics