- add sources.
[platform/framework/web/crosswalk.git] / src / content / shell / browser / shell_content_browser_client.cc
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.
4
5 #include "content/shell/browser/shell_content_browser_client.h"
6
7 #include "base/base_switches.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/path_service.h"
11 #include "content/public/browser/notification_service.h"
12 #include "content/public/browser/notification_types.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"
33 #include "url/gurl.h"
34 #include "webkit/common/webpreferences.h"
35
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"
41 #endif
42
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"
49 #endif
50
51 namespace content {
52
53 namespace {
54
55 ShellContentBrowserClient* g_browser_client;
56 bool g_swap_processes_for_redirect = false;
57
58 #if defined(OS_POSIX) && !defined(OS_MACOSX)
59 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
60     const std::string& process_type) {
61   base::FilePath dumps_path =
62       CommandLine::ForCurrentProcess()->GetSwitchValuePath(
63           switches::kCrashDumpsDir);
64   {
65     ANNOTATE_SCOPED_MEMORY_LEAK;
66     breakpad::CrashHandlerHostLinux* crash_handler =
67         new breakpad::CrashHandlerHostLinux(
68             process_type, dumps_path, false);
69     crash_handler->StartUploaderThread();
70     return crash_handler;
71   }
72 }
73
74 int GetCrashSignalFD(const CommandLine& command_line) {
75   if (!breakpad::IsCrashReporterEnabled())
76     return -1;
77
78   std::string process_type =
79       command_line.GetSwitchValueASCII(switches::kProcessType);
80
81   if (process_type == switches::kRendererProcess) {
82     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
83     if (!crash_handler)
84       crash_handler = CreateCrashHandlerHost(process_type);
85     return crash_handler->GetDeathSignalSocket();
86   }
87
88   if (process_type == switches::kPluginProcess) {
89     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
90     if (!crash_handler)
91       crash_handler = CreateCrashHandlerHost(process_type);
92     return crash_handler->GetDeathSignalSocket();
93   }
94
95   if (process_type == switches::kPpapiPluginProcess) {
96     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
97     if (!crash_handler)
98       crash_handler = CreateCrashHandlerHost(process_type);
99     return crash_handler->GetDeathSignalSocket();
100   }
101
102   if (process_type == switches::kGpuProcess) {
103     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
104     if (!crash_handler)
105       crash_handler = CreateCrashHandlerHost(process_type);
106     return crash_handler->GetDeathSignalSocket();
107   }
108
109   return -1;
110 }
111 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
112
113 }  // namespace
114
115 ShellContentBrowserClient* ShellContentBrowserClient::Get() {
116   return g_browser_client;
117 }
118
119 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
120   g_swap_processes_for_redirect = swap;
121 }
122
123 ShellContentBrowserClient::ShellContentBrowserClient()
124     : shell_browser_main_parts_(NULL) {
125   DCHECK(!g_browser_client);
126   g_browser_client = this;
127   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
128     return;
129   webkit_source_dir_ = GetWebKitRootDirFilePath();
130 }
131
132 ShellContentBrowserClient::~ShellContentBrowserClient() {
133   g_browser_client = NULL;
134 }
135
136 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
137     const MainFunctionParams& parameters) {
138   shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
139   return shell_browser_main_parts_;
140 }
141
142 void ShellContentBrowserClient::RenderProcessHostCreated(
143     RenderProcessHost* host) {
144   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
145     return;
146   host->AddFilter(new ShellMessageFilter(
147       host->GetID(),
148       BrowserContext::GetDefaultStoragePartition(browser_context())
149           ->GetDatabaseTracker(),
150       BrowserContext::GetDefaultStoragePartition(browser_context())
151           ->GetQuotaManager(),
152       BrowserContext::GetDefaultStoragePartition(browser_context())
153           ->GetURLRequestContext()));
154   host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
155   registrar_.Add(this,
156                  NOTIFICATION_RENDERER_PROCESS_CREATED,
157                  Source<RenderProcessHost>(host));
158   registrar_.Add(this,
159                  NOTIFICATION_RENDERER_PROCESS_TERMINATED,
160                  Source<RenderProcessHost>(host));
161 }
162
163 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
164     BrowserContext* content_browser_context,
165     ProtocolHandlerMap* protocol_handlers) {
166   ShellBrowserContext* shell_browser_context =
167       ShellBrowserContextForBrowserContext(content_browser_context);
168   return shell_browser_context->CreateRequestContext(protocol_handlers);
169 }
170
171 net::URLRequestContextGetter*
172 ShellContentBrowserClient::CreateRequestContextForStoragePartition(
173     BrowserContext* content_browser_context,
174     const base::FilePath& partition_path,
175     bool in_memory,
176     ProtocolHandlerMap* protocol_handlers) {
177   ShellBrowserContext* shell_browser_context =
178       ShellBrowserContextForBrowserContext(content_browser_context);
179   return shell_browser_context->CreateRequestContextForStoragePartition(
180       partition_path, in_memory, protocol_handlers);
181 }
182
183 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
184   if (!url.is_valid())
185     return false;
186   DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme()));
187   // Keep in sync with ProtocolHandlers added by
188   // ShellURLRequestContextGetter::GetURLRequestContext().
189   static const char* const kProtocolList[] = {
190       chrome::kBlobScheme,
191       chrome::kFileSystemScheme,
192       chrome::kChromeUIScheme,
193       chrome::kChromeDevToolsScheme,
194       chrome::kDataScheme,
195       chrome::kFileScheme,
196   };
197   for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
198     if (url.scheme() == kProtocolList[i])
199       return true;
200   }
201   return false;
202 }
203
204 void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
205     CommandLine* command_line, int child_process_id) {
206   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
207     command_line->AppendSwitch(switches::kDumpRenderTree);
208   if (CommandLine::ForCurrentProcess()->HasSwitch(
209       switches::kExposeInternalsForTesting))
210     command_line->AppendSwitch(switches::kExposeInternalsForTesting);
211   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode))
212     command_line->AppendSwitch(switches::kStableReleaseMode);
213   if (CommandLine::ForCurrentProcess()->HasSwitch(
214           switches::kEnableCrashReporter)) {
215     command_line->AppendSwitch(switches::kEnableCrashReporter);
216   }
217   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) {
218     command_line->AppendSwitchPath(
219         switches::kCrashDumpsDir,
220         CommandLine::ForCurrentProcess()->GetSwitchValuePath(
221             switches::kCrashDumpsDir));
222   }
223 }
224
225 void ShellContentBrowserClient::OverrideWebkitPrefs(
226     RenderViewHost* render_view_host,
227     const GURL& url,
228     WebPreferences* prefs) {
229   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
230     return;
231   WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
232 }
233
234 void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
235   resource_dispatcher_host_delegate_.reset(
236       new ShellResourceDispatcherHostDelegate());
237   ResourceDispatcherHost::Get()->SetDelegate(
238       resource_dispatcher_host_delegate_.get());
239 }
240
241 std::string ShellContentBrowserClient::GetDefaultDownloadName() {
242   return "download";
243 }
244
245 bool ShellContentBrowserClient::SupportsBrowserPlugin(
246     content::BrowserContext* browser_context, const GURL& url) {
247   return CommandLine::ForCurrentProcess()->HasSwitch(
248       switches::kEnableBrowserPluginForAllViewTypes);
249 }
250
251 WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
252     WebContents* web_contents) {
253 #if !defined(USE_AURA)
254   return CreateShellWebContentsViewDelegate(web_contents);
255 #else
256   return NULL;
257 #endif
258 }
259
260 QuotaPermissionContext*
261 ShellContentBrowserClient::CreateQuotaPermissionContext() {
262   return new ShellQuotaPermissionContext();
263 }
264
265 SpeechRecognitionManagerDelegate*
266     ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
267   return new ShellSpeechRecognitionManagerDelegate();
268 }
269
270 net::NetLog* ShellContentBrowserClient::GetNetLog() {
271   return shell_browser_main_parts_->net_log();
272 }
273
274 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
275     ResourceContext* resource_context,
276     const GURL& current_url,
277     const GURL& new_url) {
278   return g_swap_processes_for_redirect;
279 }
280
281 #if defined(OS_POSIX) && !defined(OS_MACOSX)
282 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
283     const CommandLine& command_line,
284     int child_process_id,
285     std::vector<content::FileDescriptorInfo>* mappings) {
286 #if defined(OS_ANDROID)
287   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
288   base::FilePath pak_file;
289   bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
290   CHECK(r);
291   pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
292   pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
293
294   base::PlatformFile f =
295       base::CreatePlatformFile(pak_file, flags, NULL, NULL);
296   if (f == base::kInvalidPlatformFileValue) {
297     NOTREACHED() << "Failed to open file when creating renderer process: "
298                  << "content_shell.pak";
299   }
300   mappings->push_back(
301       content::FileDescriptorInfo(kShellPakDescriptor,
302                                   base::FileDescriptor(f, true)));
303
304   if (breakpad::IsCrashReporterEnabled()) {
305     f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
306         child_process_id);
307     if (f == base::kInvalidPlatformFileValue) {
308       LOG(ERROR) << "Failed to create file for minidump, crash reporting will "
309                  << "be disabled for this process.";
310     } else {
311       mappings->push_back(FileDescriptorInfo(kAndroidMinidumpDescriptor,
312                                              base::FileDescriptor(f, true)));
313     }
314   }
315 #else  // !defined(OS_ANDROID)
316   int crash_signal_fd = GetCrashSignalFD(command_line);
317   if (crash_signal_fd >= 0) {
318     mappings->push_back(FileDescriptorInfo(
319         kCrashDumpSignal, base::FileDescriptor(crash_signal_fd, false)));
320   }
321 #endif  // defined(OS_ANDROID)
322 }
323 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
324
325 void ShellContentBrowserClient::Observe(int type,
326                                         const NotificationSource& source,
327                                         const NotificationDetails& details) {
328   switch (type) {
329     case NOTIFICATION_RENDERER_PROCESS_CREATED: {
330       registrar_.Remove(this,
331                         NOTIFICATION_RENDERER_PROCESS_CREATED,
332                         source);
333       registrar_.Remove(this,
334                         NOTIFICATION_RENDERER_PROCESS_TERMINATED,
335                         source);
336       break;
337     }
338
339     case NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
340       registrar_.Remove(this,
341                         NOTIFICATION_RENDERER_PROCESS_CREATED,
342                         source);
343       registrar_.Remove(this,
344                         NOTIFICATION_RENDERER_PROCESS_TERMINATED,
345                         source);
346       break;
347     }
348
349     default:
350       NOTREACHED();
351   }
352 }
353
354 ShellBrowserContext* ShellContentBrowserClient::browser_context() {
355   return shell_browser_main_parts_->browser_context();
356 }
357
358 ShellBrowserContext*
359     ShellContentBrowserClient::off_the_record_browser_context() {
360   return shell_browser_main_parts_->off_the_record_browser_context();
361 }
362
363 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
364   return new ShellAccessTokenStore(browser_context());
365 }
366
367 ShellBrowserContext*
368 ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
369     BrowserContext* content_browser_context) {
370   if (content_browser_context == browser_context())
371     return browser_context();
372   DCHECK_EQ(content_browser_context, off_the_record_browser_context());
373   return off_the_record_browser_context();
374 }
375
376 }  // namespace content