ActorsChild.h (18901B)
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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_indexeddb_actorschild_h__ 8 #define mozilla_dom_indexeddb_actorschild_h__ 9 10 #include "js/RootingAPI.h" 11 #include "mozilla/InitializedOnce.h" 12 #include "mozilla/UniquePtr.h" 13 #include "mozilla/dom/IDBCursorType.h" 14 #include "mozilla/dom/IDBTransaction.h" 15 #include "mozilla/dom/indexedDB/PBackgroundIDBCursorChild.h" 16 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseChild.h" 17 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" 18 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestChild.h" 19 #include "mozilla/dom/indexedDB/PBackgroundIDBRequestChild.h" 20 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h" 21 #include "mozilla/dom/indexedDB/PBackgroundIDBTransactionChild.h" 22 #include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionChild.h" 23 #include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h" 24 #include "nsCOMPtr.h" 25 #include "nsTArray.h" 26 27 class nsIEventTarget; 28 struct nsID; 29 30 namespace mozilla { 31 namespace ipc { 32 33 class BackgroundChildImpl; 34 35 } // namespace ipc 36 37 namespace dom { 38 39 class IDBCursor; 40 class IDBDatabase; 41 class IDBFactory; 42 class IDBOpenDBRequest; 43 class IDBRequest; 44 class IndexedDatabaseManager; 45 46 namespace indexedDB { 47 48 class Key; 49 class PermissionRequestChild; 50 class PermissionRequestParent; 51 class SerializedStructuredCloneReadInfo; 52 struct CloneInfo; 53 54 } // namespace indexedDB 55 } // namespace dom 56 } // namespace mozilla 57 58 MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR(mozilla::dom::indexedDB::CloneInfo) 59 60 namespace mozilla::dom::indexedDB { 61 62 class BackgroundFactoryChild final : public PBackgroundIDBFactoryChild { 63 friend class mozilla::ipc::BackgroundChildImpl; 64 friend IDBFactory; 65 66 // TODO: This long-lived raw pointer is very suspicious, in particular as it 67 // is used in BackgroundDatabaseChild::EnsureDOMObject to reacquire a strong 68 // reference. What ensures it is kept alive, and why can't we store a strong 69 // reference here? 70 IDBFactory* mFactory; 71 72 public: 73 NS_INLINE_DECL_REFCOUNTING(BackgroundFactoryChild, override) 74 75 void AssertIsOnOwningThread() const { 76 NS_ASSERT_OWNINGTHREAD(BackgroundFactoryChild); 77 } 78 79 IDBFactory& GetDOMObject() const { 80 AssertIsOnOwningThread(); 81 MOZ_ASSERT(mFactory); 82 return *mFactory; 83 } 84 85 bool SendDeleteMe() = delete; 86 87 private: 88 // Only created by IDBFactory. 89 explicit BackgroundFactoryChild(IDBFactory& aFactory); 90 91 // Only destroyed by mozilla::ipc::BackgroundChildImpl. 92 ~BackgroundFactoryChild(); 93 94 void SendDeleteMeInternal(); 95 96 public: 97 // IPDL methods are only called by IPDL. 98 void ActorDestroy(ActorDestroyReason aWhy) override; 99 100 PBackgroundIDBFactoryRequestChild* AllocPBackgroundIDBFactoryRequestChild( 101 const FactoryRequestParams& aParams); 102 103 bool DeallocPBackgroundIDBFactoryRequestChild( 104 PBackgroundIDBFactoryRequestChild* aActor); 105 106 already_AddRefed<PBackgroundIDBDatabaseChild> 107 AllocPBackgroundIDBDatabaseChild( 108 const DatabaseSpec& aSpec, 109 PBackgroundIDBFactoryRequestChild* aRequest) const; 110 111 mozilla::ipc::IPCResult RecvPBackgroundIDBDatabaseConstructor( 112 PBackgroundIDBDatabaseChild* aActor, const DatabaseSpec& aSpec, 113 NotNull<PBackgroundIDBFactoryRequestChild*> aRequest) override; 114 }; 115 116 class BackgroundDatabaseChild; 117 118 class BackgroundRequestChildBase { 119 protected: 120 const NotNull<RefPtr<IDBRequest>> mRequest; 121 122 public: 123 void AssertIsOnOwningThread() const 124 #ifdef DEBUG 125 ; 126 #else 127 { 128 } 129 #endif 130 131 protected: 132 explicit BackgroundRequestChildBase( 133 MovingNotNull<RefPtr<IDBRequest>> aRequest); 134 135 virtual ~BackgroundRequestChildBase(); 136 }; 137 138 class BackgroundFactoryRequestChild final 139 : public BackgroundRequestChildBase, 140 public PBackgroundIDBFactoryRequestChild { 141 using PersistenceType = mozilla::dom::quota::PersistenceType; 142 143 friend IDBFactory; 144 friend class BackgroundFactoryChild; 145 friend class BackgroundDatabaseChild; 146 friend class PermissionRequestChild; 147 friend class PermissionRequestParent; 148 149 const SafeRefPtr<IDBFactory> mFactory; 150 151 // Normally when opening of a database is successful, we receive a database 152 // actor in request response, so we can use it to call ReleaseDOMObject() 153 // which clears temporary strong reference to IDBDatabase. 154 // However, when there's an error, we don't receive a database actor and 155 // IDBRequest::mTransaction is already cleared (must be). So the only way how 156 // to call ReleaseDOMObject() is to have a back-reference to database actor. 157 // This creates a weak ref cycle between 158 // BackgroundFactoryRequestChild (using mDatabaseActor member) and 159 // BackgroundDatabaseChild actor (using mOpenRequestActor member). 160 // mDatabaseActor is set in EnsureDOMObject() and cleared in 161 // ReleaseDOMObject(). 162 BackgroundDatabaseChild* mDatabaseActor; 163 164 const uint64_t mRequestedVersion; 165 const bool mIsDeleteOp; 166 167 public: 168 NotNull<IDBOpenDBRequest*> GetOpenDBRequest() const; 169 170 private: 171 // Only created by IDBFactory. 172 BackgroundFactoryRequestChild( 173 SafeRefPtr<IDBFactory> aFactory, 174 MovingNotNull<RefPtr<IDBOpenDBRequest>> aOpenRequest, bool aIsDeleteOp, 175 uint64_t aRequestedVersion); 176 177 // Only destroyed by BackgroundFactoryChild. 178 ~BackgroundFactoryRequestChild(); 179 180 void SetDatabaseActor(BackgroundDatabaseChild* aActor); 181 182 void HandleResponse(nsresult aResponse); 183 184 void HandleResponse(const OpenDatabaseRequestResponse& aResponse); 185 186 void HandleResponse(const DeleteDatabaseRequestResponse& aResponse); 187 188 public: 189 // IPDL methods are only called by IPDL. 190 void ActorDestroy(ActorDestroyReason aWhy) override; 191 192 mozilla::ipc::IPCResult Recv__delete__( 193 const FactoryRequestResponse& aResponse); 194 195 mozilla::ipc::IPCResult RecvPermissionChallenge( 196 PrincipalInfo&& aPrincipalInfo); 197 198 mozilla::ipc::IPCResult RecvBlocked(uint64_t aCurrentVersion); 199 }; 200 201 class BackgroundDatabaseChild final : public PBackgroundIDBDatabaseChild { 202 friend class BackgroundFactoryChild; 203 friend class BackgroundFactoryRequestChild; 204 friend IDBDatabase; 205 206 UniquePtr<DatabaseSpec> mSpec; 207 RefPtr<IDBDatabase> mTemporaryStrongDatabase; 208 BackgroundFactoryRequestChild* mOpenRequestActor; 209 IDBDatabase* mDatabase; 210 bool mPendingInvalidate; 211 212 public: 213 NS_INLINE_DECL_REFCOUNTING(BackgroundDatabaseChild, override) 214 215 void AssertIsOnOwningThread() const 216 #ifdef DEBUG 217 ; 218 #else 219 { 220 } 221 #endif 222 223 const DatabaseSpec* Spec() const { 224 AssertIsOnOwningThread(); 225 return mSpec.get(); 226 } 227 228 IDBDatabase* GetDOMObject() const { 229 AssertIsOnOwningThread(); 230 return mDatabase; 231 } 232 233 bool SendDeleteMe() = delete; 234 235 private: 236 // Only constructed by BackgroundFactoryChild. 237 BackgroundDatabaseChild(const DatabaseSpec& aSpec, 238 BackgroundFactoryRequestChild* aOpenRequest); 239 240 ~BackgroundDatabaseChild(); 241 242 void SendDeleteMeInternal(); 243 244 [[nodiscard]] bool EnsureDOMObject(); 245 246 void ReleaseDOMObject(); 247 248 public: 249 // IPDL methods are only called by IPDL. 250 void ActorDestroy(ActorDestroyReason aWhy) override; 251 252 PBackgroundIDBDatabaseFileChild* AllocPBackgroundIDBDatabaseFileChild( 253 const IPCBlob& aIPCBlob); 254 255 bool DeallocPBackgroundIDBDatabaseFileChild( 256 PBackgroundIDBDatabaseFileChild* aActor) const; 257 258 already_AddRefed<PBackgroundIDBVersionChangeTransactionChild> 259 AllocPBackgroundIDBVersionChangeTransactionChild(uint64_t aCurrentVersion, 260 uint64_t aRequestedVersion, 261 int64_t aNextObjectStoreId, 262 int64_t aNextIndexId); 263 264 mozilla::ipc::IPCResult RecvPBackgroundIDBVersionChangeTransactionConstructor( 265 PBackgroundIDBVersionChangeTransactionChild* aActor, 266 const uint64_t& aCurrentVersion, const uint64_t& aRequestedVersion, 267 const int64_t& aNextObjectStoreId, const int64_t& aNextIndexId) override; 268 269 mozilla::ipc::IPCResult RecvVersionChange(uint64_t aOldVersion, 270 Maybe<uint64_t> aNewVersion); 271 272 mozilla::ipc::IPCResult RecvInvalidate(); 273 274 mozilla::ipc::IPCResult RecvCloseAfterInvalidationComplete(); 275 }; 276 277 class BackgroundVersionChangeTransactionChild; 278 279 class BackgroundTransactionBase { 280 friend class BackgroundVersionChangeTransactionChild; 281 282 // mTemporaryStrongTransaction is strong and is only valid until the end of 283 // NoteComplete() member function or until the NoteActorDestroyed() member 284 // function is called. 285 SafeRefPtr<IDBTransaction> mTemporaryStrongTransaction; 286 287 protected: 288 // mTransaction is weak and is valid until the NoteActorDestroyed() member 289 // function is called. 290 IDBTransaction* mTransaction = nullptr; 291 292 public: 293 #ifdef DEBUG 294 virtual void AssertIsOnOwningThread() const = 0; 295 #else 296 void AssertIsOnOwningThread() const {} 297 #endif 298 299 IDBTransaction* GetDOMObject() const { 300 AssertIsOnOwningThread(); 301 return mTransaction; 302 } 303 304 protected: 305 MOZ_COUNTED_DEFAULT_CTOR(BackgroundTransactionBase); 306 307 explicit BackgroundTransactionBase(SafeRefPtr<IDBTransaction> aTransaction); 308 309 MOZ_COUNTED_DTOR_VIRTUAL(BackgroundTransactionBase); 310 311 void NoteActorDestroyed(); 312 313 void NoteComplete(); 314 315 private: 316 // Only called by BackgroundVersionChangeTransactionChild. 317 void SetDOMTransaction(SafeRefPtr<IDBTransaction> aTransaction); 318 }; 319 320 class BackgroundTransactionChild final : public BackgroundTransactionBase, 321 public PBackgroundIDBTransactionChild { 322 friend class BackgroundDatabaseChild; 323 friend IDBDatabase; 324 325 public: 326 NS_INLINE_DECL_REFCOUNTING(BackgroundTransactionChild, override) 327 328 #ifdef DEBUG 329 void AssertIsOnOwningThread() const override; 330 #endif 331 332 void SendDeleteMeInternal(); 333 334 bool SendDeleteMe() = delete; 335 336 private: 337 // Only created by IDBDatabase. 338 explicit BackgroundTransactionChild(SafeRefPtr<IDBTransaction> aTransaction); 339 340 // Only destroyed by BackgroundDatabaseChild. 341 ~BackgroundTransactionChild(); 342 343 public: 344 // IPDL methods are only called by IPDL. 345 void ActorDestroy(ActorDestroyReason aWhy) override; 346 347 mozilla::ipc::IPCResult RecvComplete(nsresult aResult); 348 349 PBackgroundIDBRequestChild* AllocPBackgroundIDBRequestChild( 350 const int64_t& aRequestId, const RequestParams& aParams); 351 352 bool DeallocPBackgroundIDBRequestChild(PBackgroundIDBRequestChild* aActor); 353 354 PBackgroundIDBCursorChild* AllocPBackgroundIDBCursorChild( 355 const int64_t& aRequestId, const OpenCursorParams& aParams); 356 357 bool DeallocPBackgroundIDBCursorChild(PBackgroundIDBCursorChild* aActor); 358 }; 359 360 class BackgroundVersionChangeTransactionChild final 361 : public BackgroundTransactionBase, 362 public PBackgroundIDBVersionChangeTransactionChild { 363 friend class BackgroundDatabaseChild; 364 365 IDBOpenDBRequest* mOpenDBRequest; 366 367 public: 368 NS_INLINE_DECL_REFCOUNTING(BackgroundVersionChangeTransactionChild, override) 369 370 #ifdef DEBUG 371 void AssertIsOnOwningThread() const override; 372 #endif 373 374 void SendDeleteMeInternal(bool aFailedConstructor); 375 376 bool SendDeleteMe() = delete; 377 378 private: 379 // Only created by BackgroundDatabaseChild. 380 explicit BackgroundVersionChangeTransactionChild( 381 IDBOpenDBRequest* aOpenDBRequest); 382 383 // Only destroyed by BackgroundDatabaseChild. 384 ~BackgroundVersionChangeTransactionChild(); 385 386 // Only called by BackgroundDatabaseChild. 387 using BackgroundTransactionBase::SetDOMTransaction; 388 389 public: 390 // IPDL methods are only called by IPDL. 391 void ActorDestroy(ActorDestroyReason aWhy) override; 392 393 mozilla::ipc::IPCResult RecvComplete(nsresult aResult); 394 395 PBackgroundIDBRequestChild* AllocPBackgroundIDBRequestChild( 396 const int64_t& aRequestId, const RequestParams& aParams); 397 398 bool DeallocPBackgroundIDBRequestChild(PBackgroundIDBRequestChild* aActor); 399 400 PBackgroundIDBCursorChild* AllocPBackgroundIDBCursorChild( 401 const int64_t& aRequestId, const OpenCursorParams& aParams); 402 403 bool DeallocPBackgroundIDBCursorChild(PBackgroundIDBCursorChild* aActor); 404 }; 405 406 class BackgroundRequestChild final : public BackgroundRequestChildBase, 407 public PBackgroundIDBRequestChild { 408 friend class BackgroundTransactionChild; 409 friend class BackgroundVersionChangeTransactionChild; 410 friend struct CloneInfo; 411 friend IDBTransaction; 412 413 class PreprocessHelper; 414 415 SafeRefPtr<IDBTransaction> mTransaction; 416 nsTArray<CloneInfo> mCloneInfos; 417 uint32_t mRunningPreprocessHelpers; 418 uint32_t mCurrentCloneDataIndex; 419 nsresult mPreprocessResultCode; 420 bool mGetAll; 421 422 private: 423 // Only created by IDBTransaction. 424 explicit BackgroundRequestChild(MovingNotNull<RefPtr<IDBRequest>> aRequest); 425 426 // Only destroyed by BackgroundTransactionChild or 427 // BackgroundVersionChangeTransactionChild. 428 ~BackgroundRequestChild(); 429 430 void MaybeSendContinue(); 431 432 void OnPreprocessFinished(uint32_t aCloneDataIndex, 433 UniquePtr<JSStructuredCloneData> aCloneData); 434 435 void OnPreprocessFailed(uint32_t aCloneDataIndex, nsresult aErrorCode); 436 437 UniquePtr<JSStructuredCloneData> GetNextCloneData(); 438 439 void HandleResponse(nsresult aResponse); 440 441 void HandleResponse(const Key& aResponse); 442 443 void HandleResponse(const nsTArray<Key>& aResponse); 444 445 void HandleResponse(SerializedStructuredCloneReadInfo&& aResponse); 446 447 void HandleResponse(nsTArray<SerializedStructuredCloneReadInfo>&& aResponse); 448 449 void HandleResponse(JS::Handle<JS::Value> aResponse); 450 451 void HandleResponse(uint64_t aResponse); 452 453 nsresult HandlePreprocess(const PreprocessInfo& aPreprocessInfo); 454 455 nsresult HandlePreprocess(const nsTArray<PreprocessInfo>& aPreprocessInfos); 456 457 nsresult HandlePreprocessInternal( 458 const nsTArray<PreprocessInfo>& aPreprocessInfos); 459 460 SafeRefPtr<IDBTransaction> AcquireTransaction() const { 461 return mTransaction.clonePtr(); 462 } 463 464 public: 465 // IPDL methods are only called by IPDL. 466 void ActorDestroy(ActorDestroyReason aWhy) override; 467 468 mozilla::ipc::IPCResult Recv__delete__(RequestResponse&& aResponse); 469 470 mozilla::ipc::IPCResult RecvPreprocess(const PreprocessParams& aParams); 471 }; 472 473 struct CloneInfo { 474 RefPtr<BackgroundRequestChild::PreprocessHelper> mPreprocessHelper; 475 UniquePtr<JSStructuredCloneData> mCloneData; 476 }; 477 478 class BackgroundCursorChildBase 479 : public PBackgroundIDBCursorChild, 480 public SafeRefCounted<BackgroundCursorChildBase> { 481 private: 482 NS_DECL_OWNINGTHREAD 483 484 public: 485 MOZ_DECLARE_REFCOUNTED_TYPENAME( 486 mozilla::dom::indexedDB::BackgroundCursorChildBase) 487 MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(BackgroundCursorChildBase, 488 SafeRefCounted) 489 490 protected: 491 ~BackgroundCursorChildBase(); 492 493 InitializedOnce<const NotNull<IDBRequest*>> mRequest; 494 Maybe<IDBTransaction&> mTransaction; 495 496 // These are only set while a request is in progress. 497 RefPtr<IDBRequest> mStrongRequest; 498 RefPtr<IDBCursor> mStrongCursor; 499 500 const Direction mDirection; 501 502 BackgroundCursorChildBase(NotNull<IDBRequest*> aRequest, 503 Direction aDirection); 504 505 void HandleResponse(nsresult aResponse); 506 507 public: 508 void AssertIsOnOwningThread() const { 509 NS_ASSERT_OWNINGTHREAD(BackgroundCursorChildBase); 510 } 511 512 MovingNotNull<RefPtr<IDBRequest>> AcquireRequest() const; 513 514 NotNull<IDBRequest*> GetRequest() const { 515 AssertIsOnOwningThread(); 516 517 return *mRequest; 518 } 519 520 Direction GetDirection() const { 521 AssertIsOnOwningThread(); 522 523 return mDirection; 524 } 525 526 virtual void SendDeleteMeInternal() = 0; 527 528 virtual mozilla::ipc::IPCResult RecvResponse(CursorResponse&& aResponse) = 0; 529 }; 530 531 template <IDBCursorType CursorType> 532 class BackgroundCursorChild final : public BackgroundCursorChildBase { 533 public: 534 using SourceType = CursorSourceType<CursorType>; 535 using ResponseType = typename CursorTypeTraits<CursorType>::ResponseType; 536 537 private: 538 friend class BackgroundTransactionChild; 539 friend class BackgroundVersionChangeTransactionChild; 540 541 InitializedOnce<const NotNull<SourceType*>> mSource; 542 IDBCursorImpl<CursorType>* mCursor; 543 544 std::deque<CursorData<CursorType>> mCachedResponses, mDelayedResponses; 545 bool mInFlightResponseInvalidationNeeded; 546 547 public: 548 BackgroundCursorChild(NotNull<IDBRequest*> aRequest, SourceType* aSource, 549 Direction aDirection); 550 551 void SendContinueInternal(const int64_t aRequestId, 552 const CursorRequestParams& aParams, 553 const CursorData<CursorType>& aCurrentData); 554 555 void InvalidateCachedResponses(); 556 557 template <typename Condition> 558 void DiscardCachedResponses(const Condition& aConditionFunc); 559 560 SourceType* GetSource() const { 561 AssertIsOnOwningThread(); 562 563 return *mSource; 564 } 565 566 void SendDeleteMeInternal() final; 567 568 private: 569 // Only destroyed by BackgroundTransactionChild or 570 // BackgroundVersionChangeTransactionChild. 571 ~BackgroundCursorChild(); 572 573 void CompleteContinueRequestFromCache(); 574 575 using BackgroundCursorChildBase::HandleResponse; 576 577 void HandleResponse(const void_t& aResponse); 578 579 void HandleResponse(nsTArray<ResponseType>&& aResponses); 580 581 template <typename Func> 582 void HandleMultipleCursorResponses(nsTArray<ResponseType>&& aResponses, 583 const Func& aHandleRecord); 584 585 template <typename... Args> 586 [[nodiscard]] RefPtr<IDBCursor> HandleIndividualCursorResponse( 587 bool aUseAsCurrentResult, Args&&... aArgs); 588 589 SafeRefPtr<BackgroundCursorChild> SafeRefPtrFromThis(); 590 591 public: 592 // IPDL methods are only called by IPDL. 593 void ActorDestroy(ActorDestroyReason aWhy) override; 594 595 mozilla::ipc::IPCResult RecvResponse(CursorResponse&& aResponse) override; 596 597 // Force callers to use SendContinueInternal. 598 bool SendContinue(const int64_t& aRequestId, 599 const CursorRequestParams& aParams, const Key& aCurrentKey, 600 const Key& aCurrentObjectStoreKey) = delete; 601 602 bool SendDeleteMe() = delete; 603 }; 604 605 class BackgroundUtilsChild final : public PBackgroundIndexedDBUtilsChild { 606 friend class mozilla::ipc::BackgroundChildImpl; 607 friend IndexedDatabaseManager; 608 609 IndexedDatabaseManager* mManager; 610 611 NS_DECL_OWNINGTHREAD 612 613 public: 614 void AssertIsOnOwningThread() const { 615 NS_ASSERT_OWNINGTHREAD(BackgroundUtilsChild); 616 } 617 618 bool SendDeleteMe() = delete; 619 620 private: 621 // Only created by IndexedDatabaseManager. 622 explicit BackgroundUtilsChild(IndexedDatabaseManager* aManager); 623 624 // Only destroyed by mozilla::ipc::BackgroundChildImpl. 625 ~BackgroundUtilsChild(); 626 627 void SendDeleteMeInternal(); 628 629 public: 630 // IPDL methods are only called by IPDL. 631 void ActorDestroy(ActorDestroyReason aWhy) override; 632 }; 633 634 } // namespace mozilla::dom::indexedDB 635 636 #endif // mozilla_dom_indexeddb_actorschild_h__