Home | History | Annotate | Download | only in browser
      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/render_process_host.h"
     12 #include "content/public/browser/resource_dispatcher_host.h"
     13 #include "content/public/browser/storage_partition.h"
     14 #include "content/public/common/content_switches.h"
     15 #include "content/public/common/url_constants.h"
     16 #include "content/shell/browser/shell.h"
     17 #include "content/shell/browser/shell_browser_context.h"
     18 #include "content/shell/browser/shell_browser_main_parts.h"
     19 #include "content/shell/browser/shell_devtools_delegate.h"
     20 #include "content/shell/browser/shell_message_filter.h"
     21 #include "content/shell/browser/shell_net_log.h"
     22 #include "content/shell/browser/shell_quota_permission_context.h"
     23 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
     24 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
     25 #include "content/shell/browser/webkit_test_controller.h"
     26 #include "content/shell/common/shell_messages.h"
     27 #include "content/shell/common/shell_switches.h"
     28 #include "content/shell/common/webkit_test_helpers.h"
     29 #include "content/shell/geolocation/shell_access_token_store.h"
     30 #include "net/url_request/url_request_context_getter.h"
     31 #include "url/gurl.h"
     32 #include "webkit/common/webpreferences.h"
     33 
     34 #if defined(OS_ANDROID)
     35 #include "base/android/path_utils.h"
     36 #include "base/path_service.h"
     37 #include "components/breakpad/browser/crash_dump_manager_android.h"
     38 #include "content/shell/android/shell_descriptors.h"
     39 #endif
     40 
     41 #if defined(OS_POSIX) && !defined(OS_MACOSX)
     42 #include "base/debug/leak_annotations.h"
     43 #include "base/platform_file.h"
     44 #include "components/breakpad/app/breakpad_linux.h"
     45 #include "components/breakpad/browser/crash_handler_host_linux.h"
     46 #include "content/public/common/content_descriptors.h"
     47 #endif
     48 
     49 namespace content {
     50 
     51 namespace {
     52 
     53 ShellContentBrowserClient* g_browser_client;
     54 bool g_swap_processes_for_redirect = false;
     55 
     56 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
     57 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
     58     const std::string& process_type) {
     59   base::FilePath dumps_path =
     60       CommandLine::ForCurrentProcess()->GetSwitchValuePath(
     61           switches::kCrashDumpsDir);
     62   {
     63     ANNOTATE_SCOPED_MEMORY_LEAK;
     64     breakpad::CrashHandlerHostLinux* crash_handler =
     65         new breakpad::CrashHandlerHostLinux(
     66             process_type, dumps_path, false);
     67     crash_handler->StartUploaderThread();
     68     return crash_handler;
     69   }
     70 }
     71 
     72 int GetCrashSignalFD(const CommandLine& command_line) {
     73   if (!breakpad::IsCrashReporterEnabled())
     74     return -1;
     75 
     76   std::string process_type =
     77       command_line.GetSwitchValueASCII(switches::kProcessType);
     78 
     79   if (process_type == switches::kRendererProcess) {
     80     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
     81     if (!crash_handler)
     82       crash_handler = CreateCrashHandlerHost(process_type);
     83     return crash_handler->GetDeathSignalSocket();
     84   }
     85 
     86   if (process_type == switches::kPluginProcess) {
     87     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
     88     if (!crash_handler)
     89       crash_handler = CreateCrashHandlerHost(process_type);
     90     return crash_handler->GetDeathSignalSocket();
     91   }
     92 
     93   if (process_type == switches::kPpapiPluginProcess) {
     94     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
     95     if (!crash_handler)
     96       crash_handler = CreateCrashHandlerHost(process_type);
     97     return crash_handler->GetDeathSignalSocket();
     98   }
     99 
    100   if (process_type == switches::kGpuProcess) {
    101     static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
    102     if (!crash_handler)
    103       crash_handler = CreateCrashHandlerHost(process_type);
    104     return crash_handler->GetDeathSignalSocket();
    105   }
    106 
    107   return -1;
    108 }
    109 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
    110 
    111 }  // namespace
    112 
    113 ShellContentBrowserClient* ShellContentBrowserClient::Get() {
    114   return g_browser_client;
    115 }
    116 
    117 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
    118   g_swap_processes_for_redirect = swap;
    119 }
    120 
    121 ShellContentBrowserClient::ShellContentBrowserClient()
    122     : shell_browser_main_parts_(NULL) {
    123   DCHECK(!g_browser_client);
    124   g_browser_client = this;
    125   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    126     return;
    127   webkit_source_dir_ = GetWebKitRootDirFilePath();
    128 }
    129 
    130 ShellContentBrowserClient::~ShellContentBrowserClient() {
    131   g_browser_client = NULL;
    132 }
    133 
    134 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
    135     const MainFunctionParams& parameters) {
    136   shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
    137   return shell_browser_main_parts_;
    138 }
    139 
    140 void ShellContentBrowserClient::RenderProcessHostCreated(
    141     RenderProcessHost* host) {
    142   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    143     return;
    144   host->AddFilter(new ShellMessageFilter(
    145       host->GetID(),
    146       BrowserContext::GetDefaultStoragePartition(browser_context())
    147           ->GetDatabaseTracker(),
    148       BrowserContext::GetDefaultStoragePartition(browser_context())
    149           ->GetQuotaManager(),
    150       BrowserContext::GetDefaultStoragePartition(browser_context())
    151           ->GetURLRequestContext()));
    152   host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
    153 }
    154 
    155 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
    156     BrowserContext* content_browser_context,
    157     ProtocolHandlerMap* protocol_handlers) {
    158   ShellBrowserContext* shell_browser_context =
    159       ShellBrowserContextForBrowserContext(content_browser_context);
    160   return shell_browser_context->CreateRequestContext(protocol_handlers);
    161 }
    162 
    163 net::URLRequestContextGetter*
    164 ShellContentBrowserClient::CreateRequestContextForStoragePartition(
    165     BrowserContext* content_browser_context,
    166     const base::FilePath& partition_path,
    167     bool in_memory,
    168     ProtocolHandlerMap* protocol_handlers) {
    169   ShellBrowserContext* shell_browser_context =
    170       ShellBrowserContextForBrowserContext(content_browser_context);
    171   return shell_browser_context->CreateRequestContextForStoragePartition(
    172       partition_path, in_memory, protocol_handlers);
    173 }
    174 
    175 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
    176   if (!url.is_valid())
    177     return false;
    178   DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme()));
    179   // Keep in sync with ProtocolHandlers added by
    180   // ShellURLRequestContextGetter::GetURLRequestContext().
    181   static const char* const kProtocolList[] = {
    182       chrome::kBlobScheme,
    183       chrome::kFileSystemScheme,
    184       chrome::kChromeUIScheme,
    185       chrome::kChromeDevToolsScheme,
    186       chrome::kDataScheme,
    187       chrome::kFileScheme,
    188   };
    189   for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
    190     if (url.scheme() == kProtocolList[i])
    191       return true;
    192   }
    193   return false;
    194 }
    195 
    196 void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
    197     CommandLine* command_line, int child_process_id) {
    198   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    199     command_line->AppendSwitch(switches::kDumpRenderTree);
    200   if (CommandLine::ForCurrentProcess()->HasSwitch(
    201       switches::kExposeInternalsForTesting))
    202     command_line->AppendSwitch(switches::kExposeInternalsForTesting);
    203   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode))
    204     command_line->AppendSwitch(switches::kStableReleaseMode);
    205   if (CommandLine::ForCurrentProcess()->HasSwitch(
    206           switches::kEnableCrashReporter)) {
    207     command_line->AppendSwitch(switches::kEnableCrashReporter);
    208   }
    209   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) {
    210     command_line->AppendSwitchPath(
    211         switches::kCrashDumpsDir,
    212         CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    213             switches::kCrashDumpsDir));
    214   }
    215 }
    216 
    217 void ShellContentBrowserClient::OverrideWebkitPrefs(
    218     RenderViewHost* render_view_host,
    219     const GURL& url,
    220     WebPreferences* prefs) {
    221   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
    222     return;
    223   WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
    224 }
    225 
    226 void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
    227   resource_dispatcher_host_delegate_.reset(
    228       new ShellResourceDispatcherHostDelegate());
    229   ResourceDispatcherHost::Get()->SetDelegate(
    230       resource_dispatcher_host_delegate_.get());
    231 }
    232 
    233 std::string ShellContentBrowserClient::GetDefaultDownloadName() {
    234   return "download";
    235 }
    236 
    237 bool ShellContentBrowserClient::SupportsBrowserPlugin(
    238     content::BrowserContext* browser_context, const GURL& url) {
    239   return CommandLine::ForCurrentProcess()->HasSwitch(
    240       switches::kEnableBrowserPluginForAllViewTypes);
    241 }
    242 
    243 WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
    244     WebContents* web_contents) {
    245 #if !defined(USE_AURA)
    246   return CreateShellWebContentsViewDelegate(web_contents);
    247 #else
    248   return NULL;
    249 #endif
    250 }
    251 
    252 QuotaPermissionContext*
    253 ShellContentBrowserClient::CreateQuotaPermissionContext() {
    254   return new ShellQuotaPermissionContext();
    255 }
    256 
    257 SpeechRecognitionManagerDelegate*
    258     ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
    259   return new ShellSpeechRecognitionManagerDelegate();
    260 }
    261 
    262 net::NetLog* ShellContentBrowserClient::GetNetLog() {
    263   return shell_browser_main_parts_->net_log();
    264 }
    265 
    266 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
    267     ResourceContext* resource_context,
    268     const GURL& current_url,
    269     const GURL& new_url) {
    270   return g_swap_processes_for_redirect;
    271 }
    272 
    273 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    274 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
    275     const CommandLine& command_line,
    276     int child_process_id,
    277     std::vector<content::FileDescriptorInfo>* mappings) {
    278 #if defined(OS_ANDROID)
    279   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
    280   base::FilePath pak_file;
    281   bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
    282   CHECK(r);
    283   pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
    284   pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
    285 
    286   base::PlatformFile f =
    287       base::CreatePlatformFile(pak_file, flags, NULL, NULL);
    288   if (f == base::kInvalidPlatformFileValue) {
    289     NOTREACHED() << "Failed to open file when creating renderer process: "
    290                  << "content_shell.pak";
    291   }
    292   mappings->push_back(
    293       content::FileDescriptorInfo(kShellPakDescriptor,
    294                                   base::FileDescriptor(f, true)));
    295 
    296   if (breakpad::IsCrashReporterEnabled()) {
    297     f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
    298         child_process_id);
    299     if (f == base::kInvalidPlatformFileValue) {
    300       LOG(ERROR) << "Failed to create file for minidump, crash reporting will "
    301                  << "be disabled for this process.";
    302     } else {
    303       mappings->push_back(FileDescriptorInfo(kAndroidMinidumpDescriptor,
    304                                              base::FileDescriptor(f, true)));
    305     }
    306   }
    307 #else  // !defined(OS_ANDROID)
    308   int crash_signal_fd = GetCrashSignalFD(command_line);
    309   if (crash_signal_fd >= 0) {
    310     mappings->push_back(FileDescriptorInfo(
    311         kCrashDumpSignal, base::FileDescriptor(crash_signal_fd, false)));
    312   }
    313 #endif  // defined(OS_ANDROID)
    314 }
    315 #endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
    316 
    317 ShellBrowserContext* ShellContentBrowserClient::browser_context() {
    318   return shell_browser_main_parts_->browser_context();
    319 }
    320 
    321 ShellBrowserContext*
    322     ShellContentBrowserClient::off_the_record_browser_context() {
    323   return shell_browser_main_parts_->off_the_record_browser_context();
    324 }
    325 
    326 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
    327   return new ShellAccessTokenStore(browser_context());
    328 }
    329 
    330 ShellBrowserContext*
    331 ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
    332     BrowserContext* content_browser_context) {
    333   if (content_browser_context == browser_context())
    334     return browser_context();
    335   DCHECK_EQ(content_browser_context, off_the_record_browser_context());
    336   return off_the_record_browser_context();
    337 }
    338 
    339 }  // namespace content
    340