1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/path_service.h"
7 #include "base/posix/global_descriptors.h"
8 #include "base/trace_event/trace_event.h"
9 #include "build/build_config.h"
10 #include "content/browser/child_process_launcher.h"
11 #include "content/browser/child_process_launcher_helper.h"
12 #include "content/browser/child_process_launcher_helper_posix.h"
13 #include "content/browser/sandbox_host_linux.h"
14 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
15 #include "content/common/zygote/zygote_communication_linux.h"
16 #include "content/public/browser/child_process_launcher_utils.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "content/public/common/content_client.h"
19 #include "content/public/common/content_constants.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/result_codes.h"
22 #include "content/public/common/sandboxed_process_launcher_delegate.h"
23 #include "content/public/common/zygote/sandbox_support_linux.h"
24 #include "content/public/common/zygote/zygote_handle.h"
25 #include "sandbox/policy/linux/sandbox_linux.h"
30 absl::optional<mojo::NamedPlatformChannel>
31 ChildProcessLauncherHelper::CreateNamedPlatformChannelOnLauncherThread() {
32 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
36 void ChildProcessLauncherHelper::BeforeLaunchOnClientThread() {
37 DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
40 std::unique_ptr<FileMappedForLaunch>
41 ChildProcessLauncherHelper::GetFilesToMap() {
42 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
43 return CreateDefaultPosixFilesToMap(
44 child_process_id(), mojo_channel_->remote_endpoint(),
45 file_data_->files_to_preload, GetProcessType(), command_line());
48 bool ChildProcessLauncherHelper::IsUsingLaunchOptions() {
49 return !GetZygoteForLaunch();
52 bool ChildProcessLauncherHelper::BeforeLaunchOnLauncherThread(
53 PosixFileDescriptorInfo& files_to_register,
54 base::LaunchOptions* options) {
56 DCHECK(!GetZygoteForLaunch());
57 // Convert FD mapping to FileHandleMappingVector
58 options->fds_to_remap = files_to_register.GetMappingWithIDAdjustment(
59 base::GlobalDescriptors::kBaseDescriptor);
61 if (GetProcessType() == switches::kRendererProcess) {
62 const int sandbox_fd = SandboxHostLinux::GetInstance()->GetChildSocket();
63 options->fds_to_remap.emplace_back(sandbox_fd, GetSandboxFD());
66 options->environment = delegate_->GetEnvironment();
68 DCHECK(GetZygoteForLaunch());
69 // Environment variables could be supported in the future, but are not
70 // currently supported when launching with the zygote.
71 DCHECK(delegate_->GetEnvironment().empty());
77 ChildProcessLauncherHelper::Process
78 ChildProcessLauncherHelper::LaunchProcessOnLauncherThread(
79 const base::LaunchOptions* options,
80 std::unique_ptr<FileMappedForLaunch> files_to_register,
81 bool* is_synchronous_launch,
83 *is_synchronous_launch = true;
85 ZygoteCommunication* zygote_handle = GetZygoteForLaunch();
86 #if BUILDFLAG(IS_TIZEN) && !BUILDFLAG(IS_TIZEN_TV)
87 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
88 switches::kSingleProcess))
89 zygote_handle = nullptr;
92 // TODO(crbug.com/569191): If chrome supported multiple zygotes they could
93 // be created lazily here, or in the delegate GetZygote() implementations.
94 // Additionally, the delegate could provide a UseGenericZygote() method.
95 base::ProcessHandle handle = zygote_handle->ForkRequest(
96 command_line()->argv(), files_to_register->GetMapping(),
98 *launch_result = LAUNCH_RESULT_SUCCESS;
100 #if !BUILDFLAG(IS_OPENBSD) && !BUILDFLAG(IS_TIZEN_TV)
102 // It could be a renderer process or an utility process.
103 int oom_score = content::kMiscOomScore;
104 if (command_line()->GetSwitchValueASCII(switches::kProcessType) ==
105 switches::kRendererProcess)
106 oom_score = content::kLowestRendererOomScore;
107 ZygoteHostImpl::GetInstance()->AdjustRendererOOMScore(handle, oom_score);
111 process.process = base::Process(handle);
112 process.zygote = zygote_handle;
114 process.process = base::LaunchProcess(*command_line(), *options);
115 *launch_result = process.process.IsValid() ? LAUNCH_RESULT_SUCCESS
116 : LAUNCH_RESULT_FAILURE;
119 #if BUILDFLAG(IS_CHROMEOS)
120 if (GetProcessType() == switches::kRendererProcess) {
121 process.process.InitializePriority();
128 void ChildProcessLauncherHelper::AfterLaunchOnLauncherThread(
129 const ChildProcessLauncherHelper::Process& process,
130 const base::LaunchOptions* options) {
131 // Reset any FDs still held open.
135 ChildProcessTerminationInfo ChildProcessLauncherHelper::GetTerminationInfo(
136 const ChildProcessLauncherHelper::Process& process,
138 ChildProcessTerminationInfo info;
139 if (process.zygote) {
140 info.status = process.zygote->GetTerminationStatus(
141 process.process.Handle(), known_dead, &info.exit_code);
142 } else if (known_dead) {
143 info.status = base::GetKnownDeadTerminationStatus(process.process.Handle(),
147 base::GetTerminationStatus(process.process.Handle(), &info.exit_code);
153 bool ChildProcessLauncherHelper::TerminateProcess(const base::Process& process,
155 // TODO(https://crbug.com/818244): Determine whether we should also call
156 // EnsureProcessTerminated() to make sure of process-exit, and reap it.
157 return process.Terminate(exit_code, false);
161 void ChildProcessLauncherHelper::ForceNormalProcessTerminationSync(
162 ChildProcessLauncherHelper::Process process) {
163 TRACE_EVENT0("chromeos",
164 "ChildProcessLauncherHelper::ForceNormalProcessTerminationSync");
165 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
166 process.process.Terminate(RESULT_CODE_NORMAL_EXIT, false);
167 // On POSIX, we must additionally reap the child.
168 if (process.zygote) {
169 // If the renderer was created via a zygote, we have to proxy the reaping
170 // through the zygote process.
171 process.zygote->EnsureProcessTerminated(process.process.Handle());
173 base::EnsureProcessTerminated(std::move(process.process));
177 void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread(
178 base::Process process,
179 base::Process::Priority priority) {
180 DCHECK(CurrentlyOnProcessLauncherTaskRunner());
181 if (process.CanSetPriority() && priority_ != priority) {
182 priority_ = priority;
183 process.SetPriority(priority);
187 ZygoteCommunication* ChildProcessLauncherHelper::GetZygoteForLaunch() {
188 return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote)
190 : delegate_->GetZygote();
193 base::File OpenFileToShare(const base::FilePath& path,
194 base::MemoryMappedFile::Region* region) {
195 base::FilePath exe_dir;
196 bool result = base::PathService::Get(base::BasePathKey::DIR_EXE, &exe_dir);
198 base::File file(exe_dir.Append(path),
199 base::File::FLAG_OPEN | base::File::FLAG_READ);
200 *region = base::MemoryMappedFile::Region::kWholeFile;
204 } // namespace internal
205 } // namespace content