ClientManager.cpp (13118B)
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 "ClientManager.h" 8 9 #include "ClientHandle.h" 10 #include "ClientManagerChild.h" 11 #include "ClientManagerOpChild.h" 12 #include "ClientSource.h" 13 #include "mozilla/ClearOnShutdown.h" // PastShutdownPhase 14 #include "mozilla/StaticPrefs_dom.h" 15 #include "mozilla/dom/WorkerPrivate.h" 16 #include "mozilla/ipc/BackgroundChild.h" 17 #include "mozilla/ipc/PBackgroundChild.h" 18 #include "prthread.h" 19 20 namespace mozilla::dom { 21 22 using mozilla::ipc::BackgroundChild; 23 using mozilla::ipc::PBackgroundChild; 24 using mozilla::ipc::PrincipalInfo; 25 26 namespace { 27 28 const uint32_t kBadThreadLocalIndex = -1; 29 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 30 const uint32_t kThreadLocalMagic1 = 0x8d57eea6; 31 const uint32_t kThreadLocalMagic2 = 0x59f375c9; 32 #endif 33 34 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 35 uint32_t sClientManagerThreadLocalMagic1 = kThreadLocalMagic1; 36 #endif 37 38 uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex; 39 40 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 41 uint32_t sClientManagerThreadLocalMagic2 = kThreadLocalMagic2; 42 uint32_t sClientManagerThreadLocalIndexDuplicate = kBadThreadLocalIndex; 43 #endif 44 45 } // anonymous namespace 46 47 ClientManager::ClientManager() { 48 PBackgroundChild* parentActor = 49 BackgroundChild::GetOrCreateForCurrentThread(); 50 if (NS_WARN_IF(!parentActor)) { 51 Shutdown(); 52 return; 53 } 54 55 RefPtr<ClientManagerChild> actor = ClientManagerChild::Create(); 56 if (NS_WARN_IF(!actor)) { 57 Shutdown(); 58 return; 59 } 60 61 PClientManagerChild* sentActor = 62 parentActor->SendPClientManagerConstructor(actor); 63 if (NS_WARN_IF(!sentActor)) { 64 Shutdown(); 65 return; 66 } 67 MOZ_DIAGNOSTIC_ASSERT(sentActor == actor); 68 69 ActivateThing(actor); 70 } 71 72 ClientManager::~ClientManager() { 73 NS_ASSERT_OWNINGTHREAD(ClientManager); 74 75 Shutdown(); 76 77 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); 78 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); 79 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); 80 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == 81 sClientManagerThreadLocalIndexDuplicate); 82 MOZ_DIAGNOSTIC_ASSERT(this == 83 PR_GetThreadPrivate(sClientManagerThreadLocalIndex)); 84 85 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 86 PRStatus status = 87 #endif 88 PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr); 89 MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS); 90 } 91 92 void ClientManager::Shutdown() { 93 NS_ASSERT_OWNINGTHREAD(ClientManager); 94 95 if (IsShutdown()) { 96 return; 97 } 98 99 ShutdownThing(); 100 } 101 102 UniquePtr<ClientSource> ClientManager::CreateSourceInternal( 103 ClientType aType, nsISerialEventTarget* aEventTarget, 104 const PrincipalInfo& aPrincipal) { 105 NS_ASSERT_OWNINGTHREAD(ClientManager); 106 107 nsID id; 108 nsresult rv = nsID::GenerateUUIDInPlace(id); 109 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 110 if (NS_WARN_IF(NS_FAILED(rv))) { 111 // If we can't even get a UUID, at least make sure not to use a garbage 112 // value. Instead return a shutdown ClientSource with a zero'd id. 113 // This should be exceptionally rare, if it happens at all. 114 id.Clear(); 115 ClientSourceConstructorArgs args(id, Nothing(), aType, aPrincipal, 116 TimeStamp::Now(), VoidCString(), 117 FrameType::None); 118 UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args)); 119 source->Shutdown(); 120 return source; 121 } 122 123 ClientSourceConstructorArgs args(id, Nothing(), aType, aPrincipal, 124 TimeStamp::Now(), VoidCString(), 125 FrameType::None); 126 UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args)); 127 128 if (IsShutdown()) { 129 source->Shutdown(); 130 return source; 131 } 132 133 source->Activate(GetActor()); 134 135 return source; 136 } 137 138 UniquePtr<ClientSource> ClientManager::CreateSourceInternal( 139 const ClientInfo& aClientInfo, nsISerialEventTarget* aEventTarget) { 140 NS_ASSERT_OWNINGTHREAD(ClientManager); 141 142 ClientSourceConstructorArgs args( 143 aClientInfo.Id(), aClientInfo.AgentClusterId(), aClientInfo.Type(), 144 aClientInfo.PrincipalInfo(), aClientInfo.CreationTime(), 145 aClientInfo.URL(), aClientInfo.FrameType()); 146 UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args)); 147 148 if (IsShutdown()) { 149 source->Shutdown(); 150 return source; 151 } 152 153 source->Activate(GetActor()); 154 155 return source; 156 } 157 158 already_AddRefed<ClientHandle> ClientManager::CreateHandleInternal( 159 const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget) { 160 NS_ASSERT_OWNINGTHREAD(ClientManager); 161 MOZ_DIAGNOSTIC_ASSERT(aSerialEventTarget); 162 163 RefPtr<ClientHandle> handle = 164 new ClientHandle(this, aSerialEventTarget, aClientInfo); 165 166 if (IsShutdown()) { 167 handle->Shutdown(); 168 return handle.forget(); 169 } 170 171 handle->Activate(GetActor()); 172 173 return handle.forget(); 174 } 175 176 RefPtr<ClientOpPromise> ClientManager::StartOp( 177 const ClientOpConstructorArgs& aArgs, 178 nsISerialEventTarget* aSerialEventTarget) { 179 RefPtr<ClientOpPromise::Private> promise = 180 new ClientOpPromise::Private(__func__); 181 182 // Hold a ref to the client until the remote operation completes. Otherwise 183 // the ClientHandle might get de-refed and teardown the actor before we 184 // get an answer. 185 RefPtr<ClientManager> kungFuGrip = this; 186 187 MaybeExecute( 188 [&aArgs, promise, kungFuGrip](ClientManagerChild* aActor) { 189 ClientManagerOpChild* actor = 190 new ClientManagerOpChild(kungFuGrip, aArgs, promise); 191 if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) { 192 // Constructor failure will reject promise via ActorDestroy() 193 return; 194 } 195 }, 196 [promise] { 197 CopyableErrorResult rv; 198 rv.ThrowInvalidStateError("Client has been destroyed"); 199 promise->Reject(rv, __func__); 200 }); 201 202 return promise; 203 } 204 205 // static 206 already_AddRefed<ClientManager> ClientManager::GetOrCreateForCurrentThread() { 207 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); 208 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); 209 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); 210 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == 211 sClientManagerThreadLocalIndexDuplicate); 212 RefPtr<ClientManager> cm = static_cast<ClientManager*>( 213 PR_GetThreadPrivate(sClientManagerThreadLocalIndex)); 214 215 if (!cm) { 216 cm = new ClientManager(); 217 218 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 219 PRStatus status = 220 #endif 221 PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get()); 222 MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS); 223 } 224 225 MOZ_DIAGNOSTIC_ASSERT(cm); 226 227 if (StaticPrefs::dom_workers_testing_enabled()) { 228 // Check that the ClientManager instance associated to the current thread 229 // has not been kept alive when it was expected to have been already 230 // deallocated (e.g. due to a leak ClientManager's mShutdown can have ben 231 // set to true from its RevokeActor method but never fully deallocated and 232 // unset from the thread locals). 233 MOZ_DIAGNOSTIC_ASSERT(!cm->IsShutdown()); 234 } 235 return cm.forget(); 236 } 237 238 WorkerPrivate* ClientManager::GetWorkerPrivate() const { 239 NS_ASSERT_OWNINGTHREAD(ClientManager); 240 MOZ_DIAGNOSTIC_ASSERT(GetActor()); 241 return GetActor()->GetWorkerPrivate(); 242 } 243 244 // Used to share logic between ExpectFutureSource and ForgetFutureSource. 245 /* static */ bool ClientManager::ExpectOrForgetFutureSource( 246 const ClientInfo& aClientInfo, 247 bool (PClientManagerChild::*aMethod)(const IPCClientInfo&)) { 248 // Return earlier if called late in the XPCOM shutdown path, 249 // ClientManager would be already shutdown at the point. 250 if (NS_WARN_IF(PastShutdownPhase(ShutdownPhase::XPCOMShutdown))) { 251 return false; 252 } 253 254 bool rv = true; 255 256 RefPtr<ClientManager> mgr = ClientManager::GetOrCreateForCurrentThread(); 257 mgr->MaybeExecute( 258 [&](ClientManagerChild* aActor) { 259 if (!(aActor->*aMethod)(aClientInfo.ToIPC())) { 260 rv = false; 261 } 262 }, 263 [&] { rv = false; }); 264 265 return rv; 266 } 267 268 /* static */ bool ClientManager::ExpectFutureSource( 269 const ClientInfo& aClientInfo) { 270 return ExpectOrForgetFutureSource( 271 aClientInfo, &PClientManagerChild::SendExpectFutureClientSource); 272 } 273 274 /* static */ bool ClientManager::ForgetFutureSource( 275 const ClientInfo& aClientInfo) { 276 return ExpectOrForgetFutureSource( 277 aClientInfo, &PClientManagerChild::SendForgetFutureClientSource); 278 } 279 280 // static 281 void ClientManager::Startup() { 282 MOZ_ASSERT(NS_IsMainThread()); 283 284 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); 285 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); 286 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex); 287 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == 288 sClientManagerThreadLocalIndexDuplicate); 289 290 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 291 PRStatus status = 292 #endif 293 PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr); 294 MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS); 295 296 MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); 297 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 298 sClientManagerThreadLocalIndexDuplicate = sClientManagerThreadLocalIndex; 299 #endif 300 } 301 302 // static 303 UniquePtr<ClientSource> ClientManager::CreateSource( 304 ClientType aType, nsISerialEventTarget* aEventTarget, 305 nsIPrincipal* aPrincipal) { 306 MOZ_ASSERT(NS_IsMainThread()); 307 MOZ_ASSERT(aPrincipal); 308 309 PrincipalInfo principalInfo; 310 nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo); 311 if (NS_WARN_IF(NS_FAILED(rv))) { 312 MOZ_CRASH("ClientManager::CreateSource() cannot serialize bad principal"); 313 } 314 315 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 316 return mgr->CreateSourceInternal(aType, aEventTarget, principalInfo); 317 } 318 319 // static 320 UniquePtr<ClientSource> ClientManager::CreateSource( 321 ClientType aType, nsISerialEventTarget* aEventTarget, 322 const PrincipalInfo& aPrincipal) { 323 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 324 return mgr->CreateSourceInternal(aType, aEventTarget, aPrincipal); 325 } 326 327 // static 328 UniquePtr<ClientSource> ClientManager::CreateSourceFromInfo( 329 const ClientInfo& aClientInfo, nsISerialEventTarget* aEventTarget) { 330 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 331 return mgr->CreateSourceInternal(aClientInfo, aEventTarget); 332 } 333 334 Maybe<ClientInfo> ClientManager::CreateInfo(ClientType aType, 335 nsIPrincipal* aPrincipal) { 336 MOZ_ASSERT(NS_IsMainThread()); 337 MOZ_ASSERT(aPrincipal); 338 339 PrincipalInfo principalInfo; 340 nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo); 341 if (NS_WARN_IF(NS_FAILED(rv))) { 342 MOZ_CRASH("ClientManager::CreateSource() cannot serialize bad principal"); 343 } 344 345 nsID id; 346 rv = nsID::GenerateUUIDInPlace(id); 347 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); 348 if (NS_WARN_IF(NS_FAILED(rv))) { 349 return Nothing(); 350 } 351 352 return Some(ClientInfo(id, Nothing(), aType, principalInfo, TimeStamp::Now(), 353 ""_ns, FrameType::None)); 354 } 355 356 // static 357 already_AddRefed<ClientHandle> ClientManager::CreateHandle( 358 const ClientInfo& aClientInfo, nsISerialEventTarget* aSerialEventTarget) { 359 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 360 return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget); 361 } 362 363 // static 364 RefPtr<ClientOpPromise> ClientManager::MatchAll( 365 const ClientMatchAllArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) { 366 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 367 return mgr->StartOp(aArgs, aSerialEventTarget); 368 } 369 370 // static 371 RefPtr<ClientOpPromise> ClientManager::Claim( 372 const ClientClaimArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) { 373 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 374 return mgr->StartOp(aArgs, aSerialEventTarget); 375 } 376 377 // static 378 RefPtr<ClientOpPromise> ClientManager::GetInfoAndState( 379 const ClientGetInfoAndStateArgs& aArgs, 380 nsISerialEventTarget* aSerialEventTarget) { 381 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 382 return mgr->StartOp(aArgs, aSerialEventTarget); 383 } 384 385 // static 386 RefPtr<ClientOpPromise> ClientManager::Navigate( 387 const ClientNavigateArgs& aArgs, nsISerialEventTarget* aSerialEventTarget) { 388 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 389 return mgr->StartOp(aArgs, aSerialEventTarget); 390 } 391 392 // static 393 RefPtr<ClientOpPromise> ClientManager::OpenWindow( 394 const ClientOpenWindowArgs& aArgs, 395 nsISerialEventTarget* aSerialEventTarget) { 396 RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread(); 397 return mgr->StartOp(aArgs, aSerialEventTarget); 398 } 399 400 } // namespace mozilla::dom