Adding WebRTC log upload list under chrome://webrtc-logs
[chromium-blink-merge.git] / chrome / app / client_util.cc
blob38412e7af5fa9f8126ee0d8750ae149a0c483abe
1 // Copyright (c) 2012 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.
5 #include <windows.h>
6 #include <shlwapi.h>
8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h"
10 #include "base/environment.h"
11 #include "base/file_version_info.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/version.h"
19 #include "base/win/registry.h"
20 #include "chrome/app/breakpad_win.h"
21 #include "chrome/app/client_util.h"
22 #include "chrome/common/chrome_constants.h"
23 #include "chrome/common/chrome_result_codes.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/env_vars.h"
26 #include "chrome/installer/util/browser_distribution.h"
27 #include "chrome/installer/util/channel_info.h"
28 #include "chrome/installer/util/google_update_constants.h"
29 #include "chrome/installer/util/google_update_settings.h"
30 #include "chrome/installer/util/install_util.h"
31 #include "chrome/installer/util/util_constants.h"
33 namespace {
34 // The entry point signature of chrome.dll.
35 typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*);
37 typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
39 // Gets chrome version according to the load path. |exe_path| must be the
40 // backslash terminated directory of the current chrome.exe.
41 // TODO(cpu): This is now only used to support metro_driver, remove it.
42 bool GetChromeVersion(const wchar_t* exe_dir, const wchar_t* key_path,
43 string16* version) {
44 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_dir) ? HKEY_CURRENT_USER :
45 HKEY_LOCAL_MACHINE;
46 bool success = false;
48 base::win::RegKey key(reg_root, key_path, KEY_QUERY_VALUE);
49 if (key.Valid()) {
50 string16 new_chrome_exe(exe_dir);
51 new_chrome_exe.append(installer::kChromeNewExe);
52 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
53 key.ReadValue(google_update::kRegOldVersionField,
54 version) == ERROR_SUCCESS) {
55 success = true;
56 } else {
57 success = (key.ReadValue(google_update::kRegVersionField,
58 version) == ERROR_SUCCESS);
62 return success;
65 // Expects that |dir| has a trailing backslash. |dir| is modified so it
66 // contains the full path that was tried. Caller must check for the return
67 // value not being null to determine if this path contains a valid dll.
68 HMODULE LoadChromeWithDirectory(string16* dir) {
69 ::SetCurrentDirectoryW(dir->c_str());
70 dir->append(installer::kChromeDll);
72 return ::LoadLibraryExW(dir->c_str(), NULL,
73 LOAD_WITH_ALTERED_SEARCH_PATH);
76 void RecordDidRun(const string16& dll_path) {
77 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str());
78 GoogleUpdateSettings::UpdateDidRunState(true, system_level);
81 void ClearDidRun(const string16& dll_path) {
82 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str());
83 GoogleUpdateSettings::UpdateDidRunState(false, system_level);
86 #if defined(CHROME_SPLIT_DLL)
87 // Deferred initialization entry point for chrome1.dll.
88 typedef BOOL (__stdcall *DoDeferredCrtInitFunc)(HINSTANCE hinstance);
90 bool InitSplitChromeDll(HMODULE mod) {
91 if (!mod)
92 return false;
93 DoDeferredCrtInitFunc init = reinterpret_cast<DoDeferredCrtInitFunc>(
94 ::GetProcAddress(mod, "_DoDeferredCrtInit@4"));
95 return (init(mod) == TRUE);
97 #endif
98 } // namespace
100 string16 GetExecutablePath() {
101 wchar_t path[MAX_PATH];
102 ::GetModuleFileNameW(NULL, path, MAX_PATH);
103 if (!::PathRemoveFileSpecW(path))
104 return string16();
105 string16 exe_path(path);
106 return exe_path.append(1, L'\\');
109 //=============================================================================
111 MainDllLoader::MainDllLoader() : dll_(NULL) {
114 MainDllLoader::~MainDllLoader() {
117 // Loading chrome is an interesting affair. First we try loading from the
118 // current directory to support run-what-you-compile and other development
119 // scenarios.
120 // If that fails then we look at the --chrome-version command line flag followed
121 // by the 'CHROME_VERSION' env variable to determine if we should stick with an
122 // older dll version even if a new one is available to support upgrade-in-place
123 // scenarios.
124 // If that fails then finally we look at the registry which should point us
125 // to the latest version. This is the expected path for the first chrome.exe
126 // browser instance in an installed build.
127 HMODULE MainDllLoader::Load(string16* out_version, string16* out_file) {
128 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
129 const string16 dir(GetExecutablePath());
130 *out_file = dir;
131 HMODULE dll = LoadChromeWithDirectory(out_file);
132 if (!dll) {
133 // Loading from same directory (for developers) failed.
134 string16 version_string;
135 Version version;
136 if (cmd_line.HasSwitch(switches::kChromeVersion)) {
137 // This is used to support Chrome Frame, see http://crbug.com/88589.
138 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion);
139 version = Version(WideToASCII(version_string));
141 if (!version.IsValid()) {
142 // If a bogus command line flag was given, then abort.
143 LOG(ERROR) << "Invalid command line version: " << version_string;
144 return NULL;
148 // If no version on the command line, then look at the version resource in
149 // the current module and try loading that.
150 if (!version.IsValid()) {
151 scoped_ptr<FileVersionInfo> file_version_info(
152 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
153 if (file_version_info.get()) {
154 version_string = file_version_info->file_version();
155 version = Version(WideToASCII(version_string));
159 if (!version.IsValid()) {
160 LOG(ERROR) << "No valid Chrome version found";
161 return NULL;
164 *out_file = dir;
165 *out_version = version_string;
166 out_file->append(*out_version).append(1, L'\\');
167 dll = LoadChromeWithDirectory(out_file);
168 if (!dll) {
169 LOG(ERROR) << "Failed to load Chrome DLL from " << *out_file;
170 return NULL;
174 #if defined(CHROME_SPLIT_DLL)
175 // In split dlls mode, we need to manually initialize both DLLs because
176 // the circular dependencies between them make the loader not call the
177 // Dllmain for DLL_PROCESS_ATTACH.
178 InitSplitChromeDll(dll);
179 InitSplitChromeDll(::GetModuleHandleA("chrome1.dll"));
180 #endif
182 return dll;
185 // Launching is a matter of loading the right dll, setting the CHROME_VERSION
186 // environment variable and just calling the entry point. Derived classes can
187 // add custom code in the OnBeforeLaunch callback.
188 int MainDllLoader::Launch(HINSTANCE instance,
189 sandbox::SandboxInterfaceInfo* sbox_info) {
190 string16 version;
191 string16 file;
192 dll_ = Load(&version, &file);
193 if (!dll_)
194 return chrome::RESULT_CODE_MISSING_DATA;
196 scoped_ptr<base::Environment> env(base::Environment::Create());
197 env->SetVar(chrome::kChromeVersionEnvVar, WideToUTF8(version));
198 // TODO(erikwright): Remove this when http://crbug.com/174953 is fixed and
199 // widely deployed.
200 env->UnSetVar(env_vars::kGoogleUpdateIsMachineEnvVar);
202 InitCrashReporter();
203 OnBeforeLaunch(file);
205 DLL_MAIN entry_point =
206 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
207 if (!entry_point)
208 return chrome::RESULT_CODE_BAD_PROCESS_TYPE;
210 int rc = entry_point(instance, sbox_info);
211 return OnBeforeExit(rc, file);
214 string16 MainDllLoader::GetVersion() {
215 string16 reg_path(GetRegistryPath());
216 string16 version_string;
217 string16 dir(GetExecutablePath());
218 if (!GetChromeVersion(dir.c_str(), reg_path.c_str(), &version_string))
219 return string16();
220 return version_string;
223 void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
224 RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
225 reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
226 ::GetProcAddress(dll_,
227 "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
228 if (!relaunch_function) {
229 LOG(ERROR) << "Could not find exported function "
230 << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
231 } else {
232 relaunch_function();
236 //=============================================================================
238 class ChromeDllLoader : public MainDllLoader {
239 public:
240 virtual string16 GetRegistryPath() {
241 string16 key(google_update::kRegPathClients);
242 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
243 key.append(L"\\").append(dist->GetAppGuid());
244 return key;
247 virtual void OnBeforeLaunch(const string16& dll_path) {
248 RecordDidRun(dll_path);
251 virtual int OnBeforeExit(int return_code, const string16& dll_path) {
252 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
253 // so we need to reset the did_run signal so omaha does not count
254 // this run as active usage.
255 if (chrome::RESULT_CODE_NORMAL_EXIT_CANCEL == return_code) {
256 ClearDidRun(dll_path);
258 return return_code;
262 //=============================================================================
264 class ChromiumDllLoader : public MainDllLoader {
265 public:
266 virtual string16 GetRegistryPath() {
267 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
268 return dist->GetVersionKey();
272 MainDllLoader* MakeMainDllLoader() {
273 #if defined(GOOGLE_CHROME_BUILD)
274 return new ChromeDllLoader();
275 #else
276 return new ChromiumDllLoader();
277 #endif