1 // Copyright 2015 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/installer/util/beacons.h"
6 
7 #include <stdint.h>
8 
9 #include "base/notreached.h"
10 #include "base/win/registry.h"
11 #include "base/win/win_util.h"
12 #include "chrome/install_static/install_details.h"
13 #include "chrome/install_static/install_util.h"
14 
UpdateDefaultBrowserBeaconForPath(const base::FilePath & chrome_exe)15 void UpdateDefaultBrowserBeaconForPath(const base::FilePath& chrome_exe) {
16   // Getting Chrome's default state causes the beacon to be updated via a call
17   // to UpdateDefaultBrowserBeaconWithState below.
18   ignore_result(ShellUtil::GetChromeDefaultStateFromPath(chrome_exe));
19 }
20 
UpdateDefaultBrowserBeaconWithState(ShellUtil::DefaultState default_state)21 void UpdateDefaultBrowserBeaconWithState(
22     ShellUtil::DefaultState default_state) {
23   switch (default_state) {
24     case ShellUtil::UNKNOWN_DEFAULT:
25       break;
26     case ShellUtil::NOT_DEFAULT:
27       installer_util::MakeFirstNotDefaultBeacon()->Update();
28       break;
29     case ShellUtil::IS_DEFAULT:
30     case ShellUtil::OTHER_MODE_IS_DEFAULT:
31       installer_util::MakeLastWasDefaultBeacon()->Update();
32       installer_util::MakeFirstNotDefaultBeacon()->Remove();
33       break;
34   }
35 }
36 
UpdateOsUpgradeBeacon()37 void UpdateOsUpgradeBeacon() {
38   installer_util::MakeLastOsUpgradeBeacon()->Update();
39 }
40 
41 namespace installer_util {
42 
MakeLastOsUpgradeBeacon()43 std::unique_ptr<Beacon> MakeLastOsUpgradeBeacon() {
44   return std::make_unique<Beacon>(L"LastOsUpgrade", Beacon::BeaconType::LAST,
45                                   Beacon::BeaconScope::PER_INSTALL);
46 }
47 
MakeLastWasDefaultBeacon()48 std::unique_ptr<Beacon> MakeLastWasDefaultBeacon() {
49   return std::make_unique<Beacon>(L"LastWasDefault", Beacon::BeaconType::LAST,
50                                   Beacon::BeaconScope::PER_USER);
51 }
52 
MakeFirstNotDefaultBeacon()53 std::unique_ptr<Beacon> MakeFirstNotDefaultBeacon() {
54   return std::make_unique<Beacon>(L"FirstNotDefault", Beacon::BeaconType::FIRST,
55                                   Beacon::BeaconScope::PER_USER);
56 }
57 
58 // Beacon ----------------------------------------------------------------------
59 
Beacon(base::StringPiece16 name,BeaconType type,BeaconScope scope)60 Beacon::Beacon(base::StringPiece16 name, BeaconType type, BeaconScope scope)
61     : type_(type),
62       root_(install_static::IsSystemInstall() ? HKEY_LOCAL_MACHINE
63                                               : HKEY_CURRENT_USER),
64       scope_(scope) {
65   Initialize(name);
66 }
67 
~Beacon()68 Beacon::~Beacon() {}
69 
Update()70 void Beacon::Update() {
71   const REGSAM kAccess = KEY_WOW64_32KEY | KEY_QUERY_VALUE | KEY_SET_VALUE;
72   base::win::RegKey key;
73 
74   // Nothing to update if the key couldn't be created. This should only be the
75   // case for a developer build.
76   if (key.Create(root_, key_path_.c_str(), kAccess) != ERROR_SUCCESS)
77     return;
78 
79   // Nothing to do if this beacon is tracking the first occurrence of an event
80   // that has already been recorded.
81   if (type_ == BeaconType::FIRST && key.HasValue(value_name_.c_str()))
82     return;
83 
84   int64_t now(base::Time::Now().ToInternalValue());
85   key.WriteValue(value_name_.c_str(), &now, sizeof(now), REG_QWORD);
86 }
87 
Remove()88 void Beacon::Remove() {
89   const REGSAM kAccess = KEY_WOW64_32KEY | KEY_SET_VALUE;
90   base::win::RegKey key;
91 
92   if (key.Open(root_, key_path_.c_str(), kAccess) == ERROR_SUCCESS)
93     key.DeleteValue(value_name_.c_str());
94 }
95 
Get()96 base::Time Beacon::Get() {
97   const REGSAM kAccess = KEY_WOW64_32KEY | KEY_QUERY_VALUE;
98   base::win::RegKey key;
99   int64_t now;
100 
101   if (key.Open(root_, key_path_.c_str(), kAccess) != ERROR_SUCCESS ||
102       key.ReadInt64(value_name_.c_str(), &now) != ERROR_SUCCESS) {
103     return base::Time();
104   }
105 
106   return base::Time::FromInternalValue(now);
107 }
108 
Initialize(base::StringPiece16 name)109 void Beacon::Initialize(base::StringPiece16 name) {
110   const install_static::InstallDetails& install_details =
111       install_static::InstallDetails::Get();
112 
113   // When possible, beacons are located in the app's ClientState key. Per-user
114   // beacons for a per-machine install are located in a beacon-specific sub-key
115   // of the app's ClientStateMedium key.
116   if (scope_ == BeaconScope::PER_INSTALL ||
117       !install_static::IsSystemInstall()) {
118     key_path_ = install_details.GetClientStateKeyPath();
119     value_name_.assign(name.data(), name.size());
120   } else {
121     key_path_ = install_details.GetClientStateMediumKeyPath();
122     key_path_.push_back(L'\\');
123     key_path_.append(name.data(), name.size());
124     // This should never fail. If it does, the beacon will be written in the
125     // key's default value, which is okay since the majority case is likely a
126     // machine with a single user.
127     if (!base::win::GetUserSidString(&value_name_))
128       NOTREACHED();
129   }
130 }
131 
132 }  // namespace installer_util
133