Home | History | Annotate | Download | only in app
      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/shell/app/shell_main_delegate.h"
      6 
      7 #include "base/base_switches.h"
      8 #include "base/command_line.h"
      9 #include "base/cpu.h"
     10 #include "base/files/file.h"
     11 #include "base/files/file_path.h"
     12 #include "base/lazy_instance.h"
     13 #include "base/logging.h"
     14 #include "base/path_service.h"
     15 #include "cc/base/switches.h"
     16 #include "content/public/browser/browser_main_runner.h"
     17 #include "content/public/common/content_switches.h"
     18 #include "content/public/common/url_constants.h"
     19 #include "content/public/test/layouttest_support.h"
     20 #include "content/shell/app/shell_breakpad_client.h"
     21 #include "content/shell/app/webkit_test_platform_support.h"
     22 #include "content/shell/browser/shell_browser_main.h"
     23 #include "content/shell/browser/shell_content_browser_client.h"
     24 #include "content/shell/common/shell_switches.h"
     25 #include "content/shell/renderer/shell_content_renderer_client.h"
     26 #include "net/cookies/cookie_monster.h"
     27 #include "ui/base/resource/resource_bundle.h"
     28 #include "ui/base/ui_base_paths.h"
     29 #include "ui/base/ui_base_switches.h"
     30 #include "ui/events/event_switches.h"
     31 #include "ui/gfx/switches.h"
     32 #include "ui/gl/gl_switches.h"
     33 
     34 #include "ipc/ipc_message.h"  // For IPC_MESSAGE_LOG_ENABLED.
     35 
     36 #if defined(IPC_MESSAGE_LOG_ENABLED)
     37 #define IPC_MESSAGE_MACROS_LOG_ENABLED
     38 #include "content/public/common/content_ipc_logging.h"
     39 #define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
     40     content::RegisterIPCLogger(msg_id, logger)
     41 #include "content/shell/common/shell_messages.h"
     42 #endif
     43 
     44 #if defined(OS_ANDROID)
     45 #include "base/posix/global_descriptors.h"
     46 #include "content/shell/android/shell_descriptors.h"
     47 #endif
     48 
     49 #if defined(OS_MACOSX)
     50 #include "base/mac/os_crash_dumps.h"
     51 #include "components/breakpad/app/breakpad_mac.h"
     52 #include "content/shell/app/paths_mac.h"
     53 #include "content/shell/app/shell_main_delegate_mac.h"
     54 #endif  // OS_MACOSX
     55 
     56 #if defined(OS_WIN)
     57 #include <initguid.h>
     58 #include <windows.h>
     59 #include "base/logging_win.h"
     60 #include "components/breakpad/app/breakpad_win.h"
     61 #endif
     62 
     63 #if defined(OS_POSIX) && !defined(OS_MACOSX)
     64 #include "components/breakpad/app/breakpad_linux.h"
     65 #endif
     66 
     67 namespace {
     68 
     69 base::LazyInstance<content::ShellBreakpadClient>::Leaky
     70     g_shell_breakpad_client = LAZY_INSTANCE_INITIALIZER;
     71 
     72 #if defined(OS_WIN)
     73 // If "Content Shell" doesn't show up in your list of trace providers in
     74 // Sawbuck, add these registry entries to your machine (NOTE the optional
     75 // Wow6432Node key for x64 machines):
     76 // 1. Find:  HKLM\SOFTWARE\[Wow6432Node\]Google\Sawbuck\Providers
     77 // 2. Add a subkey with the name "{6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}"
     78 // 3. Add these values:
     79 //    "default_flags"=dword:00000001
     80 //    "default_level"=dword:00000004
     81 //    @="Content Shell"
     82 
     83 // {6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}
     84 const GUID kContentShellProviderName = {
     85     0x6a3e50a4, 0x7e15, 0x4099,
     86         { 0x84, 0x13, 0xec, 0x94, 0xd8, 0xc2, 0xa4, 0xb6 } };
     87 #endif
     88 
     89 void InitLogging() {
     90   base::FilePath log_filename;
     91   PathService::Get(base::DIR_EXE, &log_filename);
     92   log_filename = log_filename.AppendASCII("content_shell.log");
     93   logging::LoggingSettings settings;
     94   settings.logging_dest = logging::LOG_TO_ALL;
     95   settings.log_file = log_filename.value().c_str();
     96   settings.delete_old = logging::DELETE_OLD_LOG_FILE;
     97   logging::InitLogging(settings);
     98   logging::SetLogItems(true, true, true, true);
     99 }
    100 
    101 }  // namespace
    102 
    103 namespace content {
    104 
    105 ShellMainDelegate::ShellMainDelegate() {
    106 }
    107 
    108 ShellMainDelegate::~ShellMainDelegate() {
    109 }
    110 
    111 bool ShellMainDelegate::BasicStartupComplete(int* exit_code) {
    112 #if defined(OS_WIN)
    113   // Enable trace control and transport through event tracing for Windows.
    114   logging::LogEventProvider::Initialize(kContentShellProviderName);
    115 #endif
    116 #if defined(OS_MACOSX)
    117   // Needs to happen before InitializeResourceBundle() and before
    118   // WebKitTestPlatformInitialize() are called.
    119   OverrideFrameworkBundlePath();
    120   OverrideChildProcessPath();
    121   EnsureCorrectResolutionSettings();
    122 #endif  // OS_MACOSX
    123 
    124   InitLogging();
    125   CommandLine& command_line = *CommandLine::ForCurrentProcess();
    126   if (command_line.HasSwitch(switches::kCheckLayoutTestSysDeps)) {
    127     if (!CheckLayoutSystemDeps()) {
    128       if (exit_code)
    129         *exit_code = 1;
    130       return true;
    131     }
    132   }
    133 
    134   if (command_line.HasSwitch(switches::kDumpRenderTree)) {
    135     EnableBrowserLayoutTestMode();
    136 
    137     command_line.AppendSwitch(switches::kProcessPerTab);
    138     command_line.AppendSwitch(switches::kEnableLogging);
    139     command_line.AppendSwitch(switches::kAllowFileAccessFromFiles);
    140     command_line.AppendSwitchASCII(switches::kUseGL,
    141                                    gfx::kGLImplementationOSMesaName);
    142     command_line.AppendSwitch(switches::kSkipGpuDataLoading);
    143     command_line.AppendSwitchASCII(switches::kTouchEvents,
    144                                    switches::kTouchEventsEnabled);
    145     command_line.AppendSwitch(switches::kEnableGestureTapHighlight);
    146     command_line.AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1.0");
    147 #if defined(OS_ANDROID)
    148     command_line.AppendSwitch(
    149         switches::kDisableGestureRequirementForMediaPlayback);
    150 #endif
    151 
    152     if (!command_line.HasSwitch(switches::kStableReleaseMode)) {
    153       command_line.AppendSwitch(
    154         switches::kEnableExperimentalWebPlatformFeatures);
    155     }
    156 
    157     if (!command_line.HasSwitch(switches::kEnableThreadedCompositing)) {
    158       command_line.AppendSwitch(switches::kDisableThreadedCompositing);
    159       command_line.AppendSwitch(cc::switches::kDisableThreadedAnimation);
    160     }
    161 
    162     command_line.AppendSwitch(switches::kEnableInbandTextTracks);
    163     command_line.AppendSwitch(switches::kMuteAudio);
    164 
    165 #if defined(USE_AURA) || defined(OS_ANDROID)
    166     // TODO: crbug.com/311404 Make layout tests work w/ delegated renderer.
    167     command_line.AppendSwitch(switches::kDisableDelegatedRenderer);
    168     command_line.AppendSwitch(cc::switches::kCompositeToMailbox);
    169 #endif
    170 
    171     command_line.AppendSwitch(switches::kEnableFileCookies);
    172 
    173     command_line.AppendSwitch(switches::kEnablePreciseMemoryInfo);
    174 
    175     // Unless/until WebM files are added to the media layout tests, we need to
    176     // avoid removing MP4/H264/AAC so that layout tests can run on Android.
    177 #if !defined(OS_ANDROID)
    178     net::RemoveProprietaryMediaTypesAndCodecsForTests();
    179 #endif
    180 
    181     if (!WebKitTestPlatformInitialize()) {
    182       if (exit_code)
    183         *exit_code = 1;
    184       return true;
    185     }
    186   }
    187   SetContentClient(&content_client_);
    188   return false;
    189 }
    190 
    191 void ShellMainDelegate::PreSandboxStartup() {
    192 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
    193   // Create an instance of the CPU class to parse /proc/cpuinfo and cache
    194   // cpu_brand info.
    195   base::CPU cpu_info;
    196 #endif
    197   if (CommandLine::ForCurrentProcess()->HasSwitch(
    198           switches::kEnableCrashReporter)) {
    199     std::string process_type =
    200         CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    201             switches::kProcessType);
    202     breakpad::SetBreakpadClient(g_shell_breakpad_client.Pointer());
    203 #if defined(OS_MACOSX)
    204     base::mac::DisableOSCrashDumps();
    205     breakpad::InitCrashReporter(process_type);
    206     breakpad::InitCrashProcessInfo(process_type);
    207 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
    208     if (process_type != switches::kZygoteProcess) {
    209 #if defined(OS_ANDROID)
    210       if (process_type.empty())
    211         breakpad::InitCrashReporter(process_type);
    212       else
    213         breakpad::InitNonBrowserCrashReporterForAndroid(process_type);
    214 #else
    215       breakpad::InitCrashReporter(process_type);
    216 #endif
    217     }
    218 #elif defined(OS_WIN)
    219     UINT new_flags =
    220         SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
    221     UINT existing_flags = SetErrorMode(new_flags);
    222     SetErrorMode(existing_flags | new_flags);
    223     breakpad::InitCrashReporter(process_type);
    224 #endif
    225   }
    226 
    227   InitializeResourceBundle();
    228 }
    229 
    230 int ShellMainDelegate::RunProcess(
    231     const std::string& process_type,
    232     const MainFunctionParams& main_function_params) {
    233   if (!process_type.empty())
    234     return -1;
    235 
    236 #if !defined(OS_ANDROID)
    237   // Android stores the BrowserMainRunner instance as a scoped member pointer
    238   // on the ShellMainDelegate class because of different object lifetime.
    239   scoped_ptr<BrowserMainRunner> browser_runner_;
    240 #endif
    241 
    242   browser_runner_.reset(BrowserMainRunner::Create());
    243   return ShellBrowserMain(main_function_params, browser_runner_);
    244 }
    245 
    246 #if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
    247 void ShellMainDelegate::ZygoteForked() {
    248   if (CommandLine::ForCurrentProcess()->HasSwitch(
    249           switches::kEnableCrashReporter)) {
    250     std::string process_type =
    251         CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    252             switches::kProcessType);
    253     breakpad::InitCrashReporter(process_type);
    254   }
    255 }
    256 #endif
    257 
    258 void ShellMainDelegate::InitializeResourceBundle() {
    259 #if defined(OS_ANDROID)
    260   // In the Android case, the renderer runs with a different UID and can never
    261   // access the file system.  So we are passed a file descriptor to the
    262   // ResourceBundle pak at launch time.
    263   int pak_fd =
    264       base::GlobalDescriptors::GetInstance()->MaybeGet(kShellPakDescriptor);
    265   if (pak_fd >= 0) {
    266     // This is clearly wrong. See crbug.com/330930
    267     ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
    268         base::File(pak_fd), base::MemoryMappedFile::Region::kWholeFile, false);
    269     ResourceBundle::GetSharedInstance().AddDataPackFromFile(
    270         base::File(pak_fd), ui::SCALE_FACTOR_100P);
    271     return;
    272   }
    273 #endif
    274 
    275   base::FilePath pak_file;
    276 #if defined(OS_MACOSX)
    277   pak_file = GetResourcesPakFilePath();
    278 #else
    279   base::FilePath pak_dir;
    280 
    281 #if defined(OS_ANDROID)
    282   bool got_path = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir);
    283   DCHECK(got_path);
    284   pak_dir = pak_dir.Append(FILE_PATH_LITERAL("paks"));
    285 #else
    286   PathService::Get(base::DIR_MODULE, &pak_dir);
    287 #endif
    288 
    289   pak_file = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
    290 #endif
    291   ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
    292 }
    293 
    294 ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {
    295   browser_client_.reset(new ShellContentBrowserClient);
    296   return browser_client_.get();
    297 }
    298 
    299 ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {
    300   renderer_client_.reset(new ShellContentRendererClient);
    301   return renderer_client_.get();
    302 }
    303 
    304 }  // namespace content
    305