SocketProcessHost.cpp (8426B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "SocketProcessHost.h" 7 8 #include "SocketProcessParent.h" 9 #include "mozilla/dom/ContentParent.h" 10 #include "mozilla/ipc/FileDescriptor.h" 11 #include "mozilla/ipc/ProcessUtils.h" 12 #include "nsAppRunner.h" 13 #include "nsIOService.h" 14 #include "nsIObserverService.h" 15 #include "ProfilerParent.h" 16 #include "nsNetUtil.h" 17 #include "mozilla/ipc/Endpoint.h" 18 #include "mozilla/ipc/ProcessChild.h" 19 20 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 21 # include "mozilla/SandboxBroker.h" 22 # include "mozilla/SandboxBrokerPolicyFactory.h" 23 # include "mozilla/SandboxSettings.h" 24 #endif 25 26 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 27 # include "mozilla/Sandbox.h" 28 #endif 29 30 #if defined(XP_WIN) 31 # include "mozilla/WinDllServices.h" 32 #endif 33 34 using namespace mozilla::ipc; 35 36 namespace mozilla { 37 namespace net { 38 39 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 40 bool SocketProcessHost::sLaunchWithMacSandbox = false; 41 #endif 42 43 SocketProcessHost::SocketProcessHost(Listener* aListener) 44 : GeckoChildProcessHost(GeckoProcessType_Socket), 45 mListener(aListener), 46 mTaskFactory(Some(this)), 47 mLaunchPhase(LaunchPhase::Unlaunched), 48 mShutdownRequested(false), 49 mChannelClosed(false) { 50 MOZ_ASSERT(NS_IsMainThread()); 51 MOZ_COUNT_CTOR(SocketProcessHost); 52 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 53 if (!sLaunchWithMacSandbox) { 54 sLaunchWithMacSandbox = 55 (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX") == nullptr); 56 } 57 mDisableOSActivityMode = sLaunchWithMacSandbox; 58 #endif 59 } 60 61 SocketProcessHost::~SocketProcessHost() { MOZ_COUNT_DTOR(SocketProcessHost); } 62 63 bool SocketProcessHost::Launch() { 64 MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched); 65 MOZ_ASSERT(!mSocketProcessParent); 66 MOZ_ASSERT(NS_IsMainThread()); 67 68 geckoargs::ChildProcessArgs extraArgs; 69 ProcessChild::AddPlatformBuildID(extraArgs); 70 71 SharedPreferenceSerializer prefSerializer; 72 if (!prefSerializer.SerializeToSharedMemory(GeckoProcessType_VR, 73 /* remoteType */ ""_ns)) { 74 return false; 75 } 76 prefSerializer.AddSharedPrefCmdLineArgs(*this, extraArgs); 77 78 mLaunchPhase = LaunchPhase::Waiting; 79 if (!GeckoChildProcessHost::LaunchAndWaitForProcessHandle( 80 std::move(extraArgs))) { 81 mLaunchPhase = LaunchPhase::Complete; 82 return false; 83 } 84 85 return true; 86 } 87 88 static void HandleErrorAfterDestroy( 89 RefPtr<SocketProcessHost::Listener>&& aListener) { 90 if (!aListener) { 91 return; 92 } 93 94 NS_DispatchToMainThread(NS_NewRunnableFunction( 95 "HandleErrorAfterDestroy", [listener = std::move(aListener)]() { 96 listener->OnProcessLaunchComplete(nullptr, false); 97 })); 98 } 99 100 void SocketProcessHost::OnChannelConnected(base::ProcessId peer_pid) { 101 MOZ_ASSERT(!NS_IsMainThread()); 102 103 GeckoChildProcessHost::OnChannelConnected(peer_pid); 104 105 // Post a task to the main thread. Take the lock because mTaskFactory is not 106 // thread-safe. 107 RefPtr<Runnable> runnable; 108 { 109 MonitorAutoLock lock(mMonitor); 110 if (!mTaskFactory) { 111 HandleErrorAfterDestroy(std::move(mListener)); 112 return; 113 } 114 runnable = 115 (*mTaskFactory) 116 .NewRunnableMethod(&SocketProcessHost::OnChannelConnectedTask); 117 } 118 NS_DispatchToMainThread(runnable); 119 } 120 121 void SocketProcessHost::OnChannelConnectedTask() { 122 MOZ_ASSERT(NS_IsMainThread()); 123 124 if (mLaunchPhase == LaunchPhase::Waiting) { 125 InitAfterConnect(true); 126 } 127 } 128 129 void SocketProcessHost::InitAfterConnect(bool aSucceeded) { 130 MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting); 131 MOZ_ASSERT(!mSocketProcessParent); 132 MOZ_ASSERT(NS_IsMainThread()); 133 134 mLaunchPhase = LaunchPhase::Complete; 135 if (!aSucceeded) { 136 if (mListener) { 137 mListener->OnProcessLaunchComplete(this, false); 138 } 139 return; 140 } 141 142 mSocketProcessParent = MakeRefPtr<SocketProcessParent>(this); 143 DebugOnly<bool> rv = TakeInitialEndpoint().Bind(mSocketProcessParent.get()); 144 MOZ_ASSERT(rv); 145 146 SocketPorcessInitAttributes attributes; 147 nsCOMPtr<nsIIOService> ioService(do_GetIOService()); 148 MOZ_ASSERT(ioService, "No IO service?"); 149 DebugOnly<nsresult> result = ioService->GetOffline(&attributes.mOffline()); 150 MOZ_ASSERT(NS_SUCCEEDED(result), "Failed getting offline?"); 151 result = ioService->GetConnectivity(&attributes.mConnectivity()); 152 MOZ_ASSERT(NS_SUCCEEDED(result), "Failed getting connectivity?"); 153 154 attributes.mInitSandbox() = false; 155 156 #if defined(XP_WIN) 157 RefPtr<DllServices> dllSvc(DllServices::Get()); 158 attributes.mIsReadyForBackgroundProcessing() = 159 dllSvc->IsReadyForBackgroundProcessing(); 160 #endif 161 162 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 163 if (GetEffectiveSocketProcessSandboxLevel() > 0) { 164 auto policy = SandboxBrokerPolicyFactory::GetSocketProcessPolicy( 165 GetActor()->OtherPid()); 166 if (policy != nullptr) { 167 attributes.mSandboxBroker() = Some(FileDescriptor()); 168 mSandboxBroker = 169 SandboxBroker::Create(std::move(policy), GetActor()->OtherPid(), 170 attributes.mSandboxBroker().ref()); 171 // This is unlikely to fail and probably indicates OS resource 172 // exhaustion. 173 (void)NS_WARN_IF(mSandboxBroker == nullptr); 174 MOZ_ASSERT(attributes.mSandboxBroker().ref().IsValid()); 175 } 176 attributes.mInitSandbox() = true; 177 } 178 #endif // XP_LINUX && MOZ_SANDBOX 179 180 (void)GetActor()->SendInit(attributes); 181 182 (void)GetActor()->SendInitProfiler( 183 ProfilerParent::CreateForProcess(GetActor()->OtherPid())); 184 185 if (mListener) { 186 mListener->OnProcessLaunchComplete(this, true); 187 } 188 } 189 190 void SocketProcessHost::Shutdown() { 191 MOZ_ASSERT(!mShutdownRequested); 192 MOZ_ASSERT(NS_IsMainThread()); 193 194 mListener = nullptr; 195 196 if (mSocketProcessParent) { 197 // OnChannelClosed uses this to check if the shutdown was expected or 198 // unexpected. 199 mShutdownRequested = true; 200 201 // The channel might already be closed if we got here unexpectedly. 202 if (!mChannelClosed) { 203 mSocketProcessParent->Close(); 204 } 205 206 return; 207 } 208 209 DestroyProcess(); 210 } 211 212 void SocketProcessHost::OnChannelClosed() { 213 MOZ_ASSERT(NS_IsMainThread()); 214 215 mChannelClosed = true; 216 217 if (!mShutdownRequested && mListener) { 218 // This is an unclean shutdown. Notify our listener that we're going away. 219 mListener->OnProcessUnexpectedShutdown(this); 220 } else { 221 DestroyProcess(); 222 } 223 224 // Release the actor. 225 SocketProcessParent::Destroy(std::move(mSocketProcessParent)); 226 MOZ_ASSERT(!mSocketProcessParent); 227 } 228 229 void SocketProcessHost::DestroyProcess() { 230 { 231 MonitorAutoLock lock(mMonitor); 232 mTaskFactory.reset(); 233 } 234 235 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction( 236 "DestroySocketProcessRunnable", [this] { Destroy(); })); 237 } 238 239 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 240 bool SocketProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) { 241 GeckoChildProcessHost::FillMacSandboxInfo(aInfo); 242 if (!aInfo.shouldLog && PR_GetEnv("MOZ_SANDBOX_SOCKET_PROCESS_LOGGING")) { 243 aInfo.shouldLog = true; 244 } 245 return true; 246 } 247 248 /* static */ 249 MacSandboxType SocketProcessHost::GetMacSandboxType() { 250 return MacSandboxType_Socket; 251 } 252 #endif 253 254 //----------------------------------------------------------------------------- 255 // SocketProcessMemoryReporter 256 //----------------------------------------------------------------------------- 257 258 bool SocketProcessMemoryReporter::IsAlive() const { 259 MOZ_ASSERT(gIOService); 260 261 if (!gIOService->mSocketProcess) { 262 return false; 263 } 264 265 return gIOService->mSocketProcess->IsConnected(); 266 } 267 268 bool SocketProcessMemoryReporter::SendRequestMemoryReport( 269 const uint32_t& aGeneration, const bool& aAnonymize, 270 const bool& aMinimizeMemoryUsage, 271 const Maybe<ipc::FileDescriptor>& aDMDFile) { 272 MOZ_ASSERT(gIOService); 273 274 if (!gIOService->mSocketProcess) { 275 return false; 276 } 277 278 SocketProcessParent* actor = gIOService->mSocketProcess->GetActor(); 279 if (!actor) { 280 return false; 281 } 282 283 return actor->SendRequestMemoryReport(aGeneration, aAnonymize, 284 aMinimizeMemoryUsage, aDMDFile); 285 } 286 287 int32_t SocketProcessMemoryReporter::Pid() const { 288 MOZ_ASSERT(gIOService); 289 return gIOService->SocketProcessPid(); 290 } 291 292 } // namespace net 293 } // namespace mozilla