EarlyHintRegistrar.cpp (3734B)
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 "EarlyHintRegistrar.h" 8 9 #include "EarlyHintPreloader.h" 10 #include "mozilla/ClearOnShutdown.h" 11 #include "mozilla/StaticPtr.h" 12 #include "nsIObserver.h" 13 #include "nsIObserverService.h" 14 #include "nsXULAppAPI.h" 15 16 namespace { 17 mozilla::StaticRefPtr<mozilla::net::EarlyHintRegistrar> gSingleton; 18 } // namespace 19 20 namespace mozilla::net { 21 22 namespace { 23 24 class EHShutdownObserver final : public nsIObserver { 25 public: 26 EHShutdownObserver() = default; 27 28 NS_DECL_ISUPPORTS 29 NS_DECL_NSIOBSERVER 30 31 private: 32 ~EHShutdownObserver() = default; 33 }; 34 35 NS_IMPL_ISUPPORTS(EHShutdownObserver, nsIObserver) 36 37 NS_IMETHODIMP 38 EHShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic, 39 const char16_t* aData) { 40 EarlyHintRegistrar::CleanUp(); 41 return NS_OK; 42 } 43 44 } // namespace 45 46 EarlyHintRegistrar::EarlyHintRegistrar() { 47 // EarlyHintRegistrar is a main-thread-only object. 48 // All the operations should be run on main thread. 49 // It should be used on chrome process only. 50 MOZ_ASSERT(XRE_IsParentProcess()); 51 MOZ_ASSERT(NS_IsMainThread()); 52 } 53 54 EarlyHintRegistrar::~EarlyHintRegistrar() { MOZ_ASSERT(NS_IsMainThread()); } 55 56 // static 57 void EarlyHintRegistrar::CleanUp() { 58 MOZ_ASSERT(NS_IsMainThread()); 59 60 if (!gSingleton) { 61 return; 62 } 63 64 for (auto& preloader : gSingleton->mEarlyHint) { 65 if (auto p = preloader.GetData()) { 66 // Don't delete entry from EarlyHintPreloader, because that would 67 // invalidate the iterator. 68 69 p->CancelChannel(NS_ERROR_ABORT, "EarlyHintRegistrar::CleanUp"_ns, 70 /* aDeleteEntry */ false); 71 } 72 } 73 gSingleton->mEarlyHint.Clear(); 74 } 75 76 // static 77 already_AddRefed<EarlyHintRegistrar> EarlyHintRegistrar::GetOrCreate() { 78 MOZ_ASSERT(NS_IsMainThread()); 79 80 if (!gSingleton) { 81 gSingleton = new EarlyHintRegistrar(); 82 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 83 if (NS_WARN_IF(!obs)) { 84 return nullptr; 85 } 86 nsCOMPtr<nsIObserver> observer = new EHShutdownObserver(); 87 nsresult rv = 88 obs->AddObserver(observer, "profile-change-net-teardown", false); 89 if (NS_WARN_IF(NS_FAILED(rv))) { 90 return nullptr; 91 } 92 mozilla::ClearOnShutdown(&gSingleton); 93 } 94 return do_AddRef(gSingleton); 95 } 96 97 void EarlyHintRegistrar::DeleteEntry(dom::ContentParentId aCpId, 98 uint64_t aEarlyHintPreloaderId) { 99 MOZ_ASSERT(NS_IsMainThread()); 100 101 RefPtr<EarlyHintPreloader> ehp = mEarlyHint.Get(aEarlyHintPreloaderId); 102 if (ehp && ehp->IsFromContentParent(aCpId)) { 103 mEarlyHint.Remove(aEarlyHintPreloaderId); 104 } 105 } 106 107 void EarlyHintRegistrar::RegisterEarlyHint(uint64_t aEarlyHintPreloaderId, 108 EarlyHintPreloader* aEhp) { 109 MOZ_ASSERT(NS_IsMainThread()); 110 MOZ_ASSERT(aEhp); 111 112 mEarlyHint.InsertOrUpdate(aEarlyHintPreloaderId, RefPtr{aEhp}); 113 } 114 115 bool EarlyHintRegistrar::LinkParentChannel(dom::ContentParentId aCpId, 116 uint64_t aEarlyHintPreloaderId, 117 nsIParentChannel* aParent) { 118 MOZ_ASSERT(NS_IsMainThread()); 119 MOZ_ASSERT(aParent); 120 121 RefPtr<EarlyHintPreloader> ehp; 122 bool found = mEarlyHint.Get(aEarlyHintPreloaderId, getter_AddRefs(ehp)); 123 if (ehp && ehp->IsFromContentParent(aCpId)) { 124 ehp->OnParentReady(aParent); 125 } 126 MOZ_ASSERT(ehp || !found); 127 return found; 128 } 129 130 } // namespace mozilla::net