blob: 074b6c826ab4c96c389a966eabaff9f4c3fb7965 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
[email protected]c9349d082008-08-22 21:16:474
[email protected]4512f3ac2009-11-04 03:39:225#include <windows.h>
6#include <shlwapi.h>
[email protected]c9349d082008-08-22 21:16:477
[email protected]4512f3ac2009-11-04 03:39:228#include "chrome/app/breakpad_win.h"
9#include "chrome/app/client_util.h"
[email protected]103607e2010-02-01 18:57:0910#include "chrome/common/chrome_switches.h"
[email protected]4512f3ac2009-11-04 03:39:2211#include "chrome/common/result_codes.h"
[email protected]74d1eec2009-11-04 22:18:5712#include "chrome/installer/util/browser_distribution.h"
[email protected]4512f3ac2009-11-04 03:39:2213#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5714#include "chrome/installer/util/google_update_constants.h"
[email protected]28c19692008-11-07 23:40:3815#include "chrome/installer/util/util_constants.h"
16
17namespace {
[email protected]4512f3ac2009-11-04 03:39:2218// The entry point signature of chrome.dll.
19typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);
[email protected]28c19692008-11-07 23:40:3820
[email protected]4512f3ac2009-11-04 03:39:2221// Not generic, we only handle strings up to 128 chars.
22bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
23 BYTE out[128 * sizeof(wchar_t)];
24 DWORD size = sizeof(out);
25 DWORD type = 0;
26 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
[email protected]28c19692008-11-07 23:40:3827 return false;
[email protected]4512f3ac2009-11-04 03:39:2228 if (type != REG_SZ)
29 return false;
30 value->assign(reinterpret_cast<wchar_t*>(out));
[email protected]28c19692008-11-07 23:40:3831 return true;
32}
[email protected]c9349d082008-08-22 21:16:4733
[email protected]4512f3ac2009-11-04 03:39:2234// Gets chrome version according to the load path. |exe_path| must be the
35// backslash terminated directory of the current chrome.exe.
36bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
37 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3238 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3839 HKEY_LOCAL_MACHINE;
[email protected]4512f3ac2009-11-04 03:39:2240 HKEY key;
41 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
[email protected]c9349d082008-08-22 21:16:4742 return false;
[email protected]28c19692008-11-07 23:40:3843
[email protected]4512f3ac2009-11-04 03:39:2244 // If 'new_chrome.exe' is present it means chrome was auto-updated while
45 // running. We need to consult the opv value so we can load the old dll.
46 // TODO(cpu) : This is solving the same problem as the environment variable
47 // so one of them will eventually be deprecated.
[email protected]28c19692008-11-07 23:40:3848 std::wstring new_chrome_exe(exe_path);
49 new_chrome_exe.append(installer_util::kChromeNewExe);
[email protected]4512f3ac2009-11-04 03:39:2250 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
51 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
52 ::RegCloseKey(key);
[email protected]28c19692008-11-07 23:40:3853 return true;
[email protected]2414e842008-11-07 01:27:5754 }
55
[email protected]4512f3ac2009-11-04 03:39:2256 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
57 ::RegCloseKey(key);
[email protected]c9349d082008-08-22 21:16:4758 return ret;
59}
60
[email protected]4512f3ac2009-11-04 03:39:2261// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2662std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2263 wchar_t path[MAX_PATH];
64 ::GetModuleFileNameW(NULL, path, MAX_PATH);
65 if (!::PathRemoveFileSpecW(path))
66 return std::wstring();
67 std::wstring exe_path(path);
68 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4769}
70
[email protected]4512f3ac2009-11-04 03:39:2271// Not generic, we only handle strings up to 128 chars.
72bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
73 wchar_t out[128];
74 DWORD count = sizeof(out)/sizeof(out[0]);
75 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
76 if ((rv == 0) || (rv >= count))
77 return false;
78 *value = out;
79 return true;
80}
81
82// Expects that |dir| has a trailing backslash. |dir| is modified so it
83// contains the full path that was tried. Caller must check for the return
84// value not being null to dermine if this path contains a valid dll.
85HMODULE LoadChromeWithDirectory(std::wstring* dir) {
86 ::SetCurrentDirectoryW(dir->c_str());
[email protected]103607e2010-02-01 18:57:0987#ifdef _WIN64
88 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
89 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
90 switches::kNaClBrokerProcess) ||
91 (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
92 switches::kNaClLoaderProcess)) {
93 // Load the 64-bit DLL when running in a 64-bit process.
94 dir->append(installer_util::kChromeNaCl64Dll);
95 } else {
96 // Only NaCl broker and loader can be launched as Win64 processes.
97 NOTREACHED();
98 return NULL;
99 }
100#else
[email protected]4512f3ac2009-11-04 03:39:22101 dir->append(installer_util::kChromeDll);
[email protected]103607e2010-02-01 18:57:09102#endif
[email protected]4512f3ac2009-11-04 03:39:22103 return ::LoadLibraryExW(dir->c_str(), NULL,
104 LOAD_WITH_ALTERED_SEARCH_PATH);
105}
106
[email protected]42d7510c2009-12-19 01:48:30107// Set did_run "dr" in omaha's client state for this product.
108bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
[email protected]4512f3ac2009-11-04 03:39:22109 std::wstring key_path(google_update::kRegPathClientState);
110 key_path.append(L"\\").append(guid);
111 HKEY reg_key;
112 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
113 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
114 &reg_key, NULL) == ERROR_SUCCESS) {
[email protected]203c6872010-01-30 15:59:45115 // Note that the length here must be in bytes and must account for the
116 // terminating null char.
[email protected]4512f3ac2009-11-04 03:39:22117 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
[email protected]203c6872010-01-30 15:59:45118 reinterpret_cast<const BYTE *>(value),
119 (::lstrlenW(value) + 1) * sizeof(wchar_t));
[email protected]4512f3ac2009-11-04 03:39:22120 ::RegCloseKey(reg_key);
121 return true;
122 }
123 return false;
124}
[email protected]42d7510c2009-12-19 01:48:30125
126bool RecordDidRun(const wchar_t* guid) {
127 return SetDidRunState(guid, L"1");
[email protected]4512f3ac2009-11-04 03:39:22128}
129
[email protected]42d7510c2009-12-19 01:48:30130bool ClearDidRun(const wchar_t* guid) {
131 return SetDidRunState(guid, L"0");
132}
133
134}
[email protected]4512f3ac2009-11-04 03:39:22135//=============================================================================
136
137MainDllLoader::MainDllLoader() : dll_(NULL) {
138}
139
140MainDllLoader::~MainDllLoader() {
141#ifdef PURIFY
142 // We should never unload the dll. There is only risk and no gain from
143 // doing so. The singleton dtors have been already run by AtExitManager.
144 ::FreeLibrary(dll_);
145#endif
146}
147
148// Loading chrome is an interesting afair. First we try loading from the current
149// directory to support run-what-you-compile and other development scenarios.
150// If that fails then we look at the 'CHROME_VERSION' env variable to determine
151// if we should stick with an older dll version even if a new one is available
152// to support upgrade-in-place scenarios, and if that fails we finally we look
153// at the registry which should point us to the latest version.
154HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
155 std::wstring dir(GetExecutablePath());
156 *file = dir;
157 HMODULE dll = LoadChromeWithDirectory(file);
158 if (dll)
159 return dll;
160
161 if (!EnvQueryStr(google_update::kEnvProductVersionKey, version)) {
162 std::wstring reg_path(GetRegistryPath());
163 // Look into the registry to find the latest version.
164 if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
165 return NULL;
166 }
167
168 *file = dir;
[email protected]f244388d2009-11-04 05:33:28169 file->append(*version).append(L"\\");
[email protected]4512f3ac2009-11-04 03:39:22170 return LoadChromeWithDirectory(file);
171}
172
173// Launching is a matter of loading the right dll, setting the CHROME_VERSION
174// environment variable and just calling the entry point. Derived classes can
175// add custom code in the OnBeforeLaunch callback.
176int MainDllLoader::Launch(HINSTANCE instance,
177 sandbox::SandboxInterfaceInfo* sbox_info) {
178 std::wstring version;
179 std::wstring file;
180 dll_ = Load(&version, &file);
181 if (!dll_)
182 return ResultCodes::MISSING_DATA;
183
184 ::SetEnvironmentVariableW(google_update::kEnvProductVersionKey,
185 version.c_str());
186
187 InitCrashReporterWithDllPath(file);
[email protected]4512f3ac2009-11-04 03:39:22188 OnBeforeLaunch(version);
189
190 DLL_MAIN entry_point =
191 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
192 if (!entry_point)
193 return ResultCodes::BAD_PROCESS_TYPE;
194
[email protected]42d7510c2009-12-19 01:48:30195 int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
196 return OnBeforeExit(rc);
[email protected]4512f3ac2009-11-04 03:39:22197}
198
199//=============================================================================
200
201class ChromeDllLoader : public MainDllLoader {
202 public:
203 virtual std::wstring GetRegistryPath() {
204 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48205 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
206 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22207 return key;
208 }
209
210 virtual void OnBeforeLaunch(const std::wstring& version) {
[email protected]5f2cee82009-11-05 04:59:48211 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
212 RecordDidRun(dist->GetAppGuid().c_str());
[email protected]4512f3ac2009-11-04 03:39:22213 }
[email protected]42d7510c2009-12-19 01:48:30214
215 virtual int OnBeforeExit(int return_code) {
216 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
217 // so we need to reset the did_run signal so omaha does not count
218 // this run as active usage.
219 if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
220 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
221 ClearDidRun(dist->GetAppGuid().c_str());
222 }
223 return return_code;
224 }
[email protected]4512f3ac2009-11-04 03:39:22225};
226
227//=============================================================================
228
229class ChromiumDllLoader : public MainDllLoader {
230 public:
231 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57232 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
233 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22234 }
235};
236
237MainDllLoader* MakeMainDllLoader() {
238#if defined(GOOGLE_CHROME_BUILD)
239 return new ChromeDllLoader();
240#else
241 return new ChromiumDllLoader();
242#endif
243}