ProcessChild.cpp (4411B)
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/. */ 6 7 #include "mozilla/ipc/ProcessChild.h" 8 9 #include "Endpoint.h" 10 #include "nsDebug.h" 11 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 21 22 #include "nsAppRunner.h" 23 #include "mozilla/AppShutdown.h" 24 #include "mozilla/ipc/IOThread.h" 25 #include "mozilla/ipc/ProcessUtils.h" 26 #include "mozilla/GeckoArgs.h" 27 28 namespace mozilla { 29 namespace ipc { 30 31 ProcessChild* ProcessChild::gProcessChild; 32 StaticMutex ProcessChild::gIPCShutdownStateLock; 33 constinit nsCString ProcessChild::gIPCShutdownStateAnnotation; 34 35 ProcessChild::ProcessChild(IPC::Channel::ChannelHandle aClientChannel, 36 ProcessId aParentPid, const nsID& aMessageChannelId) 37 : mUILoop(MessageLoop::current()), 38 mParentPid(aParentPid), 39 mMessageChannelId(aMessageChannelId), 40 mChildThread( 41 MakeUnique<IOThreadChild>(std::move(aClientChannel), aParentPid)) { 42 MOZ_ASSERT(mUILoop, "UILoop should be created by now"); 43 MOZ_ASSERT(!gProcessChild, "should only be one ProcessChild"); 44 CrashReporter::RegisterAnnotationNSCString( 45 CrashReporter::Annotation::IPCShutdownState, 46 &gIPCShutdownStateAnnotation); 47 gProcessChild = this; 48 } 49 50 /* static */ 51 void ProcessChild::AddPlatformBuildID(geckoargs::ChildProcessArgs& aExtraArgs) { 52 nsCString parentBuildID(mozilla::PlatformBuildID()); 53 geckoargs::sParentBuildID.Put(parentBuildID.get(), aExtraArgs); 54 } 55 56 /* static */ 57 bool ProcessChild::InitPrefs(int aArgc, char* aArgv[]) { 58 Maybe<ReadOnlySharedMemoryHandle> prefsHandle = 59 geckoargs::sPrefsHandle.Get(aArgc, aArgv); 60 Maybe<ReadOnlySharedMemoryHandle> prefMapHandle = 61 geckoargs::sPrefMapHandle.Get(aArgc, aArgv); 62 63 if (prefsHandle.isNothing() || prefMapHandle.isNothing()) { 64 return false; 65 } 66 67 SharedPreferenceDeserializer deserializer; 68 return deserializer.DeserializeFromSharedMemory(std::move(*prefsHandle), 69 std::move(*prefMapHandle)); 70 } 71 72 #ifdef ENABLE_TESTS 73 // Allow tests to cause a synthetic delay/"hang" during child process 74 // shutdown by setting environment variables. 75 # ifdef XP_UNIX 76 static void ReallySleep(int aSeconds) { 77 struct ::timespec snooze = {aSeconds, 0}; 78 HANDLE_EINTR(nanosleep(&snooze, &snooze)); 79 } 80 # else 81 static void ReallySleep(int aSeconds) { ::Sleep(aSeconds * 1000); } 82 # endif // Unix/Win 83 static void SleepIfEnv(const char* aName) { 84 if (auto* value = PR_GetEnv(aName)) { 85 ReallySleep(atoi(value)); 86 } 87 } 88 #else // not tests 89 static void SleepIfEnv(const char* aName) {} 90 #endif 91 92 ProcessChild::~ProcessChild() { 93 #ifdef NS_FREE_PERMANENT_DATA 94 // In this case, we won't early-exit and we'll wait indefinitely for 95 // child processes to terminate. This sleep is late enough that, in 96 // content processes, it won't block parent process shutdown, so 97 // we'll get into late IPC shutdown with processes still running. 98 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG"); 99 #endif 100 gIPCShutdownStateAnnotation = ""_ns; 101 gProcessChild = nullptr; 102 } 103 104 /* static */ 105 void ProcessChild::NotifiedImpendingShutdown() { 106 AppShutdown::SetImpendingShutdown(); 107 ProcessChild::AppendToIPCShutdownStateAnnotation( 108 "NotifiedImpendingShutdown"_ns); 109 } 110 111 /* static */ 112 void ProcessChild::QuickExit() { 113 #ifndef NS_FREE_PERMANENT_DATA 114 // In this case, we're going to terminate the child process before 115 // we get to ~ProcessChild above (and terminate the parent process 116 // before the shutdown hook in ProcessWatcher). Instead, blocking 117 // earlier will let us exercise ProcessWatcher's kill timer. 118 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG"); 119 #endif 120 AppShutdown::DoImmediateExit(); 121 } 122 123 UntypedEndpoint ProcessChild::TakeInitialEndpoint() { 124 return UntypedEndpoint{PrivateIPDLInterface{}, 125 mChildThread->TakeInitialPort(), mMessageChannelId, 126 EndpointProcInfo::Current(), 127 EndpointProcInfo{.mPid = mParentPid, .mChildID = 0}}; 128 } 129 130 } // namespace ipc 131 } // namespace mozilla