summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-14 18:57:36 +0000
committerrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-14 18:57:36 +0000
commitfbc083b99e0fbe436c87225133263de70043f146 (patch)
tree9a0e09b9a88b18506a83b1e16b0392f7754ea580 /chrome/installer
parentf7fe6ec7d7442bfaaa0c7f640fc27b561010b668 (diff)
downloadchromium_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.cc99
-rw-r--r--chrome/installer/gcapi/gcapi.def11
-rw-r--r--chrome/installer/gcapi/gcapi.h27
-rw-r--r--chrome/installer/gcapi/gcapi_last_run_test.cc136
-rw-r--r--chrome/installer/gcapi/gcapi_test.cc10
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());