// Copyright (c) 2013 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include "shell/app/electron_main_delegate.h" #include #include #include #if defined(OS_LINUX) #include // for g_setenv() #endif #include "base/command_line.h" #include "base/debug/stack_trace.h" #include "base/environment.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/path_service.h" #include "chrome/common/chrome_paths.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "content/public/common/content_switches.h" #include "electron/buildflags/buildflags.h" #include "extensions/common/constants.h" #include "ipc/ipc_buildflags.h" #include "services/service_manager/embedder/switches.h" #include "services/service_manager/sandbox/switches.h" #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" #include "shell/app/electron_content_client.h" #include "shell/browser/electron_browser_client.h" #include "shell/browser/electron_gpu_client.h" #include "shell/browser/feature_list.h" #include "shell/browser/relauncher.h" #include "shell/common/options_switches.h" #include "shell/renderer/electron_renderer_client.h" #include "shell/renderer/electron_sandboxed_renderer_client.h" #include "shell/utility/electron_content_utility_client.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" #if defined(OS_MACOSX) #include "shell/app/electron_main_delegate_mac.h" #endif #if defined(OS_WIN) #include "base/win/win_util.h" #if defined(_WIN64) #include "shell/common/crash_reporter/crash_reporter_win.h" #endif #endif namespace electron { namespace { const char* kRelauncherProcess = "relauncher"; bool IsBrowserProcess(base::CommandLine* cmd) { std::string process_type = cmd->GetSwitchValueASCII(::switches::kProcessType); return process_type.empty(); } bool IsSandboxEnabled(base::CommandLine* command_line) { return command_line->HasSwitch(switches::kEnableSandbox) || !command_line->HasSwitch(service_manager::switches::kNoSandbox); } // Returns true if this subprocess type needs the ResourceBundle initialized // and resources loaded. bool SubprocessNeedsResourceBundle(const std::string& process_type) { return #if defined(OS_POSIX) && !defined(OS_MACOSX) // The zygote process opens the resources for the renderers. process_type == service_manager::switches::kZygoteProcess || #endif #if defined(OS_MACOSX) // Mac needs them too for scrollbar related images and for sandbox // profiles. process_type == ::switches::kPpapiPluginProcess || process_type == ::switches::kPpapiBrokerProcess || process_type == ::switches::kGpuProcess || #endif process_type == ::switches::kRendererProcess || process_type == ::switches::kUtilityProcess; } #if defined(OS_WIN) void InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) { // noop. } #endif } // namespace void LoadResourceBundle(const std::string& locale) { const bool initialized = ui::ResourceBundle::HasSharedInstance(); if (initialized) ui::ResourceBundle::CleanupSharedInstance(); // Load other resource files. base::FilePath pak_dir; #if defined(OS_MACOSX) pak_dir = base::mac::FrameworkBundlePath().Append(FILE_PATH_LITERAL("Resources")); #else base::PathService::Get(base::DIR_MODULE, &pak_dir); #endif ui::ResourceBundle::InitSharedInstanceWithLocale( locale, nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES); ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); bundle.ReloadLocaleResources(locale); bundle.AddDataPackFromPath(pak_dir.Append(FILE_PATH_LITERAL("resources.pak")), ui::SCALE_FACTOR_NONE); } ElectronMainDelegate::ElectronMainDelegate() = default; ElectronMainDelegate::~ElectronMainDelegate() = default; const char* const ElectronMainDelegate::kNonWildcardDomainNonPortSchemes[] = { extensions::kExtensionScheme}; const size_t ElectronMainDelegate::kNonWildcardDomainNonPortSchemesSize = base::size(kNonWildcardDomainNonPortSchemes); bool ElectronMainDelegate::BasicStartupComplete(int* exit_code) { auto* command_line = base::CommandLine::ForCurrentProcess(); logging::LoggingSettings settings; #if defined(OS_WIN) #if defined(_WIN64) crash_reporter::CrashReporterWin::SetUnhandledExceptionFilter(); #endif // On Windows the terminal returns immediately, so we add a new line to // prevent output in the same line as the prompt. if (IsBrowserProcess(command_line)) std::wcout << std::endl; #if defined(DEBUG) // Print logging to debug.log on Windows settings.logging_dest = logging::LOG_TO_ALL; base::FilePath log_filename; base::PathService::Get(base::DIR_EXE, &log_filename); log_filename = log_filename.AppendASCII("debug.log"); settings.log_file_path = log_filename.value().c_str(); settings.lock_log = logging::LOCK_LOG_FILE; settings.delete_old = logging::DELETE_OLD_LOG_FILE; #else settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; #endif // defined(DEBUG) #else // defined(OS_WIN) settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; #endif // !defined(OS_WIN) // Only enable logging when --enable-logging is specified. auto env = base::Environment::Create(); if (!command_line->HasSwitch(::switches::kEnableLogging) && !env->HasVar("ELECTRON_ENABLE_LOGGING")) { settings.logging_dest = logging::LOG_NONE; logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES); } logging::InitLogging(settings); // Logging with pid and timestamp. logging::SetLogItems(true, false, true, false); // Enable convient stack printing. This is enabled by default in non-official // builds. if (env->HasVar("ELECTRON_ENABLE_STACK_DUMPING")) base::debug::EnableInProcessStackDumping(); if (env->HasVar("ELECTRON_DISABLE_SANDBOX")) command_line->AppendSwitch(service_manager::switches::kNoSandbox); tracing_sampler_profiler_ = tracing::TracingSamplerProfiler::CreateOnMainThread(); chrome::RegisterPathProvider(); #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes( kNonWildcardDomainNonPortSchemes, kNonWildcardDomainNonPortSchemesSize); #endif #if defined(OS_MACOSX) OverrideChildProcessPath(); OverrideFrameworkBundlePath(); SetUpBundleOverrides(); #endif #if defined(OS_WIN) // Ignore invalid parameter errors. _set_invalid_parameter_handler(InvalidParameterHandler); // Disable the ActiveVerifier, which is used by Chrome to track possible // bugs, but no use in Electron. base::win::DisableHandleVerifier(); if (IsBrowserProcess(command_line)) base::win::PinUser32(); #endif #if defined(OS_LINUX) // Check for --no-sandbox parameter when running as root. if (getuid() == 0 && IsSandboxEnabled(command_line)) LOG(FATAL) << "Running as root without --" << service_manager::switches::kNoSandbox << " is not supported. See https://crbug.com/638180."; #endif #if defined(MAS_BUILD) // In MAS build we are using --disable-remote-core-animation. // // According to ccameron: // If you're running with --disable-remote-core-animation, you may want to // also run with --disable-gpu-memory-buffer-compositor-resources as well. // That flag makes it so we use regular GL textures instead of IOSurfaces // for compositor resources. IOSurfaces are very heavyweight to // create/destroy, but they can be displayed directly by CoreAnimation (and // --disable-remote-core-animation makes it so we don't use this property, // so they're just heavyweight with no upside). command_line->AppendSwitch( ::switches::kDisableGpuMemoryBufferCompositorResources); #endif content_client_ = std::make_unique(); SetContentClient(content_client_.get()); return false; } void ElectronMainDelegate::PostEarlyInitialization(bool is_running_tests) { std::string custom_locale; ui::ResourceBundle::InitSharedInstanceWithLocale( custom_locale, nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES); auto* cmd_line = base::CommandLine::ForCurrentProcess(); if (cmd_line->HasSwitch(::switches::kLang)) { const std::string locale = cmd_line->GetSwitchValueASCII(::switches::kLang); const base::FilePath locale_file_path = ui::ResourceBundle::GetSharedInstance().GetLocaleFilePath(locale); if (!locale_file_path.empty()) { custom_locale = locale; #if defined(OS_LINUX) /* When built with USE_GLIB, libcc's GetApplicationLocaleInternal() uses * glib's g_get_language_names(), which keys off of getenv("LC_ALL") */ g_setenv("LC_ALL", custom_locale.c_str(), TRUE); #endif } } #if defined(OS_MACOSX) if (custom_locale.empty()) l10n_util::OverrideLocaleWithCocoaLocale(); #endif LoadResourceBundle(custom_locale); ElectronBrowserClient::SetApplicationLocale( l10n_util::GetApplicationLocale(custom_locale)); } void ElectronMainDelegate::PreSandboxStartup() { auto* command_line = base::CommandLine::ForCurrentProcess(); std::string process_type = command_line->GetSwitchValueASCII(::switches::kProcessType); // Initialize ResourceBundle which handles files loaded from external // sources. The language should have been passed in to us from the // browser process as a command line flag. if (SubprocessNeedsResourceBundle(process_type)) { std::string locale = command_line->GetSwitchValueASCII(::switches::kLang); LoadResourceBundle(locale); } // Only append arguments for browser process. if (!IsBrowserProcess(command_line)) return; // Allow file:// URIs to read other file:// URIs by default. command_line->AppendSwitch(::switches::kAllowFileAccessFromFiles); #if defined(OS_MACOSX) // Enable AVFoundation. command_line->AppendSwitch("enable-avfoundation"); #endif } void ElectronMainDelegate::PreCreateMainMessageLoop() { // This is initialized early because the service manager reads some feature // flags and we need to make sure the feature list is initialized before the // service manager reads the features. InitializeFeatureList(); #if defined(OS_MACOSX) RegisterAtomCrApp(); #endif } content::ContentBrowserClient* ElectronMainDelegate::CreateContentBrowserClient() { browser_client_ = std::make_unique(); return browser_client_.get(); } content::ContentGpuClient* ElectronMainDelegate::CreateContentGpuClient() { gpu_client_ = std::make_unique(); return gpu_client_.get(); } content::ContentRendererClient* ElectronMainDelegate::CreateContentRendererClient() { auto* command_line = base::CommandLine::ForCurrentProcess(); if (IsSandboxEnabled(command_line)) { renderer_client_ = std::make_unique(); } else { renderer_client_ = std::make_unique(); } return renderer_client_.get(); } content::ContentUtilityClient* ElectronMainDelegate::CreateContentUtilityClient() { utility_client_ = std::make_unique(); return utility_client_.get(); } int ElectronMainDelegate::RunProcess( const std::string& process_type, const content::MainFunctionParams& main_function_params) { if (process_type == kRelauncherProcess) return relauncher::RelauncherMain(main_function_params); else return -1; } bool ElectronMainDelegate::ShouldCreateFeatureList() { return false; } bool ElectronMainDelegate::ShouldLockSchemeRegistry() { return false; } } // namespace electron