no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / ipc / glue / ForkServiceChild.cpp
blob09d7c48457f99d3027aaf7a9ca1bbca348d0df97
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ForkServiceChild.h"
8 #include "ForkServer.h"
9 #include "mozilla/Atomics.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/ipc/GeckoChildProcessHost.h"
12 #include "mozilla/ipc/IPDLParamTraits.h"
13 #include "mozilla/ipc/ProtocolMessageUtils.h"
14 #include "mozilla/StaticPrefs_dom.h"
15 #include "mozilla/Services.h"
16 #include "ipc/IPCMessageUtilsSpecializations.h"
17 #include "nsIObserverService.h"
19 #include <unistd.h>
20 #include <fcntl.h>
22 namespace mozilla {
23 namespace ipc {
25 extern LazyLogModule gForkServiceLog;
27 mozilla::UniquePtr<ForkServiceChild> ForkServiceChild::sForkServiceChild;
28 Atomic<bool> ForkServiceChild::sForkServiceUsed;
30 static bool ConfigurePipeFd(int aFd) {
31 int flags = fcntl(aFd, F_GETFD, 0);
32 return flags != -1 && fcntl(aFd, F_SETFD, flags | FD_CLOEXEC) != -1;
35 void ForkServiceChild::StartForkServer() {
36 // Create the socket to use for communication, and mark both ends as
37 // FD_CLOEXEC.
38 int fds[2];
39 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
40 MOZ_LOG(gForkServiceLog, LogLevel::Error,
41 ("failed to create fork server socket"));
42 return;
44 UniqueFileHandle server(fds[0]);
45 UniqueFileHandle client(fds[1]);
47 if (!ConfigurePipeFd(server.get()) || !ConfigurePipeFd(client.get())) {
48 MOZ_LOG(gForkServiceLog, LogLevel::Error,
49 ("failed to configure fork server socket"));
50 return;
53 GeckoChildProcessHost* subprocess =
54 new GeckoChildProcessHost(GeckoProcessType_ForkServer, false);
55 subprocess->AddFdToRemap(client.get(), ForkServer::kClientPipeFd);
56 if (!subprocess->LaunchAndWaitForProcessHandle(std::vector<std::string>{})) {
57 MOZ_LOG(gForkServiceLog, LogLevel::Error, ("failed to launch fork server"));
58 return;
61 sForkServiceUsed = true;
62 sForkServiceChild =
63 mozilla::MakeUnique<ForkServiceChild>(server.release(), subprocess);
66 void ForkServiceChild::StopForkServer() { sForkServiceChild = nullptr; }
68 ForkServiceChild::ForkServiceChild(int aFd, GeckoChildProcessHost* aProcess)
69 : mFailed(false), mProcess(aProcess) {
70 mTcver = MakeUnique<MiniTransceiver>(aFd);
73 ForkServiceChild::~ForkServiceChild() {
74 mProcess->Destroy();
75 close(mTcver->GetFD());
78 Result<Ok, LaunchError> ForkServiceChild::SendForkNewSubprocess(
79 const Args& aArgs, pid_t* aPid) {
80 mRecvPid = -1;
81 IPC::Message msg(MSG_ROUTING_CONTROL, Msg_ForkNewSubprocess__ID);
83 IPC::MessageWriter writer(msg);
84 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
85 WriteIPDLParam(&writer, nullptr, aArgs.mForkFlags);
86 WriteIPDLParam(&writer, nullptr, aArgs.mChroot);
87 #endif
88 WriteIPDLParam(&writer, nullptr, aArgs.mArgv);
89 WriteIPDLParam(&writer, nullptr, aArgs.mEnv);
90 WriteIPDLParam(&writer, nullptr, aArgs.mFdsRemap);
91 if (!mTcver->Send(msg)) {
92 MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
93 ("the pipe to the fork server is closed or having errors"));
94 OnError();
95 return Err(LaunchError("FSC::SFNS::Send"));
98 UniquePtr<IPC::Message> reply;
99 if (!mTcver->Recv(reply)) {
100 MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
101 ("the pipe to the fork server is closed or having errors"));
102 OnError();
103 return Err(LaunchError("FSC::SFNS::Recv"));
105 OnMessageReceived(std::move(reply));
107 MOZ_ASSERT(mRecvPid != -1);
108 *aPid = mRecvPid;
109 return Ok();
112 void ForkServiceChild::OnMessageReceived(UniquePtr<IPC::Message> message) {
113 if (message->type() != Reply_ForkNewSubprocess__ID) {
114 MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
115 ("unknown reply type %d", message->type()));
116 return;
118 IPC::MessageReader reader(*message);
120 if (!ReadIPDLParam(&reader, nullptr, &mRecvPid)) {
121 MOZ_CRASH("Error deserializing 'pid_t'");
123 reader.EndRead();
126 void ForkServiceChild::OnError() {
127 mFailed = true;
128 ForkServerLauncher::RestartForkServer();
131 NS_IMPL_ISUPPORTS(ForkServerLauncher, nsIObserver)
133 bool ForkServerLauncher::mHaveStartedClient = false;
134 StaticRefPtr<ForkServerLauncher> ForkServerLauncher::mSingleton;
136 ForkServerLauncher::ForkServerLauncher() {}
138 ForkServerLauncher::~ForkServerLauncher() {}
140 already_AddRefed<ForkServerLauncher> ForkServerLauncher::Create() {
141 if (mSingleton == nullptr) {
142 mSingleton = new ForkServerLauncher();
144 RefPtr<ForkServerLauncher> launcher = mSingleton;
145 return launcher.forget();
148 NS_IMETHODIMP
149 ForkServerLauncher::Observe(nsISupports* aSubject, const char* aTopic,
150 const char16_t* aData) {
151 if (strcmp(aTopic, NS_XPCOM_STARTUP_CATEGORY) == 0) {
152 nsCOMPtr<nsIObserverService> obsSvc =
153 mozilla::services::GetObserverService();
154 MOZ_ASSERT(obsSvc != nullptr);
155 // preferences are not available until final-ui-startup
156 obsSvc->AddObserver(this, "final-ui-startup", false);
157 } else if (!mHaveStartedClient && strcmp(aTopic, "final-ui-startup") == 0) {
158 if (StaticPrefs::dom_ipc_forkserver_enable_AtStartup()) {
159 mHaveStartedClient = true;
160 ForkServiceChild::StartForkServer();
162 nsCOMPtr<nsIObserverService> obsSvc =
163 mozilla::services::GetObserverService();
164 MOZ_ASSERT(obsSvc != nullptr);
165 obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
166 } else {
167 mSingleton = nullptr;
171 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
172 if (mHaveStartedClient) {
173 mHaveStartedClient = false;
174 ForkServiceChild::StopForkServer();
177 // To make leak checker happy!
178 mSingleton = nullptr;
180 return NS_OK;
183 void ForkServerLauncher::RestartForkServer() {
184 // Restart fork server
185 NS_SUCCEEDED(NS_DispatchToMainThreadQueue(
186 NS_NewRunnableFunction("OnForkServerError",
187 [] {
188 if (mSingleton) {
189 ForkServiceChild::StopForkServer();
190 ForkServiceChild::StartForkServer();
193 EventQueuePriority::Idle));
196 } // namespace ipc
197 } // namespace mozilla