Backed out 8 changesets (bug 1873776) for causing vendor failures. CLOSED TREE
[gecko.git] / ipc / glue / ProcessChild.cpp
blob724d2b09bf9047634807ecdde861098b8476381c
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 "mozilla/ipc/ProcessChild.h"
9 #include "Endpoint.h"
10 #include "nsDebug.h"
12 #ifdef XP_WIN
13 # include <stdlib.h> // for _exit()
14 # include <synchapi.h>
15 #else
16 # include <unistd.h> // for _exit()
17 # include <time.h>
18 # include "base/eintr_wrapper.h"
19 # include "prenv.h"
20 #endif
22 #include "nsAppRunner.h"
23 #include "mozilla/AppShutdown.h"
24 #include "mozilla/ipc/CrashReporterClient.h"
25 #include "mozilla/ipc/IOThreadChild.h"
26 #include "mozilla/GeckoArgs.h"
28 namespace mozilla {
29 namespace ipc {
31 ProcessChild* ProcessChild::gProcessChild;
33 static Atomic<bool> sExpectingShutdown(false);
35 ProcessChild::ProcessChild(ProcessId aParentPid, const nsID& aMessageChannelId)
36 : ChildProcess(new IOThreadChild(aParentPid)),
37 mUILoop(MessageLoop::current()),
38 mParentPid(aParentPid),
39 mMessageChannelId(aMessageChannelId) {
40 MOZ_ASSERT(mUILoop, "UILoop should be created by now");
41 MOZ_ASSERT(!gProcessChild, "should only be one ProcessChild");
42 gProcessChild = this;
45 /* static */
46 void ProcessChild::AddPlatformBuildID(std::vector<std::string>& aExtraArgs) {
47 nsCString parentBuildID(mozilla::PlatformBuildID());
48 geckoargs::sParentBuildID.Put(parentBuildID.get(), aExtraArgs);
51 /* static */
52 bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) {
53 Maybe<uint64_t> prefsHandle = Some(0);
54 Maybe<uint64_t> prefMapHandle = Some(0);
55 Maybe<uint64_t> prefsLen = geckoargs::sPrefsLen.Get(aArgc, aArgv);
56 Maybe<uint64_t> prefMapSize = geckoargs::sPrefMapSize.Get(aArgc, aArgv);
58 if (prefsLen.isNothing() || prefMapSize.isNothing()) {
59 return false;
62 #ifdef XP_WIN
63 prefsHandle = geckoargs::sPrefsHandle.Get(aArgc, aArgv);
64 prefMapHandle = geckoargs::sPrefMapHandle.Get(aArgc, aArgv);
66 if (prefsHandle.isNothing() || prefMapHandle.isNothing()) {
67 return false;
69 #endif
71 SharedPreferenceDeserializer deserializer;
72 return deserializer.DeserializeFromSharedMemory(*prefsHandle, *prefMapHandle,
73 *prefsLen, *prefMapSize);
76 #ifdef ENABLE_TESTS
77 // Allow tests to cause a synthetic delay/"hang" during child process
78 // shutdown by setting environment variables.
79 # ifdef XP_UNIX
80 static void ReallySleep(int aSeconds) {
81 struct ::timespec snooze = {aSeconds, 0};
82 HANDLE_EINTR(nanosleep(&snooze, &snooze));
84 # else
85 static void ReallySleep(int aSeconds) { ::Sleep(aSeconds * 1000); }
86 # endif // Unix/Win
87 static void SleepIfEnv(const char* aName) {
88 if (auto* value = PR_GetEnv(aName)) {
89 ReallySleep(atoi(value));
92 #else // not tests
93 static void SleepIfEnv(const char* aName) {}
94 #endif
96 ProcessChild::~ProcessChild() {
97 #ifdef NS_FREE_PERMANENT_DATA
98 // In this case, we won't early-exit and we'll wait indefinitely for
99 // child processes to terminate. This sleep is late enough that, in
100 // content processes, it won't block parent process shutdown, so
101 // we'll get into late IPC shutdown with processes still running.
102 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
103 #endif
104 gProcessChild = nullptr;
107 /* static */
108 void ProcessChild::NotifiedImpendingShutdown() {
109 sExpectingShutdown = true;
110 CrashReporter::AppendToCrashReportAnnotation(
111 CrashReporter::Annotation::IPCShutdownState,
112 "NotifiedImpendingShutdown"_ns);
115 /* static */
116 bool ProcessChild::ExpectingShutdown() { return sExpectingShutdown; }
118 /* static */
119 void ProcessChild::QuickExit() {
120 #ifndef NS_FREE_PERMANENT_DATA
121 // In this case, we're going to terminate the child process before
122 // we get to ~ProcessChild above (and terminate the parent process
123 // before the shutdown hook in ProcessWatcher). Instead, blocking
124 // earlier will let us exercise ProcessWatcher's kill timer.
125 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
126 #endif
127 AppShutdown::DoImmediateExit();
130 UntypedEndpoint ProcessChild::TakeInitialEndpoint() {
131 return UntypedEndpoint{PrivateIPDLInterface{},
132 child_thread()->TakeInitialPort(), mMessageChannelId,
133 base::GetCurrentProcId(), mParentPid};
136 } // namespace ipc
137 } // namespace mozilla