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. 4 5 #include "content/public/browser/browser_main_runner.h" 6 7 #include "base/allocator/allocator_shim.h" 8 #include "base/base_switches.h" 9 #include "base/command_line.h" 10 #include "base/debug/leak_annotations.h" 11 #include "base/debug/trace_event.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/metrics/statistics_recorder.h" 15 #include "content/browser/browser_main_loop.h" 16 #include "content/browser/browser_shutdown_profile_dumper.h" 17 #include "content/browser/notification_service_impl.h" 18 #include "content/public/common/content_switches.h" 19 #include "content/public/common/main_function_params.h" 20 #include "ui/base/ime/input_method_initializer.h" 21 22 #if defined(OS_WIN) 23 #include "base/win/win_util.h" 24 #include "base/win/windows_version.h" 25 #include "net/cert/sha256_legacy_support_win.h" 26 #include "sandbox/win/src/sidestep/preamble_patcher.h" 27 #include "ui/base/win/scoped_ole_initializer.h" 28 #endif 29 30 bool g_exited_main_message_loop = false; 31 32 namespace content { 33 34 #if defined(OS_WIN) 35 namespace { 36 37 // Pointer to the original CryptVerifyCertificateSignatureEx function. 38 net::sha256_interception::CryptVerifyCertificateSignatureExFunc 39 g_real_crypt_verify_signature_stub = NULL; 40 41 // Stub function that is called whenever the Crypt32 function 42 // CryptVerifyCertificateSignatureEx is called. It just defers to net to perform 43 // the actual verification. 44 BOOL WINAPI CryptVerifyCertificateSignatureExStub( 45 HCRYPTPROV_LEGACY provider, 46 DWORD encoding_type, 47 DWORD subject_type, 48 void* subject_data, 49 DWORD issuer_type, 50 void* issuer_data, 51 DWORD flags, 52 void* extra) { 53 return net::sha256_interception::CryptVerifyCertificateSignatureExHook( 54 g_real_crypt_verify_signature_stub, provider, encoding_type, subject_type, 55 subject_data, issuer_type, issuer_data, flags, extra); 56 } 57 58 // If necessary, install an interception 59 void InstallSha256LegacyHooks() { 60 #if defined(_WIN64) 61 // Interception on x64 is not supported. 62 return; 63 #else 64 if (base::win::MaybeHasSHA256Support()) 65 return; 66 67 net::sha256_interception::CryptVerifyCertificateSignatureExFunc 68 cert_verify_signature_ptr = reinterpret_cast< 69 net::sha256_interception::CryptVerifyCertificateSignatureExFunc>( 70 ::GetProcAddress(::GetModuleHandle(L"crypt32.dll"), 71 "CryptVerifyCertificateSignatureEx")); 72 CHECK(cert_verify_signature_ptr); 73 74 DWORD old_protect = 0; 75 if (!::VirtualProtect(cert_verify_signature_ptr, 5, PAGE_EXECUTE_READWRITE, 76 &old_protect)) { 77 return; 78 } 79 80 g_real_crypt_verify_signature_stub = 81 reinterpret_cast< 82 net::sha256_interception::CryptVerifyCertificateSignatureExFunc>( 83 VirtualAllocEx(::GetCurrentProcess(), NULL, 84 sidestep::kMaxPreambleStubSize, MEM_COMMIT, 85 PAGE_EXECUTE_READWRITE)); 86 if (g_real_crypt_verify_signature_stub == NULL) { 87 CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect, 88 &old_protect)); 89 return; 90 } 91 92 sidestep::SideStepError patch_result = 93 sidestep::PreamblePatcher::Patch( 94 cert_verify_signature_ptr, CryptVerifyCertificateSignatureExStub, 95 g_real_crypt_verify_signature_stub, sidestep::kMaxPreambleStubSize); 96 if (patch_result != sidestep::SIDESTEP_SUCCESS) { 97 CHECK(::VirtualFreeEx(::GetCurrentProcess(), 98 g_real_crypt_verify_signature_stub, 0, 99 MEM_RELEASE)); 100 CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect, 101 &old_protect)); 102 return; 103 } 104 105 DWORD dummy = 0; 106 CHECK(::VirtualProtect(cert_verify_signature_ptr, 5, old_protect, &dummy)); 107 CHECK(::VirtualProtect(g_real_crypt_verify_signature_stub, 108 sidestep::kMaxPreambleStubSize, old_protect, 109 &old_protect)); 110 #endif // _WIN64 111 } 112 113 } // namespace 114 115 #endif // OS_WIN 116 117 class BrowserMainRunnerImpl : public BrowserMainRunner { 118 public: 119 BrowserMainRunnerImpl() 120 : initialization_started_(false), is_shutdown_(false) {} 121 122 virtual ~BrowserMainRunnerImpl() { 123 if (initialization_started_ && !is_shutdown_) 124 Shutdown(); 125 } 126 127 virtual int Initialize(const MainFunctionParams& parameters) OVERRIDE { 128 TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize"); 129 // On Android we normally initialize the browser in a series of UI thread 130 // tasks. While this is happening a second request can come from the OS or 131 // another application to start the browser. If this happens then we must 132 // not run these parts of initialization twice. 133 if (!initialization_started_) { 134 initialization_started_ = true; 135 136 #if !defined(OS_IOS) 137 if (parameters.command_line.HasSwitch(switches::kWaitForDebugger)) 138 base::debug::WaitForDebugger(60, true); 139 #endif 140 141 #if defined(OS_WIN) 142 if (base::win::GetVersion() < base::win::VERSION_VISTA) { 143 // When "Extend support of advanced text services to all programs" 144 // (a.k.a. Cicero Unaware Application Support; CUAS) is enabled on 145 // Windows XP and handwriting modules shipped with Office 2003 are 146 // installed, "penjpn.dll" and "skchui.dll" will be loaded and then 147 // crash unless a user installs Office 2003 SP3. To prevent these 148 // modules from being loaded, disable TSF entirely. crbug.com/160914. 149 // TODO(yukawa): Add a high-level wrapper for this instead of calling 150 // Win32 API here directly. 151 ImmDisableTextFrameService(static_cast<DWORD>(-1)); 152 } 153 InstallSha256LegacyHooks(); 154 #endif // OS_WIN 155 156 base::StatisticsRecorder::Initialize(); 157 158 notification_service_.reset(new NotificationServiceImpl); 159 160 #if defined(OS_WIN) 161 // Ole must be initialized before starting message pump, so that TSF 162 // (Text Services Framework) module can interact with the message pump 163 // on Windows 8 Metro mode. 164 ole_initializer_.reset(new ui::ScopedOleInitializer); 165 #endif // OS_WIN 166 167 main_loop_.reset(new BrowserMainLoop(parameters)); 168 169 main_loop_->Init(); 170 171 main_loop_->EarlyInitialization(); 172 173 // Must happen before we try to use a message loop or display any UI. 174 if (!main_loop_->InitializeToolkit()) 175 return 1; 176 177 main_loop_->MainMessageLoopStart(); 178 179 // WARNING: If we get a WM_ENDSESSION, objects created on the stack here 180 // are NOT deleted. If you need something to run during WM_ENDSESSION add it 181 // to browser_shutdown::Shutdown or BrowserProcess::EndSession. 182 183 #if defined(OS_WIN) && !defined(NO_TCMALLOC) 184 // When linking shared libraries, NO_TCMALLOC is defined, and dynamic 185 // allocator selection is not supported. 186 187 // Make this call before going multithreaded, or spawning any 188 // subprocesses. 189 base::allocator::SetupSubprocessAllocator(); 190 #endif 191 ui::InitializeInputMethod(); 192 } 193 main_loop_->CreateStartupTasks(); 194 int result_code = main_loop_->GetResultCode(); 195 if (result_code > 0) 196 return result_code; 197 198 // Return -1 to indicate no early termination. 199 return -1; 200 } 201 202 virtual int Run() OVERRIDE { 203 DCHECK(initialization_started_); 204 DCHECK(!is_shutdown_); 205 main_loop_->RunMainMessageLoopParts(); 206 return main_loop_->GetResultCode(); 207 } 208 209 virtual void Shutdown() OVERRIDE { 210 DCHECK(initialization_started_); 211 DCHECK(!is_shutdown_); 212 #ifdef LEAK_SANITIZER 213 // Invoke leak detection now, to avoid dealing with shutdown-only leaks. 214 // Normally this will have already happened in 215 // BroserProcessImpl::ReleaseModule(), so this call has no effect. This is 216 // only for processes which do not instantiate a BrowserProcess. 217 // If leaks are found, the process will exit here. 218 __lsan_do_leak_check(); 219 #endif 220 // If startup tracing has not been finished yet, replace it's dumper 221 // with special version, which would save trace file on exit (i.e. 222 // startup tracing becomes a version of shutdown tracing). 223 scoped_ptr<BrowserShutdownProfileDumper> startup_profiler; 224 if (main_loop_->is_tracing_startup()) { 225 main_loop_->StopStartupTracingTimer(); 226 if (main_loop_->startup_trace_file() != 227 base::FilePath().AppendASCII("none")) { 228 startup_profiler.reset( 229 new BrowserShutdownProfileDumper(main_loop_->startup_trace_file())); 230 } 231 } 232 233 // The shutdown tracing got enabled in AttemptUserExit earlier, but someone 234 // needs to write the result to disc. For that a dumper needs to get created 235 // which will dump the traces to disc when it gets destroyed. 236 const base::CommandLine& command_line = 237 *base::CommandLine::ForCurrentProcess(); 238 scoped_ptr<BrowserShutdownProfileDumper> shutdown_profiler; 239 if (command_line.HasSwitch(switches::kTraceShutdown)) { 240 shutdown_profiler.reset(new BrowserShutdownProfileDumper( 241 BrowserShutdownProfileDumper::GetShutdownProfileFileName())); 242 } 243 244 { 245 // The trace event has to stay between profiler creation and destruction. 246 TRACE_EVENT0("shutdown", "BrowserMainRunner"); 247 g_exited_main_message_loop = true; 248 249 main_loop_->ShutdownThreadsAndCleanUp(); 250 251 ui::ShutdownInputMethod(); 252 #if defined(OS_WIN) 253 ole_initializer_.reset(NULL); 254 #endif 255 #if defined(OS_ANDROID) 256 // Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring 257 // proper shutdown for content_browsertests. Shutdown() is not used by 258 // the actual browser. 259 base::MessageLoop::current()->QuitNow(); 260 #endif 261 main_loop_.reset(NULL); 262 263 notification_service_.reset(NULL); 264 265 is_shutdown_ = true; 266 } 267 } 268 269 protected: 270 // True if we have started to initialize the runner. 271 bool initialization_started_; 272 273 // True if the runner has been shut down. 274 bool is_shutdown_; 275 276 scoped_ptr<NotificationServiceImpl> notification_service_; 277 scoped_ptr<BrowserMainLoop> main_loop_; 278 #if defined(OS_WIN) 279 scoped_ptr<ui::ScopedOleInitializer> ole_initializer_; 280 #endif 281 282 DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl); 283 }; 284 285 // static 286 BrowserMainRunner* BrowserMainRunner::Create() { 287 return new BrowserMainRunnerImpl(); 288 } 289 290 } // namespace content 291