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