Remove EWK_BRINGUPS for M120 #3
[platform/framework/web/chromium-efl.git] / chrome / app / chrome_exe_main_win.cc
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/app/chrome_exe_main_win.h"
6
7 #include <windows.h>
8
9 #include <malloc.h>
10 #include <stddef.h>
11 #include <tchar.h>
12
13 #include <algorithm>
14 #include <array>
15 #include <string>
16
17 #include "base/at_exit.h"
18 #include "base/base_switches.h"
19 #include "base/command_line.h"
20 #include "base/containers/cxx20_erase.h"
21 #include "base/debug/alias.h"
22 #include "base/debug/handle_hooks_win.h"
23 #include "base/feature_list.h"
24 #include "base/files/file_path.h"
25 #include "base/files/file_util.h"
26 #include "base/logging.h"
27 #include "base/path_service.h"
28 #include "base/process/memory.h"
29 #include "base/process/process.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/strings/string_split.h"
32 #include "base/strings/string_util.h"
33 #include "base/strings/utf_string_conversions.h"
34 #include "base/time/time.h"
35 #include "base/win/current_module.h"
36 #include "base/win/registry.h"
37 #include "base/win/win_util.h"
38 #include "base/win/windows_version.h"
39 #include "build/build_config.h"
40 #include "chrome/app/delay_load_failure_hook_win.h"
41 #include "chrome/app/exit_code_watcher_win.h"
42 #include "chrome/app/main_dll_loader_win.h"
43 #include "chrome/app/packed_resources_integrity.h"
44 #include "chrome/browser/policy/policy_path_parser.h"
45 #include "chrome/browser/win/chrome_process_finder.h"
46 #include "chrome/chrome_elf/chrome_elf_main.h"
47 #include "chrome/common/chrome_paths_internal.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chrome/install_static/initialize_from_primary_module.h"
50 #include "chrome/install_static/install_util.h"
51 #include "chrome/install_static/user_data_dir.h"
52 #include "components/crash/core/app/crash_switches.h"
53 #include "components/crash/core/app/crashpad.h"
54 #include "components/crash/core/app/fallback_crash_handling_win.h"
55 #include "components/crash/core/app/run_as_crashpad_handler_win.h"
56 #include "content/public/common/content_switches.h"
57 #include "content/public/common/result_codes.h"
58 #include "third_party/crashpad/crashpad/util/win/initial_client_data.h"
59
60 #if defined(WIN_CONSOLE_APP)
61 // Forward declaration of main.
62 int main();
63 #endif
64
65 namespace {
66
67 // Sets the current working directory for the process to the directory holding
68 // the executable if this is the browser process. This avoids leaking a handle
69 // to an arbitrary directory to child processes (e.g., the crashpad handler
70 // process) created before MainDllLoader changes the current working directory
71 // to the browser's version directory.
72 void SetCwdForBrowserProcess() {
73   if (!::IsBrowserProcess())
74     return;
75
76   std::array<wchar_t, MAX_PATH + 1> buffer;
77   buffer[0] = L'\0';
78   DWORD length = ::GetModuleFileName(nullptr, &buffer[0], buffer.size());
79   if (!length || length >= buffer.size())
80     return;
81
82   base::SetCurrentDirectory(
83       base::FilePath(base::FilePath::StringPieceType(&buffer[0], length))
84           .DirName());
85 }
86
87 bool IsFastStartSwitch(const std::string& command_line_switch) {
88   return command_line_switch == switches::kProfileDirectory;
89 }
90
91 bool ContainsNonFastStartFlag(const base::CommandLine& command_line) {
92   const base::CommandLine::SwitchMap& switches = command_line.GetSwitches();
93   if (switches.size() > 1)
94     return true;
95   for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
96        it != switches.end(); ++it) {
97     if (!IsFastStartSwitch(it->first))
98       return true;
99   }
100   return false;
101 }
102
103 bool AttemptFastNotify(const base::CommandLine& command_line) {
104   if (ContainsNonFastStartFlag(command_line))
105     return false;
106
107   base::FilePath user_data_dir;
108   if (!chrome::GetDefaultUserDataDirectory(&user_data_dir))
109     return false;
110   policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
111
112   HWND chrome = chrome::FindRunningChromeWindow(user_data_dir);
113   if (!chrome)
114     return false;
115   return chrome::AttemptToNotifyRunningChrome(chrome) == chrome::NOTIFY_SUCCESS;
116 }
117
118 // Returns true if |command_line| contains a /prefetch:# argument where # is in
119 // [1, 8].
120 bool HasValidWindowsPrefetchArgument(const base::CommandLine& command_line) {
121   const wchar_t kPrefetchArgumentPrefix[] = L"/prefetch:";
122
123   for (const auto& arg : command_line.argv()) {
124     if (arg.size() == std::size(kPrefetchArgumentPrefix) &&
125         base::StartsWith(arg, kPrefetchArgumentPrefix,
126                          base::CompareCase::SENSITIVE)) {
127       return arg[std::size(kPrefetchArgumentPrefix) - 1] >= L'1' &&
128              arg[std::size(kPrefetchArgumentPrefix) - 1] <= L'8';
129     }
130   }
131   return false;
132 }
133
134 // Some users are getting stuck in compatibility mode. Try to help them escape.
135 // See http://crbug.com/581499. Returns true if a compatibility mode entry was
136 // removed.
137 bool RemoveAppCompatFlagsEntry() {
138   base::FilePath current_exe;
139   if (!base::PathService::Get(base::FILE_EXE, &current_exe))
140     return false;
141   if (!current_exe.IsAbsolute())
142     return false;
143   base::win::RegKey key;
144   if (key.Open(HKEY_CURRENT_USER,
145                L"Software\\Microsoft\\Windows "
146                L"NT\\CurrentVersion\\AppCompatFlags\\Layers",
147                KEY_READ | KEY_WRITE) == ERROR_SUCCESS) {
148     std::wstring layers;
149     if (key.ReadValue(current_exe.value().c_str(), &layers) == ERROR_SUCCESS) {
150       std::vector<std::wstring> tokens = base::SplitString(
151           layers, L" ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
152       size_t initial_size = tokens.size();
153       static const wchar_t* const kCompatModeTokens[] = {
154           L"WIN95",       L"WIN98",       L"WIN4SP5",  L"WIN2000",  L"WINXPSP2",
155           L"WINXPSP3",    L"VISTARTM",    L"VISTASP1", L"VISTASP2", L"WIN7RTM",
156           L"WINSRV03SP1", L"WINSRV08SP1", L"WIN8RTM",
157       };
158       for (const wchar_t* compat_mode_token : kCompatModeTokens) {
159         base::Erase(tokens, compat_mode_token);
160       }
161       LONG result;
162       if (tokens.empty()) {
163         result = key.DeleteValue(current_exe.value().c_str());
164       } else {
165         std::wstring without_compat_mode_tokens =
166             base::JoinString(tokens, L" ");
167         result = key.WriteValue(current_exe.value().c_str(),
168                                 without_compat_mode_tokens.c_str());
169       }
170
171       // Return if we changed anything so that we can restart.
172       return tokens.size() != initial_size && result == ERROR_SUCCESS;
173     }
174   }
175   return false;
176 }
177
178 int RunFallbackCrashHandler(const base::CommandLine& cmd_line) {
179   // Retrieve the product & version details we need to report the crash
180   // correctly.
181   wchar_t exe_file[MAX_PATH] = {};
182   CHECK(::GetModuleFileName(nullptr, exe_file, std::size(exe_file)));
183
184   std::wstring product_name, version, channel_name, special_build;
185   install_static::GetExecutableVersionDetails(exe_file, &product_name, &version,
186                                               &special_build, &channel_name);
187
188   return crash_reporter::RunAsFallbackCrashHandler(
189       cmd_line, base::WideToUTF8(product_name), base::WideToUTF8(version),
190       base::WideToUTF8(channel_name));
191 }
192
193 // In 32-bit builds, the main thread starts with the default (small) stack size.
194 // The ARCH_CPU_32_BITS blocks here and below are in support of moving the main
195 // thread to a fiber with a larger stack size.
196 #if defined(ARCH_CPU_32_BITS)
197 // The information needed to transfer control to the large-stack fiber and later
198 // pass the main routine's exit code back to the small-stack fiber prior to
199 // termination.
200 struct FiberState {
201   HINSTANCE instance;
202   LPVOID original_fiber;
203   int fiber_result;
204 };
205
206 // A PFIBER_START_ROUTINE function run on a large-stack fiber that calls the
207 // main routine, stores its return value, and returns control to the small-stack
208 // fiber. |params| must be a pointer to a FiberState struct.
209 void WINAPI FiberBinder(void* params) {
210   auto* fiber_state = static_cast<FiberState*>(params);
211   // Call the main routine from the fiber. Reusing the entry point minimizes
212   // confusion when examining call stacks in crash reports - seeing wWinMain on
213   // the stack is a handy hint that this is the main thread of the process.
214 #if !defined(WIN_CONSOLE_APP)
215   fiber_state->fiber_result =
216       wWinMain(fiber_state->instance, nullptr, nullptr, 0);
217 #else   // !defined(WIN_CONSOLE_APP)
218   fiber_state->fiber_result = main();
219 #endif  // !defined(WIN_CONSOLE_APP)
220   // Switch back to the main thread to exit.
221   ::SwitchToFiber(fiber_state->original_fiber);
222 }
223 #endif  // defined(ARCH_CPU_32_BITS)
224
225 }  // namespace
226
227 __declspec(dllexport) __cdecl void GetPakFileHashes(
228     const uint8_t** resources_pak,
229     const uint8_t** chrome_100_pak,
230     const uint8_t** chrome_200_pak) {
231   *resources_pak = kSha256_resources_pak.data();
232   *chrome_100_pak = kSha256_chrome_100_percent_pak.data();
233   *chrome_200_pak = kSha256_chrome_200_percent_pak.data();
234 }
235
236 #if !defined(WIN_CONSOLE_APP)
237 int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
238 #else   // !defined(WIN_CONSOLE_APP)
239 int main() {
240   HINSTANCE instance = GetModuleHandle(nullptr);
241 #endif  // !defined(WIN_CONSOLE_APP)
242
243 #if defined(ARCH_CPU_32_BITS)
244   enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess };
245   FiberStatus fiber_status = FiberStatus::kSuccess;
246   // GetLastError result if fiber conversion failed.
247   DWORD fiber_error = ERROR_SUCCESS;
248   if (!::IsThreadAFiber()) {
249     // Make the main thread's stack size 4 MiB so that it has roughly the same
250     // effective size as the 64-bit build's 8 MiB stack.
251     constexpr size_t kStackSize = 4 * 1024 * 1024;  // 4 MiB
252     // Leak the fiber on exit.
253     LPVOID original_fiber =
254         ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
255     if (original_fiber) {
256       FiberState fiber_state = {instance, original_fiber};
257       // Create a fiber with a bigger stack and switch to it. Leak the fiber on
258       // exit.
259       LPVOID big_stack_fiber = ::CreateFiberEx(
260           0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state);
261       if (big_stack_fiber) {
262         ::SwitchToFiber(big_stack_fiber);
263         // The fibers must be cleaned up to avoid obscure TLS-related shutdown
264         // crashes.
265         ::DeleteFiber(big_stack_fiber);
266         ::ConvertFiberToThread();
267         // Control returns here after Chrome has finished running on FiberMain.
268         return fiber_state.fiber_result;
269       }
270       fiber_status = FiberStatus::kCreateFiberFailed;
271     } else {
272       fiber_status = FiberStatus::kConvertFailed;
273     }
274     // If we reach here then creating and switching to a fiber has failed. This
275     // probably means we are low on memory and will soon crash. Try to report
276     // this error once crash reporting is initialized.
277     fiber_error = ::GetLastError();
278     base::debug::Alias(&fiber_error);
279   }
280   // If we are already a fiber then continue normal execution.
281 #endif  // defined(ARCH_CPU_32_BITS)
282
283   SetCwdForBrowserProcess();
284   install_static::InitializeFromPrimaryModule();
285   SignalInitializeCrashReporting();
286   if (IsBrowserProcess())
287     chrome::DisableDelayLoadFailureHooksForMainExecutable();
288 #if defined(ARCH_CPU_32_BITS)
289   // Intentionally crash if converting to a fiber failed.
290   CHECK_EQ(fiber_status, FiberStatus::kSuccess);
291 #endif  // defined(ARCH_CPU_32_BITS)
292
293   // Done here to ensure that OOMs that happen early in process initialization
294   // are correctly signaled to the OS.
295   base::EnableTerminationOnOutOfMemory();
296
297   // Initialize the CommandLine singleton from the environment.
298   base::CommandLine::Init(0, nullptr);
299   const base::CommandLine* command_line =
300       base::CommandLine::ForCurrentProcess();
301
302   const std::string process_type =
303       command_line->GetSwitchValueASCII(switches::kProcessType);
304
305 #if !defined(COMPONENT_BUILD) && DCHECK_IS_ON()
306   // In non-component mode, chrome.exe contains its own base::FeatureList
307   // instance pointer, which remains nullptr. Attempts to access feature state
308   // from chrome.exe should fail, instead of silently returning a default state.
309   base::FeatureList::FailOnFeatureAccessWithoutFeatureList();
310
311   // Patch the main EXE on non-component builds when DCHECKs are enabled.
312   // This allows detection of third party code that might attempt to meddle with
313   // Chrome's handles. This must be done when single-threaded to avoid other
314   // threads attempting to make calls through the hooks while they are being
315   // emplaced.
316   // Note: The DLL is patched separately, in chrome/app/chrome_main.cc.
317   base::debug::HandleHooks::AddIATPatch(CURRENT_MODULE());
318 #endif  // !defined(COMPONENT_BUILD) && DCHECK_IS_ON()
319
320   // Confirm that an explicit prefetch profile is used for all process types
321   // except for the browser process. Any new process type will have to assign
322   // itself a prefetch id. See kPrefetchArgument* constants in
323   // content_switches.cc for details.
324   DCHECK(process_type.empty() ||
325          HasValidWindowsPrefetchArgument(*command_line));
326
327   if (process_type == crash_reporter::switches::kCrashpadHandler) {
328     // Check if we should monitor the exit code of this process
329     std::unique_ptr<ExitCodeWatcher> exit_code_watcher;
330
331     crash_reporter::SetupFallbackCrashHandling(*command_line);
332     // no-periodic-tasks is specified for self monitoring crashpad instances.
333     // This is to ensure we are a crashpad process monitoring the browser
334     // process and not another crashpad process.
335     if (!command_line->HasSwitch("no-periodic-tasks")) {
336       // Retrieve the client process from the command line
337       crashpad::InitialClientData initial_client_data;
338       if (initial_client_data.InitializeFromString(
339               command_line->GetSwitchValueASCII("initial-client-data"))) {
340         // Setup exit code watcher to monitor the parent process
341         HANDLE duplicate_handle = INVALID_HANDLE_VALUE;
342         if (DuplicateHandle(
343                 ::GetCurrentProcess(), initial_client_data.client_process(),
344                 ::GetCurrentProcess(), &duplicate_handle,
345                 PROCESS_QUERY_INFORMATION, FALSE, DUPLICATE_SAME_ACCESS)) {
346           base::Process parent_process(duplicate_handle);
347           exit_code_watcher = std::make_unique<ExitCodeWatcher>();
348           if (exit_code_watcher->Initialize(std::move(parent_process))) {
349             exit_code_watcher->StartWatching();
350           }
351         }
352       }
353     }
354
355     // The handler process must always be passed the user data dir on the
356     // command line.
357     DCHECK(command_line->HasSwitch(switches::kUserDataDir));
358
359     base::FilePath user_data_dir =
360         command_line->GetSwitchValuePath(switches::kUserDataDir);
361     int crashpad_status = crash_reporter::RunAsCrashpadHandler(
362         *base::CommandLine::ForCurrentProcess(), user_data_dir,
363         switches::kProcessType, switches::kUserDataDir);
364     if (crashpad_status != 0 && exit_code_watcher) {
365       // Crashpad failed to initialize, explicitly stop the exit code watcher
366       // so the crashpad-handler process can exit with an error
367       exit_code_watcher->StopWatching();
368     }
369     return crashpad_status;
370   } else if (process_type == crash_reporter::switches::kFallbackCrashHandler) {
371     return RunFallbackCrashHandler(*command_line);
372   }
373
374   const base::TimeTicks exe_entry_point_ticks = base::TimeTicks::Now();
375
376   // Signal Chrome Elf that Chrome has begun to start.
377   SignalChromeElf();
378
379   // The exit manager is in charge of calling the dtors of singletons.
380   base::AtExitManager exit_manager;
381
382   if (AttemptFastNotify(*command_line))
383     return 0;
384
385   RemoveAppCompatFlagsEntry();
386
387   // Load and launch the chrome dll. *Everything* happens inside.
388   VLOG(1) << "About to load main DLL.";
389   MainDllLoader* loader = MakeMainDllLoader();
390   int rc = loader->Launch(instance, exe_entry_point_ticks);
391   loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded();
392   delete loader;
393
394   // Process shutdown is hard and some process types have been crashing during
395   // shutdown. TerminateCurrentProcessImmediately is safer and faster.
396   if (process_type == switches::kUtilityProcess ||
397       process_type == switches::kPpapiPluginProcess) {
398     base::Process::TerminateCurrentProcessImmediately(rc);
399   }
400   return rc;
401 }