1 // Copyright 2020 The Chromium Embedded Framework Authors.
2 // Portions copyright 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "libcef/common/chrome/chrome_main_delegate_cef.h"
7
8 #include "libcef/browser/chrome/chrome_browser_context.h"
9 #include "libcef/browser/chrome/chrome_content_browser_client_cef.h"
10 #include "libcef/common/cef_switches.h"
11 #include "libcef/common/command_line_impl.h"
12 #include "libcef/common/crash_reporting.h"
13 #include "libcef/common/resource_util.h"
14 #include "libcef/renderer/chrome/chrome_content_renderer_client_cef.h"
15
16 #include "base/command_line.h"
17 #include "base/lazy_instance.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "components/embedder_support/switches.h"
20 #include "content/public/common/content_switches.h"
21 #include "sandbox/policy/switches.h"
22 #include "ui/base/ui_base_switches.h"
23
24 #if defined(OS_MAC)
25 #include "libcef/common/util_mac.h"
26 #endif
27
28 namespace {
29
30 base::LazyInstance<ChromeContentRendererClientCef>::DestructorAtExit
31 g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
32
33 } // namespace
34
ChromeMainDelegateCef(CefMainRunnerHandler * runner,CefSettings * settings,CefRefPtr<CefApp> application)35 ChromeMainDelegateCef::ChromeMainDelegateCef(CefMainRunnerHandler* runner,
36 CefSettings* settings,
37 CefRefPtr<CefApp> application)
38 : ChromeMainDelegate(base::TimeTicks::Now()),
39 runner_(runner),
40 settings_(settings),
41 application_(application) {
42 #if defined(OS_LINUX)
43 resource_util::OverrideAssetPath();
44 #endif
45 }
46
47 ChromeMainDelegateCef::~ChromeMainDelegateCef() = default;
48
BasicStartupComplete(int * exit_code)49 bool ChromeMainDelegateCef::BasicStartupComplete(int* exit_code) {
50 // Returns false if startup should proceed.
51 bool result = ChromeMainDelegate::BasicStartupComplete(exit_code);
52 if (result)
53 return true;
54
55 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
56
57 #if defined(OS_POSIX)
58 // Read the crash configuration file. Platforms using Breakpad also add a
59 // command-line switch. On Windows this is done from chrome_elf.
60 crash_reporting::BasicStartupComplete(command_line);
61 #endif
62
63 const std::string& process_type =
64 command_line->GetSwitchValueASCII(switches::kProcessType);
65 if (process_type.empty()) {
66 // In the browser process. Populate the global command-line object.
67 // TODO(chrome-runtime): Copy more settings from AlloyMainDelegate and test.
68 if (settings_->command_line_args_disabled) {
69 // Remove any existing command-line arguments.
70 base::CommandLine::StringVector argv;
71 argv.push_back(command_line->GetProgram().value());
72 command_line->InitFromArgv(argv);
73
74 const base::CommandLine::SwitchMap& map = command_line->GetSwitches();
75 const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
76 }
77
78 bool no_sandbox = settings_->no_sandbox ? true : false;
79
80 if (no_sandbox) {
81 command_line->AppendSwitch(sandbox::policy::switches::kNoSandbox);
82 }
83
84 if (settings_->user_agent.length > 0) {
85 command_line->AppendSwitchASCII(embedder_support::kUserAgent,
86 CefString(&settings_->user_agent));
87 } else if (settings_->user_agent_product.length > 0) {
88 command_line->AppendSwitchASCII(
89 switches::kUserAgentProductAndVersion,
90 CefString(&settings_->user_agent_product));
91 }
92
93 if (settings_->locale.length > 0) {
94 command_line->AppendSwitchASCII(switches::kLang,
95 CefString(&settings_->locale));
96 } else if (!command_line->HasSwitch(switches::kLang)) {
97 command_line->AppendSwitchASCII(switches::kLang, "en-US");
98 }
99
100 if (settings_->javascript_flags.length > 0) {
101 command_line->AppendSwitchASCII(switches::kJavaScriptFlags,
102 CefString(&settings_->javascript_flags));
103 }
104
105 if (settings_->remote_debugging_port >= 1024 &&
106 settings_->remote_debugging_port <= 65535) {
107 command_line->AppendSwitchASCII(
108 switches::kRemoteDebuggingPort,
109 base::NumberToString(settings_->remote_debugging_port));
110 }
111
112 if (settings_->uncaught_exception_stack_size > 0) {
113 command_line->AppendSwitchASCII(
114 switches::kUncaughtExceptionStackSize,
115 base::NumberToString(settings_->uncaught_exception_stack_size));
116 }
117 }
118
119 if (application_) {
120 // Give the application a chance to view/modify the command line.
121 CefRefPtr<CefCommandLineImpl> commandLinePtr(
122 new CefCommandLineImpl(command_line, false, false));
123 application_->OnBeforeCommandLineProcessing(process_type,
124 commandLinePtr.get());
125 commandLinePtr->Detach(nullptr);
126 }
127
128 #if defined(OS_MAC)
129 util_mac::BasicStartupComplete();
130 #endif
131
132 return false;
133 }
134
PreSandboxStartup()135 void ChromeMainDelegateCef::PreSandboxStartup() {
136 const base::CommandLine* command_line =
137 base::CommandLine::ForCurrentProcess();
138 const std::string& process_type =
139 command_line->GetSwitchValueASCII(switches::kProcessType);
140
141 #if defined(OS_MAC)
142 if (process_type.empty()) {
143 util_mac::PreSandboxStartup();
144 }
145 #endif // defined(OS_MAC)
146
147 // Since this may be configured via CefSettings we override the value on
148 // all platforms. We can't use the default implementation on macOS because
149 // chrome::GetDefaultUserDataDirectory expects to find the Chromium version
150 // number in the app bundle path.
151 resource_util::OverrideUserDataDir(settings_, command_line);
152
153 ChromeMainDelegate::PreSandboxStartup();
154
155 // Initialize crash reporting state for this process/module.
156 // chrome::DIR_CRASH_DUMPS must be configured before calling this function.
157 crash_reporting::PreSandboxStartup(*command_line, process_type);
158 }
159
PreCreateMainMessageLoop()160 void ChromeMainDelegateCef::PreCreateMainMessageLoop() {
161 // The parent ChromeMainDelegate implementation creates the NSApplication
162 // instance on macOS, and we intentionally don't want to do that here.
163 // TODO(macos): Do we need l10n_util::OverrideLocaleWithCocoaLocale()?
164 runner_->PreCreateMainMessageLoop();
165 }
166
RunProcess(const std::string & process_type,const content::MainFunctionParams & main_function_params)167 int ChromeMainDelegateCef::RunProcess(
168 const std::string& process_type,
169 const content::MainFunctionParams& main_function_params) {
170 if (process_type.empty()) {
171 return runner_->RunMainProcess(main_function_params);
172 }
173
174 return ChromeMainDelegate::RunProcess(process_type, main_function_params);
175 }
176
177 #if defined(OS_LINUX)
ZygoteForked()178 void ChromeMainDelegateCef::ZygoteForked() {
179 ChromeMainDelegate::ZygoteForked();
180
181 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
182 const std::string& process_type =
183 command_line->GetSwitchValueASCII(switches::kProcessType);
184
185 // Initialize crash reporting state for the newly forked process.
186 crash_reporting::ZygoteForked(command_line, process_type);
187 }
188 #endif // defined(OS_LINUX)
189
CreateContentClient()190 content::ContentClient* ChromeMainDelegateCef::CreateContentClient() {
191 return &chrome_content_client_cef_;
192 }
193
194 content::ContentBrowserClient*
CreateContentBrowserClient()195 ChromeMainDelegateCef::CreateContentBrowserClient() {
196 // Match the logic in the parent ChromeMainDelegate implementation, but create
197 // our own object type.
198 chrome_content_browser_client_ =
199 std::make_unique<ChromeContentBrowserClientCef>();
200 return chrome_content_browser_client_.get();
201 }
202
203 content::ContentRendererClient*
CreateContentRendererClient()204 ChromeMainDelegateCef::CreateContentRendererClient() {
205 return g_chrome_content_renderer_client.Pointer();
206 }
207
GetGlobalRequestContext()208 CefRefPtr<CefRequestContext> ChromeMainDelegateCef::GetGlobalRequestContext() {
209 auto browser_client = content_browser_client();
210 if (browser_client)
211 return browser_client->request_context();
212 return nullptr;
213 }
214
CreateNewBrowserContext(const CefRequestContextSettings & settings,base::OnceClosure initialized_cb)215 CefBrowserContext* ChromeMainDelegateCef::CreateNewBrowserContext(
216 const CefRequestContextSettings& settings,
217 base::OnceClosure initialized_cb) {
218 auto context = new ChromeBrowserContext(settings);
219 context->InitializeAsync(std::move(initialized_cb));
220 return context;
221 }
222
223 scoped_refptr<base::SingleThreadTaskRunner>
GetBackgroundTaskRunner()224 ChromeMainDelegateCef::GetBackgroundTaskRunner() {
225 auto browser_client = content_browser_client();
226 if (browser_client)
227 return browser_client->background_task_runner();
228 return nullptr;
229 }
230
231 scoped_refptr<base::SingleThreadTaskRunner>
GetUserVisibleTaskRunner()232 ChromeMainDelegateCef::GetUserVisibleTaskRunner() {
233 auto browser_client = content_browser_client();
234 if (browser_client)
235 return browser_client->user_visible_task_runner();
236 return nullptr;
237 }
238
239 scoped_refptr<base::SingleThreadTaskRunner>
GetUserBlockingTaskRunner()240 ChromeMainDelegateCef::GetUserBlockingTaskRunner() {
241 auto browser_client = content_browser_client();
242 if (browser_client)
243 return browser_client->user_blocking_task_runner();
244 return nullptr;
245 }
246
247 scoped_refptr<base::SingleThreadTaskRunner>
GetRenderTaskRunner()248 ChromeMainDelegateCef::GetRenderTaskRunner() {
249 auto renderer_client = content_renderer_client();
250 if (renderer_client)
251 return renderer_client->render_task_runner();
252 return nullptr;
253 }
254
255 scoped_refptr<base::SingleThreadTaskRunner>
GetWebWorkerTaskRunner()256 ChromeMainDelegateCef::GetWebWorkerTaskRunner() {
257 auto renderer_client = content_renderer_client();
258 if (renderer_client)
259 return renderer_client->GetCurrentTaskRunner();
260 return nullptr;
261 }
262
content_browser_client() const263 ChromeContentBrowserClientCef* ChromeMainDelegateCef::content_browser_client()
264 const {
265 return static_cast<ChromeContentBrowserClientCef*>(
266 chrome_content_browser_client_.get());
267 }
268
content_renderer_client() const269 ChromeContentRendererClientCef* ChromeMainDelegateCef::content_renderer_client()
270 const {
271 if (!g_chrome_content_renderer_client.IsCreated())
272 return nullptr;
273 return g_chrome_content_renderer_client.Pointer();
274 }