1 // Copyright 2013 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 "content/shell/browser/shell_content_browser_client.h"
7 #include "base/base_switches.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/file.h"
11 #include "base/path_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/resource_dispatcher_host.h"
15 #include "content/public/browser/storage_partition.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/common/url_constants.h"
18 #include "content/shell/browser/shell.h"
19 #include "content/shell/browser/shell_browser_context.h"
20 #include "content/shell/browser/shell_browser_main_parts.h"
21 #include "content/shell/browser/shell_devtools_delegate.h"
22 #include "content/shell/browser/shell_message_filter.h"
23 #include "content/shell/browser/shell_net_log.h"
24 #include "content/shell/browser/shell_quota_permission_context.h"
25 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
26 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
27 #include "content/shell/browser/webkit_test_controller.h"
28 #include "content/shell/common/shell_messages.h"
29 #include "content/shell/common/shell_switches.h"
30 #include "content/shell/common/webkit_test_helpers.h"
31 #include "content/shell/geolocation/shell_access_token_store.h"
32 #include "net/url_request/url_request_context_getter.h"
34 #include "webkit/common/webpreferences.h"
36 #if defined(OS_ANDROID)
37 #include "base/android/path_utils.h"
38 #include "base/path_service.h"
39 #include "components/breakpad/browser/crash_dump_manager_android.h"
40 #include "content/shell/android/shell_descriptors.h"
43 #if defined(OS_POSIX) && !defined(OS_MACOSX)
44 #include "base/debug/leak_annotations.h"
45 #include "base/platform_file.h"
46 #include "components/breakpad/app/breakpad_linux.h"
47 #include "components/breakpad/browser/crash_handler_host_linux.h"
48 #include "content/public/common/content_descriptors.h"
52 #include "content/common/sandbox_win.h"
53 #include "sandbox/win/src/sandbox.h"
60 ShellContentBrowserClient
* g_browser_client
;
61 bool g_swap_processes_for_redirect
= false;
63 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
64 breakpad::CrashHandlerHostLinux
* CreateCrashHandlerHost(
65 const std::string
& process_type
) {
66 base::FilePath dumps_path
=
67 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
68 switches::kCrashDumpsDir
);
70 ANNOTATE_SCOPED_MEMORY_LEAK
;
71 breakpad::CrashHandlerHostLinux
* crash_handler
=
72 new breakpad::CrashHandlerHostLinux(
73 process_type
, dumps_path
, false);
74 crash_handler
->StartUploaderThread();
79 int GetCrashSignalFD(const CommandLine
& command_line
) {
80 if (!breakpad::IsCrashReporterEnabled())
83 std::string process_type
=
84 command_line
.GetSwitchValueASCII(switches::kProcessType
);
86 if (process_type
== switches::kRendererProcess
) {
87 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
89 crash_handler
= CreateCrashHandlerHost(process_type
);
90 return crash_handler
->GetDeathSignalSocket();
93 if (process_type
== switches::kPluginProcess
) {
94 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
96 crash_handler
= CreateCrashHandlerHost(process_type
);
97 return crash_handler
->GetDeathSignalSocket();
100 if (process_type
== switches::kPpapiPluginProcess
) {
101 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
103 crash_handler
= CreateCrashHandlerHost(process_type
);
104 return crash_handler
->GetDeathSignalSocket();
107 if (process_type
== switches::kGpuProcess
) {
108 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
110 crash_handler
= CreateCrashHandlerHost(process_type
);
111 return crash_handler
->GetDeathSignalSocket();
116 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
120 ShellContentBrowserClient
* ShellContentBrowserClient::Get() {
121 return g_browser_client
;
124 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap
) {
125 g_swap_processes_for_redirect
= swap
;
128 ShellContentBrowserClient::ShellContentBrowserClient()
129 : shell_browser_main_parts_(NULL
) {
130 DCHECK(!g_browser_client
);
131 g_browser_client
= this;
132 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
134 webkit_source_dir_
= GetWebKitRootDirFilePath();
137 ShellContentBrowserClient::~ShellContentBrowserClient() {
138 g_browser_client
= NULL
;
141 BrowserMainParts
* ShellContentBrowserClient::CreateBrowserMainParts(
142 const MainFunctionParams
& parameters
) {
143 shell_browser_main_parts_
= new ShellBrowserMainParts(parameters
);
144 return shell_browser_main_parts_
;
147 void ShellContentBrowserClient::RenderProcessWillLaunch(
148 RenderProcessHost
* host
) {
149 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
151 host
->AddFilter(new ShellMessageFilter(
153 BrowserContext::GetDefaultStoragePartition(browser_context())
154 ->GetDatabaseTracker(),
155 BrowserContext::GetDefaultStoragePartition(browser_context())
157 BrowserContext::GetDefaultStoragePartition(browser_context())
158 ->GetURLRequestContext()));
159 host
->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_
));
162 net::URLRequestContextGetter
* ShellContentBrowserClient::CreateRequestContext(
163 BrowserContext
* content_browser_context
,
164 ProtocolHandlerMap
* protocol_handlers
,
165 ProtocolHandlerScopedVector protocol_interceptors
) {
166 ShellBrowserContext
* shell_browser_context
=
167 ShellBrowserContextForBrowserContext(content_browser_context
);
168 return shell_browser_context
->CreateRequestContext(
169 protocol_handlers
, protocol_interceptors
.Pass());
172 net::URLRequestContextGetter
*
173 ShellContentBrowserClient::CreateRequestContextForStoragePartition(
174 BrowserContext
* content_browser_context
,
175 const base::FilePath
& partition_path
,
177 ProtocolHandlerMap
* protocol_handlers
,
178 ProtocolHandlerScopedVector protocol_interceptors
) {
179 ShellBrowserContext
* shell_browser_context
=
180 ShellBrowserContextForBrowserContext(content_browser_context
);
181 return shell_browser_context
->CreateRequestContextForStoragePartition(
185 protocol_interceptors
.Pass());
188 bool ShellContentBrowserClient::IsHandledURL(const GURL
& url
) {
191 DCHECK_EQ(url
.scheme(), StringToLowerASCII(url
.scheme()));
192 // Keep in sync with ProtocolHandlers added by
193 // ShellURLRequestContextGetter::GetURLRequestContext().
194 static const char* const kProtocolList
[] = {
198 kChromeDevToolsScheme
,
202 for (size_t i
= 0; i
< arraysize(kProtocolList
); ++i
) {
203 if (url
.scheme() == kProtocolList
[i
])
209 void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
210 CommandLine
* command_line
, int child_process_id
) {
211 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
212 command_line
->AppendSwitch(switches::kDumpRenderTree
);
213 if (CommandLine::ForCurrentProcess()->HasSwitch(
214 switches::kEnableFontSmoothing
))
215 command_line
->AppendSwitch(switches::kEnableFontSmoothing
);
216 if (CommandLine::ForCurrentProcess()->HasSwitch(
217 switches::kExposeInternalsForTesting
))
218 command_line
->AppendSwitch(switches::kExposeInternalsForTesting
);
219 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode
))
220 command_line
->AppendSwitch(switches::kStableReleaseMode
);
221 if (CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kEnableCrashReporter
)) {
223 command_line
->AppendSwitch(switches::kEnableCrashReporter
);
225 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir
)) {
226 command_line
->AppendSwitchPath(
227 switches::kCrashDumpsDir
,
228 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
229 switches::kCrashDumpsDir
));
231 if (CommandLine::ForCurrentProcess()->HasSwitch(
232 switches::kEnableLeakDetection
))
233 command_line
->AppendSwitch(switches::kEnableLeakDetection
);
234 if (CommandLine::ForCurrentProcess()->HasSwitch(
235 switches::kRegisterFontFiles
)) {
236 command_line
->AppendSwitchASCII(
237 switches::kRegisterFontFiles
,
238 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
239 switches::kRegisterFontFiles
));
243 void ShellContentBrowserClient::OverrideWebkitPrefs(
244 RenderViewHost
* render_view_host
,
246 WebPreferences
* prefs
) {
247 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree
))
249 WebKitTestController::Get()->OverrideWebkitPrefs(prefs
);
252 void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
253 resource_dispatcher_host_delegate_
.reset(
254 new ShellResourceDispatcherHostDelegate());
255 ResourceDispatcherHost::Get()->SetDelegate(
256 resource_dispatcher_host_delegate_
.get());
259 std::string
ShellContentBrowserClient::GetDefaultDownloadName() {
263 WebContentsViewDelegate
* ShellContentBrowserClient::GetWebContentsViewDelegate(
264 WebContents
* web_contents
) {
265 #if !defined(USE_AURA)
266 return CreateShellWebContentsViewDelegate(web_contents
);
272 QuotaPermissionContext
*
273 ShellContentBrowserClient::CreateQuotaPermissionContext() {
274 return new ShellQuotaPermissionContext();
277 SpeechRecognitionManagerDelegate
*
278 ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
279 return new ShellSpeechRecognitionManagerDelegate();
282 net::NetLog
* ShellContentBrowserClient::GetNetLog() {
283 return shell_browser_main_parts_
->net_log();
286 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
287 ResourceContext
* resource_context
,
288 const GURL
& current_url
,
289 const GURL
& new_url
) {
290 return g_swap_processes_for_redirect
;
293 #if defined(OS_POSIX) && !defined(OS_MACOSX)
294 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
295 const CommandLine
& command_line
,
296 int child_process_id
,
297 std::vector
<content::FileDescriptorInfo
>* mappings
) {
298 #if defined(OS_ANDROID)
299 int flags
= base::PLATFORM_FILE_OPEN
| base::PLATFORM_FILE_READ
;
300 base::FilePath pak_file
;
301 bool r
= PathService::Get(base::DIR_ANDROID_APP_DATA
, &pak_file
);
303 pak_file
= pak_file
.Append(FILE_PATH_LITERAL("paks"));
304 pak_file
= pak_file
.Append(FILE_PATH_LITERAL("content_shell.pak"));
306 base::File
f(pak_file
, flags
);
308 NOTREACHED() << "Failed to open file when creating renderer process: "
309 << "content_shell.pak";
312 content::FileDescriptorInfo(kShellPakDescriptor
,
313 base::FileDescriptor(f
.Pass())));
315 if (breakpad::IsCrashReporterEnabled()) {
316 f
= breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
319 LOG(ERROR
) << "Failed to create file for minidump, crash reporting will "
320 << "be disabled for this process.";
323 FileDescriptorInfo(kAndroidMinidumpDescriptor
,
324 base::FileDescriptor(f
.Pass())));
327 #else // !defined(OS_ANDROID)
328 int crash_signal_fd
= GetCrashSignalFD(command_line
);
329 if (crash_signal_fd
>= 0) {
330 mappings
->push_back(FileDescriptorInfo(
331 kCrashDumpSignal
, base::FileDescriptor(crash_signal_fd
, false)));
333 #endif // defined(OS_ANDROID)
335 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
338 void ShellContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy
* policy
,
340 // Add sideloaded font files for testing. See also DIR_WINDOWS_FONTS
341 // addition in |StartSandboxedProcess|.
342 std::vector
<std::string
> font_files
= GetSideloadFontFiles();
343 for (std::vector
<std::string
>::const_iterator
i(font_files
.begin());
344 i
!= font_files
.end();
346 policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
,
347 sandbox::TargetPolicy::FILES_ALLOW_READONLY
,
348 base::UTF8ToWide(*i
).c_str());
353 ShellBrowserContext
* ShellContentBrowserClient::browser_context() {
354 return shell_browser_main_parts_
->browser_context();
358 ShellContentBrowserClient::off_the_record_browser_context() {
359 return shell_browser_main_parts_
->off_the_record_browser_context();
362 AccessTokenStore
* ShellContentBrowserClient::CreateAccessTokenStore() {
363 return new ShellAccessTokenStore(browser_context());
367 ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
368 BrowserContext
* content_browser_context
) {
369 if (content_browser_context
== browser_context())
370 return browser_context();
371 DCHECK_EQ(content_browser_context
, off_the_record_browser_context());
372 return off_the_record_browser_context();
375 } // namespace content