1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file.
4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/metrics/cloned_install_detector.h"
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/bind.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/location.h"
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/metrics/histogram.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/prefs/pref_registry_simple.h"
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/prefs/pref_service.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/single_thread_task_runner.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/task_runner_util.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/metrics/cloned_install_detector.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/metrics/machine_id_provider.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/metrics/metrics_hashes.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/metrics/metrics_pref_names.h"
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace metrics {
20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace {
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochuint32 HashRawId(const std::string& value) {
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  uint64 hash = metrics::HashMetricName(value);
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Only use 24 bits from the 64-bit hash.
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return hash & ((1 << 24) - 1);
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// State of the generated machine id in relation to the previously stored value.
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Note: UMA histogram enum - don't re-order or remove entries
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochenum MachineIdState {
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ID_GENERATION_FAILED,
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ID_NO_STORED_VALUE,
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ID_CHANGED,
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ID_UNCHANGED,
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ID_ENUM_SIZE
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Logs the state of generating a machine id and comparing it to a stored value.
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogMachineIdState(MachineIdState state) {
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_ENUMERATION("UMA.MachineIdState", state, ID_ENUM_SIZE);
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
47effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochClonedInstallDetector::ClonedInstallDetector(MachineIdProvider* raw_id_provider)
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : raw_id_provider_(raw_id_provider), weak_ptr_factory_(this) {
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClonedInstallDetector::~ClonedInstallDetector() {
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClonedInstallDetector::CheckForClonedInstall(
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PrefService* local_state,
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      task_runner.get(),
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&metrics::MachineIdProvider::GetMachineId, raw_id_provider_),
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&metrics::ClonedInstallDetector::SaveMachineId,
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 weak_ptr_factory_.GetWeakPtr(),
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 local_state));
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClonedInstallDetector::SaveMachineId(PrefService* local_state,
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                          std::string raw_id) {
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (raw_id.empty()) {
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LogMachineIdState(ID_GENERATION_FAILED);
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    local_state->ClearPref(prefs::kMetricsMachineId);
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  int hashed_id = HashRawId(raw_id);
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  MachineIdState id_state = ID_NO_STORED_VALUE;
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (local_state->HasPrefPath(prefs::kMetricsMachineId)) {
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (local_state->GetInteger(prefs::kMetricsMachineId) != hashed_id) {
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      id_state = ID_CHANGED;
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // TODO(jwd): Use a callback to set the reset pref. That way
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // ClonedInstallDetector doesn't need to know about this pref.
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      local_state->SetBoolean(prefs::kMetricsResetIds, true);
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    } else {
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      id_state = ID_UNCHANGED;
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LogMachineIdState(id_state);
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  local_state->SetInteger(prefs::kMetricsMachineId, hashed_id);
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ClonedInstallDetector::RegisterPrefs(PrefRegistrySimple* registry) {
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  registry->RegisterIntegerPref(prefs::kMetricsMachineId, 0);
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace metrics
99