Chromium Code Reviews| Index: chrome/installer/util/beacons.cc |
| diff --git a/chrome/installer/util/beacons.cc b/chrome/installer/util/beacons.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..00c12c93428d638d30ccac0a48eff995b3c32985 |
| --- /dev/null |
| +++ b/chrome/installer/util/beacons.cc |
| @@ -0,0 +1,153 @@ |
| +// 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/installer/util/beacons.h" |
| + |
| +#include "base/win/registry.h" |
| +#include "base/win/win_util.h" |
| +#include "chrome/installer/util/app_registration_data.h" |
| +#include "chrome/installer/util/browser_distribution.h" |
| +#include "chrome/installer/util/install_util.h" |
| +#include "chrome/installer/util/shell_util.h" |
| + |
| +void UpdateDefaultBrowserBeaconForPath(const base::FilePath& chrome_exe) { |
| + ignore_result(ShellUtil::GetChromeDefaultStateFromPath(chrome_exe)); |
|
gab
2015/05/26 18:54:34
Not done reading this CL but I assume this means t
grt (UTC plus 2)
2015/05/26 20:54:01
Yes. The doc comment explains that it makes a chec
gab
2015/05/29 13:37:36
How about s/GetChromeDefaultStateFromPath/GetChrom
|
| +} |
| + |
| +void UpdateDefaultBrowserBeacon(const base::FilePath& chrome_exe, |
| + BrowserDistribution* distribution, |
| + ShellUtil::DefaultState default_state) { |
| + const bool system_install = !InstallUtil::IsPerUserInstall(chrome_exe); |
| + const AppRegistrationData& registration_data = |
| + distribution->GetAppRegistrationData(); |
| + switch (default_state) { |
| + case ShellUtil::NOT_DEFAULT: |
| + Beacon::FirstNotDefault(system_install, registration_data)->Update(); |
| + break; |
| + case ShellUtil::IS_DEFAULT: |
| + Beacon::LastWasDefault(system_install, registration_data)->Update(); |
| + Beacon::FirstNotDefault(system_install, registration_data)->Remove(); |
| + break; |
| + case ShellUtil::UNKNOWN_DEFAULT: |
| + break; |
| + } |
| +} |
| + |
| +void UpdateOsUpgradeBeacon(bool system_install, |
| + BrowserDistribution* distribution) { |
| + Beacon::LastOsUpgrade(system_install, distribution->GetAppRegistrationData()) |
| + ->Update(); |
| +} |
| + |
| +// Beacon ---------------------------------------------------------------------- |
| + |
| +Beacon::~Beacon() { |
| +} |
| + |
| +// static |
| +scoped_ptr<Beacon> Beacon::LastOsUpgrade( |
| + bool system_install, |
| + const AppRegistrationData& registration_data) { |
| + return make_scoped_ptr(new Beacon(L"LastOsUpgrade", BeaconType::LAST, |
| + BeaconScope::PER_INSTALL, system_install, |
| + registration_data)); |
| +} |
| + |
| +// static |
| +scoped_ptr<Beacon> Beacon::LastWasDefault( |
| + bool system_install, |
| + const AppRegistrationData& registration_data) { |
| + return make_scoped_ptr(new Beacon(L"LastWasDefault", BeaconType::LAST, |
| + BeaconScope::PER_USER, system_install, |
| + registration_data)); |
| +} |
| + |
| +// static |
| +scoped_ptr<Beacon> Beacon::FirstNotDefault( |
| + bool system_install, |
| + const AppRegistrationData& registration_data) { |
| + return make_scoped_ptr(new Beacon(L"FirstNotDefault", BeaconType::FIRST, |
| + BeaconScope::PER_USER, system_install, |
| + registration_data)); |
| +} |
| + |
| +void Beacon::Update() { |
| + const REGSAM kAccess = KEY_WOW64_32KEY | KEY_QUERY_VALUE | KEY_SET_VALUE; |
|
gab
2015/05/26 18:54:34
Haven't seen much installer code since you and Wil
grt (UTC plus 2)
2015/05/26 20:54:01
Yes. This is where Google Update keeps its state r
|
| + base::win::RegKey key(root_, key_path_.c_str(), kAccess); |
| + |
| + // Nothing to update if the key couldn't be created. This should only be the |
| + // case for a developer build. |
| + if (!key.Valid()) |
| + return; |
| + |
| + // Nothing to do if this beacon is tracking the first occurrence of an event |
| + // that has already been recorded. |
| + if (type_ == BeaconType::FIRST && key.HasValue(value_name_.c_str())) |
| + return; |
| + |
| + FILETIME now(base::Time::Now().ToFileTime()); |
|
gab
2015/05/26 18:54:34
Do we really need that precise of a timestamp? Fee
grt (UTC plus 2)
2015/05/26 20:54:01
FILETIME is a simple, well-documented platform typ
gab
2015/05/29 13:37:36
My argument against it is you need multiple lines
grt (UTC plus 2)
2015/05/29 15:31:10
Changed to storing using base::Time's internal val
|
| + ULARGE_INTEGER value; |
| + value.u.LowPart = now.dwLowDateTime; |
| + value.u.HighPart = now.dwHighDateTime; |
| + key.WriteValue(value_name_.c_str(), &value.QuadPart, sizeof(value.QuadPart), |
| + REG_QWORD); |
| +} |
| + |
| +void Beacon::Remove() { |
| + const REGSAM kAccess = KEY_WOW64_32KEY | KEY_SET_VALUE; |
| + base::win::RegKey key; |
| + |
| + if (key.Open(root_, key_path_.c_str(), kAccess) == ERROR_SUCCESS) |
|
gab
2015/05/26 18:54:34
Feels weird to use key.Open() here and the RegKey(
grt (UTC plus 2)
2015/05/26 20:54:01
Done.
|
| + key.DeleteValue(value_name_.c_str()); |
| +} |
| + |
| +base::Time Beacon::Get() { |
| + const REGSAM kAccess = KEY_WOW64_32KEY | KEY_QUERY_VALUE; |
| + base::win::RegKey key; |
| + int64_t value; |
| + |
| + if (key.Open(root_, key_path_.c_str(), kAccess) != ERROR_SUCCESS || |
| + key.ReadInt64(value_name_.c_str(), &value) != ERROR_SUCCESS) { |
| + return base::Time(); |
| + } |
| + |
| + ULARGE_INTEGER intermediate; |
| + intermediate.QuadPart = static_cast<ULONGLONG>(value); |
| + FILETIME beacon_time; |
| + beacon_time.dwLowDateTime = intermediate.u.LowPart; |
| + beacon_time.dwHighDateTime = intermediate.u.HighPart; |
| + return base::Time::FromFileTime(beacon_time); |
| +} |
| + |
| +Beacon::Beacon(base::StringPiece16 name, |
| + BeaconType type, |
| + BeaconScope scope, |
| + bool system_install, |
| + const AppRegistrationData& registration_data) |
| + : type_(type), |
| + root_(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER), |
|
gab
2015/05/26 18:54:34
Remind me how ClientStateMedium works again? It's
grt (UTC plus 2)
2015/05/26 20:54:01
Yes.
|
| + scope_(scope) { |
| + Initialize(name, system_install, registration_data); |
| +} |
| + |
| +void Beacon::Initialize(base::StringPiece16 name, |
| + bool system_install, |
| + const AppRegistrationData& registration_data) { |
| + // When possible, beacons are located in the app's ClientState key. Per-user |
| + // beacons for a per-machine install are located in a beacon-specific sub-key |
| + // of the app's ClientStateMedium key. |
| + if (!system_install || scope_ == BeaconScope::PER_INSTALL) { |
| + key_path_ = registration_data.GetStateKey(); |
| + value_name_ = name.as_string(); |
| + } else { |
| + key_path_ = registration_data.GetStateMediumKey(); |
| + key_path_.push_back(L'\\'); |
| + key_path_.append(name.data(), name.size()); |
| + // This should never fail. If it does, the beacon will be written in the |
| + // key's default value, which is okay since the majority case is likely a |
| + // machine with a single user. |
| + if (!base::win::GetUserSidString(&value_name_)) |
| + NOTREACHED(); |
| + } |
| +} |