blob: 07891dd52cda918abf282c9fe3427f779d8b123a [file] [log] [blame]
// Copyright (c) 2011 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include <windows.h>
#include <cassert>
#include <memory>
#include <string>
#include <sstream>
#include "omahautil.hpp"
#include "debugutil.hpp"
//#include "memutil.hpp"
#include "registry.hpp"
namespace WebmUtil
{
class OmahaStats
{
public:
OmahaStats();
~OmahaStats();
HRESULT SetUsageFlags(const GUID& app_id);
private:
bool UserHasEnabledStats_();
HRESULT CreateHkcuClientStateSubKey_();
HRESULT MakeAppKeyStr_();
HRESULT SetUsageFlags_();
bool stats_enabled_;
GUID app_id_guid_;
Registry::Key app_key_; // App's key (might be in HKLM)
Registry::Key user_key_; // App's key in HKCU
std::wstring app_key_str_;
DISALLOW_COPY_AND_ASSIGN(OmahaStats);
};
} // WebmUtil namespace
HRESULT WebmUtil::set_omaha_usage_flags(const GUID& app_id)
{
OmahaStats stats;
return stats.SetUsageFlags(app_id);
}
namespace WebmUtil
{
const int kOmahaAppIdStrLen = 40;
OmahaStats::OmahaStats():
app_id_guid_(GUID_NULL),
stats_enabled_(false)
{
}
OmahaStats::~OmahaStats()
{
}
HRESULT OmahaStats::SetUsageFlags(const GUID& app_id)
{
HRESULT hr;
// store the user guid
app_id_guid_ = app_id;
// let's make our app sub key string...
CHK(hr, MakeAppKeyStr_());
if (FAILED(hr))
{
return hr;
}
// survived putting the sub key string in |app_key_str_|, let's see if
// the user enabled stats at install time...
if (UserHasEnabledStats_() == false)
{
// nope! Everything's ok, nothing to see here...
return S_OK;
}
// stats enabled! Let's set the usage flags...
CHK(hr, SetUsageFlags_());
return hr;
}
bool OmahaStats::UserHasEnabledStats_()
{
if (GUID_NULL != app_id_guid_ && app_key_str_.length())
{
// We support Omaha client installs that live in HKLM and HKCU...
const int num_keys = 2;
HKEY keys_to_check[num_keys] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
for (int i = 0; i < num_keys; ++i)
{
// loop through |keys_to_check| and try each with the generated
// key string in |app_key_str_|
LONG reg_error = app_key_.open(keys_to_check[i], app_key_str_);
if (ERROR_SUCCESS == reg_error)
{
assert(app_key_.is_open());
// key is open, let's read (query) the usagestats val...
DWORD usage_stats_value = 0;
reg_error = app_key_.query("usagestats", usage_stats_value);
if (ERROR_SUCCESS == reg_error && usage_stats_value)
{
// the user enabled usage tracking at install time
stats_enabled_ = true;
}
}
}
}
return stats_enabled_;
}
HRESULT OmahaStats::CreateHkcuClientStateSubKey_()
{
// .. and set the "dr" flag
// TODO(tomfinegan): flag setting should probably move elsewhere, and
// wrapping the subkey creation is sort of silly given
// how easy matthewjheaney's Registry class is to use...
LONG reg_error = user_key_.create(HKEY_CURRENT_USER, app_key_str_);
if (ERROR_SUCCESS == reg_error)
{
reg_error = user_key_.set(L"dr", L"1", REG_SZ);
}
return ERROR_SUCCESS == reg_error ? S_OK : E_FAIL;
}
// Build the subkey path for the Omaha application we're working with using
// the GUID passed to |WebmUtil::set_omaha_usage_flag|
HRESULT OmahaStats::MakeAppKeyStr_()
{
if (GUID_NULL == app_id_guid_)
{
DBGLOG("need a valid guid.");
return E_INVALIDARG;
}
wchar_t app_id_wchars[kOmahaAppIdStrLen] = {0};
int wchars_converted = StringFromGUID2(app_id_guid_, &app_id_wchars[0],
kOmahaAppIdStrLen);
assert(wchars_converted > 0);
if (!wchars_converted)
{
DBGLOG("conversion of app_id to string failed.");
return E_FAIL;
}
std::wostringstream key_stream;
key_stream << "Software\\";
#ifdef _WIN64
// At present we use a 32 bit NSIS installer, and it writes to the tree
// under Wow6432Node when the NSIS registry utility functions are used.
// Omaha reads the values from there as well, so let's keep it simple and
// write there from our 64bit builds as well.
key_stream << L"Wow6432Node\\";
#endif
key_stream << L"Google\\Update\\ClientState\\" << app_id_wchars;
app_key_str_ = key_stream.str();
return S_OK;
}
// Note: SetUsageFlags_ is a bit of a misnomer-- we're setting only the "dr"
// flag, which tells Omaha that the tracked application has been run
// since it was last updated.
HRESULT OmahaStats::SetUsageFlags_()
{
REGSAM access_flags = KEY_QUERY_VALUE | KEY_SET_VALUE;
LONG reg_error = user_key_.open(HKEY_CURRENT_USER, app_key_str_,
access_flags);
if (ERROR_FILE_NOT_FOUND == reg_error)
{
HRESULT hr;
// Note: |CreateHkcuClientStateSubKey_| sets the "dr" flag
CHK(hr, CreateHkcuClientStateSubKey_());
return hr;
}
else if (ERROR_SUCCESS == reg_error)
{
// Set only if not present. This should help prevent repeated nag
// dialogs for users running registry monitoring software that notifies
// on all registry writes.
std::wstring dr_value;
reg_error = user_key_.query(L"dr", dr_value);
if (ERROR_FILE_NOT_FOUND == reg_error)
{
reg_error = user_key_.set(L"dr", L"1", REG_SZ);
}
}
return ERROR_SUCCESS == reg_error ? S_OK : E_FAIL;
}
} // WebmUtil namespace