diff options
author | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-14 18:57:36 +0000 |
---|---|---|
committer | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-14 18:57:36 +0000 |
commit | fbc083b99e0fbe436c87225133263de70043f146 (patch) | |
tree | 9a0e09b9a88b18506a83b1e16b0392f7754ea580 /chrome/installer | |
parent | f7fe6ec7d7442bfaaa0c7f640fc27b561010b668 (diff) | |
download | chromium_src-fbc083b99e0fbe436c87225133263de70043f146.zip chromium_src-fbc083b99e0fbe436c87225133263de70043f146.tar.gz chromium_src-fbc083b99e0fbe436c87225133263de70043f146.tar.bz2 |
Add functionality to the GCAPI to detect when Chrome was last run.
Also fix a buffer overrun while I'm here.
Also, fix up the export definitions to use the more-sane .def file approach.
BUG=103909,88622
TEST=Invoke the GoogleChromeDaysSinceLastRun() export on GCAPI.dll, observe that it reports the number of days since Chrome was last run.
Review URL: http://codereview.chromium.org/8508060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109919 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/gcapi/gcapi.cc | 99 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi.def | 11 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi.h | 27 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi_last_run_test.cc | 136 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi_test.cc | 10 |
5 files changed, 252 insertions, 31 deletions
diff --git a/chrome/installer/gcapi/gcapi.cc b/chrome/installer/gcapi/gcapi.cc index dc38bbe..9982d55 100644 --- a/chrome/installer/gcapi/gcapi.cc +++ b/chrome/installer/gcapi/gcapi.cc @@ -2,19 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// NOTE: This code is a legacy utility API for partners to check whether +// Chrome can be installed and launched. Recent updates are being made +// to add new functionality. These updates use code from Chromium, the old +// coded against the win32 api directly. If you have an itch to shave a +// yak, feel free to re-write the old code too. + #include "chrome/installer/gcapi/gcapi.h" #include <atlbase.h> #include <atlcom.h> -#include <windows.h> #include <sddl.h> #define STRSAFE_NO_DEPRECATE #include <strsafe.h> #include <tlhelp32.h> +#include <windows.h> #include <cstdlib> +#include <limits> +#include <string> + +#include "base/basictypes.h" +#include "base/string_number_conversions.h" +#include "base/time.h" +#include "base/win/registry.h" +#include "chrome/installer/util/google_update_constants.h" -#include "google_update_idl.h" +#include "google_update_idl.h" // NOLINT namespace { @@ -24,6 +38,10 @@ const wchar_t kChromeRegClientsKey[] = const wchar_t kChromeRegClientStateKey[] = L"Software\\Google\\Update\\ClientState\\" L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; +const wchar_t kChromeRegClientStateMediumKey[] = + L"Software\\Google\\Update\\ClientStateMedium\\" + L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; + const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; const wchar_t kChromeRegVersion[] = L"pv"; @@ -70,11 +88,14 @@ bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { if (!::VerQueryValue(file_version_info, info_name, reinterpret_cast<LPVOID *>(&data), reinterpret_cast<UINT *>(&data_len))) return false; - if (data_len <= 0 || data_len >= out_len) + if (data_len <= 0 || data_len >= (out_len / sizeof(wchar_t))) return false; memset(buffer, 0, out_len); - ::StringCchCopyN(buffer, out_len, (const wchar_t*)data, data_len); + ::StringCchCopyN(buffer, + (out_len / sizeof(wchar_t)), + reinterpret_cast<const wchar_t*>(data), + data_len); return true; } @@ -140,9 +161,9 @@ bool CanReOfferChrome(BOOL set_flag) { // Helper function to read a value from registry. Returns true if value // is read successfully and stored in parameter value. Returns false otherwise. -bool ReadValueFromRegistry(HKEY root_key, const wchar_t *sub_key, - const wchar_t *value_name, wchar_t *value, - size_t *size) { +bool ReadValueFromRegistry(HKEY root_key, const wchar_t* sub_key, + const wchar_t* value_name, wchar_t* value, + size_t* size) { HKEY key; if ((::RegOpenKeyEx(root_key, sub_key, NULL, KEY_READ, &key) == ERROR_SUCCESS) && @@ -164,7 +185,7 @@ bool IsChromeInstalled(HKEY root_key) { enum WindowsVersion { VERSION_BELOW_XP_SP2, - VERSION_XP_SP2_UP_TO_VISTA, // "but not including" + VERSION_XP_SP2_UP_TO_VISTA, // "but not including" VERSION_VISTA_OR_HIGHER, }; WindowsVersion GetWindowsVersion() { @@ -283,9 +304,7 @@ bool GetUserIdForProcess(size_t pid, wchar_t** user_sid) { } } // namespace -#pragma comment(linker, "/EXPORT:GoogleChromeCompatibilityCheck=_GoogleChromeCompatibilityCheck@8,PRIVATE") -DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, - DWORD *reasons) { +BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, DWORD* reasons) { DWORD local_reasons = 0; WindowsVersion windows_version = GetWindowsVersion(); @@ -319,8 +338,7 @@ DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, return (local_reasons == 0); } -#pragma comment(linker, "/EXPORT:LaunchGoogleChrome=_LaunchGoogleChrome@0,PRIVATE") -DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { +BOOL __stdcall LaunchGoogleChrome() { wchar_t launch_cmd[MAX_PATH]; size_t size = _countof(launch_cmd); if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, @@ -413,11 +431,10 @@ DLLEXPORT BOOL __stdcall LaunchGoogleChrome() { return ret; } -#pragma comment(linker, "/EXPORT:LaunchGoogleChromeWithDimensions=_LaunchGoogleChromeWithDimensions@16,PRIVATE") -DLLEXPORT BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, - int y, - int width, - int height) { +BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, + int y, + int width, + int height) { if (!LaunchGoogleChrome()) return false; @@ -451,3 +468,49 @@ DLLEXPORT BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, return (handle && SetWindowPos(handle, 0, x, y, width, height, SWP_NOZORDER)); } + +int __stdcall GoogleChromeDaysSinceLastRun() { + using base::win::RegKey; + using base::Time; + using base::TimeDelta; + + int days_since_last_run = std::numeric_limits<int>::max(); + + struct { + HKEY hive; + const wchar_t* path; + } reg_data[] = { + { HKEY_LOCAL_MACHINE, kChromeRegClientStateMediumKey }, + { HKEY_CURRENT_USER, kChromeRegClientStateKey } + }; + + for (int i = 0; i < arraysize(reg_data); ++i) { + if (IsChromeInstalled(reg_data[i].hive)) { + RegKey client_state(reg_data[i].hive, reg_data[i].path, KEY_QUERY_VALUE); + if (client_state.Valid()) { + std::wstring last_run; + int64 last_run_value = 0; + if (client_state.ReadValue(google_update::kRegLastRunTimeField, + &last_run) == ERROR_SUCCESS && + base::StringToInt64(last_run, &last_run_value)) { + Time last_run_time = Time::FromInternalValue(last_run_value); + TimeDelta difference = Time::NowFromSystemTime() - last_run_time; + + // We can end up with negative numbers here, given changes in system + // clock time or due to TimeDelta's int64 -> int truncation. + int new_days_since_last_run = difference.InDays(); + if (new_days_since_last_run >= 0 && + new_days_since_last_run < days_since_last_run) { + days_since_last_run = new_days_since_last_run; + } + } + } + } + } + + if (days_since_last_run == std::numeric_limits<int>::max()) { + days_since_last_run = -1; + } + + return days_since_last_run; +} diff --git a/chrome/installer/gcapi/gcapi.def b/chrome/installer/gcapi/gcapi.def new file mode 100644 index 0000000..ad7286f --- /dev/null +++ b/chrome/installer/gcapi/gcapi.def @@ -0,0 +1,11 @@ +LIBRARY "gcapi_dll.dll" + +EXPORTS + ; Note that we keep the assigned ordinals for a couple of the exports + ; to maintain parity with the old gcapi code. LaunchGoogleChrome was + ; originally tagged as having an export ordinal of 0 which afaict is not + ; legal. + GoogleChromeCompatibilityCheck @8 PRIVATE + LaunchGoogleChrome PRIVATE + LaunchGoogleChromeWithDimensions @16 PRIVATE + GoogleChromeDaysSinceLastRun PRIVATE diff --git a/chrome/installer/gcapi/gcapi.h b/chrome/installer/gcapi/gcapi.h index dea875f..b61e315 100644 --- a/chrome/installer/gcapi/gcapi.h +++ b/chrome/installer/gcapi/gcapi.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -17,8 +17,6 @@ extern "C" { #define GCCC_ERROR_ALREADYOFFERED 0x10 #define GCCC_ERROR_INTEGRITYLEVEL 0x20 -#define DLLEXPORT __declspec(dllexport) - // This function returns TRUE if Google Chrome should be offered. // If the return is FALSE, the reasons DWORD explains why. If you don't care // for the reason, you can pass NULL for reasons. @@ -26,13 +24,12 @@ extern "C" { // offered within the last six months; if passed FALSE, this method will not // set the flag even if Chrome can be offered. If passed TRUE, this method // will set the flag only if Chrome can be offered. -DLLEXPORT BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, - DWORD *reasons); +BOOL __stdcall GoogleChromeCompatibilityCheck(BOOL set_flag, DWORD* reasons); // This function launches Google Chrome after a successful install. Make // sure COM library is NOT initalized before you call this function (so if // you called CoInitialize, call CoUninitialize before calling this function). -DLLEXPORT BOOL __stdcall LaunchGoogleChrome(); +BOOL __stdcall LaunchGoogleChrome(); // This function launches Google Chrome after a successful install at the // given x,y coordinates with size height,length. Make @@ -40,15 +37,25 @@ DLLEXPORT BOOL __stdcall LaunchGoogleChrome(); // you called CoInitialize, call CoUninitialize before calling this function). // This call is synchronous, meaning it waits for Chrome to launch and appear // to resize it before returning. -DLLEXPORT BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, +BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, int y, int width, int height); +// This function returns the number of days since Google Chrome was last run by +// the current user. If both user-level and machine-wide installations are +// present on the system, it will return the lowest last-run-days count of +// the two. +// Returns -1 if Chrome is not installed, the last run date is in the future, +// or we are otherwise unable to determine how long since Chrome was last +// launched. +int __stdcall GoogleChromeDaysSinceLastRun(); + // Funtion pointer type declarations to use with GetProcAddress. -typedef BOOL (__stdcall * GCCC_CompatibilityCheck)(BOOL, DWORD *); -typedef BOOL (__stdcall * GCCC_LaunchGC)(HANDLE *); -typedef BOOL (__stdcall * GCCC_LaunchGCWithDimensions)(int, int, int, int); +typedef BOOL (__stdcall *GCCC_CompatibilityCheck)(BOOL, DWORD *); +typedef BOOL (__stdcall *GCCC_LaunchGC)(HANDLE *); +typedef BOOL (__stdcall *GCCC_LaunchGCWithDimensions)(int, int, int, int); +typedef int (__stdcall *GCCC_GoogleChromeDaysSinceLastRun)(); } // extern "C" #endif // CHROME_INSTALLER_GCAPI_GCAPI_H_ diff --git a/chrome/installer/gcapi/gcapi_last_run_test.cc b/chrome/installer/gcapi/gcapi_last_run_test.cc new file mode 100644 index 0000000..f1eddc2 --- /dev/null +++ b/chrome/installer/gcapi/gcapi_last_run_test.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2011 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 <limits> +#include <string> + +#include "base/basictypes.h" +#include "base/string_number_conversions.h" +#include "base/stringprintf.h" +#include "base/test/test_reg_util_win.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "base/win/registry.h" +#include "chrome/common/guid.h" +#include "chrome/installer/gcapi/gcapi.h" +#include "chrome/installer/util/google_update_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::Time; +using base::TimeDelta; +using base::win::RegKey; + + +class GCAPILastRunTest : public ::testing::Test { + protected: + void SetUp() { + // Override keys - this is undone during destruction. + std::wstring hklm_override = base::StringPrintf( + L"hklm_override\\%ls", ASCIIToWide(guid::GenerateGUID())); + override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, hklm_override); + std::wstring hkcu_override = base::StringPrintf( + L"hkcu_override\\%ls", ASCIIToWide(guid::GenerateGUID())); + override_manager_.OverrideRegistry(HKEY_CURRENT_USER, hkcu_override); + + // Create the client state keys in the right places. + struct { + HKEY hive; + const wchar_t* path; + } reg_data[] = { + { HKEY_LOCAL_MACHINE, google_update::kRegPathClientStateMedium }, + { HKEY_CURRENT_USER, google_update::kRegPathClientState } + }; + for (int i = 0; i < arraysize(reg_data); ++i) { + std::wstring reg_path(reg_data[i].path); + reg_path += L"\\"; + reg_path += google_update::kChromeUpgradeCode; + RegKey client_state(reg_data[i].hive, + reg_path.c_str(), + KEY_CREATE_SUB_KEY); + ASSERT_TRUE(client_state.Valid()); + + // Place a bogus "pv" value in the right places to make the last run + // checker believe Chrome is installed. + std::wstring clients_path(google_update::kRegPathClients); + clients_path += L"\\"; + clients_path += google_update::kChromeUpgradeCode; + RegKey client_key(reg_data[i].hive, + clients_path.c_str(), + KEY_CREATE_SUB_KEY | KEY_SET_VALUE); + ASSERT_TRUE(client_key.Valid()); + client_key.WriteValue(L"pv", L"1.2.3.4"); + } + } + + bool SetLastRunTime(HKEY hive, int64 last_run_time) { + return SetLastRunTimeString(hive, base::Int64ToString16(last_run_time)); + } + + bool SetLastRunTimeString(HKEY hive, const string16& last_run_time_string) { + const wchar_t* base_path = + (hive == HKEY_LOCAL_MACHINE) ? + google_update::kRegPathClientStateMedium : + google_update::kRegPathClientState; + std::wstring path(base_path); + path += L"\\"; + path += google_update::kChromeUpgradeCode; + + RegKey client_state(hive, path.c_str(), KEY_SET_VALUE); + return (client_state.Valid() && + client_state.WriteValue( + google_update::kRegLastRunTimeField, + last_run_time_string.c_str()) == ERROR_SUCCESS); + } + + private: + registry_util::RegistryOverrideManager override_manager_; +}; + +TEST_F(GCAPILastRunTest, Basic_HKCU) { + Time last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(10); + EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER, last_run.ToInternalValue())); + + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(10, days_since_last_run); +} + +TEST_F(GCAPILastRunTest, Basic_HKLM) { + Time last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(10); + EXPECT_TRUE(SetLastRunTime(HKEY_LOCAL_MACHINE, last_run.ToInternalValue())); + + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(10, days_since_last_run); +} + +TEST_F(GCAPILastRunTest, HKLM_and_HKCU) { + Time hklm_last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(30); + EXPECT_TRUE(SetLastRunTime(HKEY_LOCAL_MACHINE, + hklm_last_run.ToInternalValue())); + + Time hkcu_last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(20); + EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER, + hkcu_last_run.ToInternalValue())); + + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(20, days_since_last_run); +} + +TEST_F(GCAPILastRunTest, NoLastRun) { + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(-1, days_since_last_run); +} + +TEST_F(GCAPILastRunTest, InvalidLastRun) { + EXPECT_TRUE(SetLastRunTimeString(HKEY_CURRENT_USER, L"Hi Mum!")); + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(-1, days_since_last_run); +} + +TEST_F(GCAPILastRunTest, OutOfRangeLastRun) { + Time last_run = Time::NowFromSystemTime() - TimeDelta::FromDays(-42); + EXPECT_TRUE(SetLastRunTime(HKEY_CURRENT_USER, last_run.ToInternalValue())); + + int days_since_last_run = GoogleChromeDaysSinceLastRun(); + EXPECT_EQ(-1, days_since_last_run); +} diff --git a/chrome/installer/gcapi/gcapi_test.cc b/chrome/installer/gcapi/gcapi_test.cc index 838397cd..2100744 100644 --- a/chrome/installer/gcapi/gcapi_test.cc +++ b/chrome/installer/gcapi/gcapi_test.cc @@ -1,11 +1,12 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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/gcapi/gcapi.h" - #include <stdio.h> +#include "chrome/installer/gcapi/gcapi.h" +#include "testing/gtest/include/gtest/gtest.h" + void call_statically() { DWORD reason = 0; BOOL result_flag_on = FALSE; @@ -54,6 +55,9 @@ void call_dynamically() { } int main(int argc, char* argv[]) { + testing::InitGoogleTest(&argc, argv); + RUN_ALL_TESTS(); + call_dynamically(); call_statically(); printf("LaunchChrome returned %d.\n", LaunchGoogleChrome()); |