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