FileSystemShutdownBlocker.cpp (4819B)
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 "fs/FileSystemShutdownBlocker.h" 8 9 #include "MainThreadUtils.h" 10 #include "mozilla/Services.h" 11 #include "mozilla/dom/quota/QuotaCommon.h" 12 #include "mozilla/dom/quota/ResultExtensions.h" 13 #include "nsComponentManagerUtils.h" 14 #include "nsIAsyncShutdown.h" 15 #include "nsISupportsImpl.h" 16 #include "nsIWritablePropertyBag2.h" 17 #include "nsStringFwd.h" 18 19 namespace mozilla::dom::fs { 20 21 namespace { 22 23 nsString CreateBlockerName() { 24 const int32_t blockerIdLength = 32; 25 nsAutoCString blockerId; 26 blockerId.SetLength(blockerIdLength); 27 NS_MakeRandomString(blockerId.BeginWriting(), blockerIdLength); 28 29 nsString blockerName = u"OPFS_"_ns; 30 blockerName.Append(NS_ConvertUTF8toUTF16(blockerId)); 31 32 return blockerName; 33 } 34 35 class FileSystemWritableBlocker : public FileSystemShutdownBlocker { 36 public: 37 FileSystemWritableBlocker() : mName(CreateBlockerName()) {} 38 39 void SetCallback(std::function<void()>&& aCallback) override; 40 41 NS_DECL_ISUPPORTS_INHERITED 42 NS_DECL_NSIASYNCSHUTDOWNBLOCKER 43 44 NS_IMETHODIMP Block() override; 45 46 NS_IMETHODIMP Unblock() override; 47 48 protected: 49 virtual ~FileSystemWritableBlocker() = default; 50 51 Result<already_AddRefed<nsIAsyncShutdownClient>, nsresult> GetBarrier() const; 52 53 private: 54 const nsString mName; 55 std::function<void()> mCallback; 56 }; 57 58 void FileSystemWritableBlocker::SetCallback(std::function<void()>&& aCallback) { 59 mCallback = std::move(aCallback); 60 } 61 62 NS_IMPL_ISUPPORTS_INHERITED(FileSystemWritableBlocker, 63 FileSystemShutdownBlocker, nsIAsyncShutdownBlocker) 64 65 NS_IMETHODIMP FileSystemWritableBlocker::Block() { 66 MOZ_ASSERT(NS_IsMainThread()); 67 QM_TRY_UNWRAP(nsCOMPtr<nsIAsyncShutdownClient> barrier, GetBarrier()); 68 69 QM_TRY(MOZ_TO_RESULT(barrier->AddBlocker( 70 this, NS_ConvertUTF8toUTF16(nsCString(__FILE__)), __LINE__, 71 NS_ConvertUTF8toUTF16(nsCString(__func__))))); 72 73 return NS_OK; 74 } 75 76 NS_IMETHODIMP FileSystemWritableBlocker::Unblock() { 77 MOZ_ASSERT(NS_IsMainThread()); 78 QM_TRY_UNWRAP(nsCOMPtr<nsIAsyncShutdownClient> barrier, GetBarrier()); 79 80 MOZ_ASSERT(NS_SUCCEEDED(barrier->RemoveBlocker(this))); 81 82 return NS_OK; 83 } 84 85 Result<already_AddRefed<nsIAsyncShutdownClient>, nsresult> 86 FileSystemWritableBlocker::GetBarrier() const { 87 nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService(); 88 QM_TRY(OkIf(svc), Err(NS_ERROR_FAILURE)); 89 90 nsCOMPtr<nsIAsyncShutdownClient> barrier; 91 QM_TRY(MOZ_TO_RESULT(svc->GetXpcomWillShutdown(getter_AddRefs(barrier)))); 92 93 return barrier.forget(); 94 } 95 96 NS_IMETHODIMP 97 FileSystemWritableBlocker::GetName(nsAString& aName) { 98 aName = mName; 99 100 return NS_OK; 101 } 102 103 NS_IMETHODIMP 104 FileSystemWritableBlocker::GetState(nsIPropertyBag** aBagOut) { 105 MOZ_ASSERT(aBagOut); 106 107 nsCOMPtr<nsIWritablePropertyBag2> propertyBag = 108 do_CreateInstance("@mozilla.org/hash-property-bag;1"); 109 110 QM_TRY(OkIf(propertyBag), NS_ERROR_OUT_OF_MEMORY) 111 112 propertyBag.forget(aBagOut); 113 114 return NS_OK; 115 } 116 117 NS_IMETHODIMP 118 FileSystemWritableBlocker::BlockShutdown( 119 nsIAsyncShutdownClient* /* aBarrier */) { 120 MOZ_ASSERT(NS_IsMainThread()); 121 122 if (mCallback) { 123 auto callback = std::move(mCallback); 124 callback(); 125 } 126 127 return NS_OK; 128 } 129 130 class FileSystemNullBlocker : public FileSystemShutdownBlocker { 131 public: 132 void SetCallback(std::function<void()>&& aCallback) override {} 133 134 NS_IMETHODIMP Block() override { return NS_OK; } 135 136 NS_IMETHODIMP Unblock() override { return NS_OK; } 137 138 protected: 139 virtual ~FileSystemNullBlocker() = default; 140 }; 141 142 } // namespace 143 144 /* static */ 145 already_AddRefed<FileSystemShutdownBlocker> 146 FileSystemShutdownBlocker::CreateForWritable() { 147 // The shutdown blocker watches for xpcom-will-shutdown which is not fired 148 // during content process shutdown in release builds. 149 #ifdef DEBUG 150 if (NS_IsMainThread()) { 151 RefPtr<FileSystemShutdownBlocker> shutdownBlocker = 152 new FileSystemWritableBlocker(); 153 154 return shutdownBlocker.forget(); 155 } 156 #endif 157 158 RefPtr<FileSystemShutdownBlocker> shutdownBlocker = 159 new FileSystemNullBlocker(); 160 161 return shutdownBlocker.forget(); 162 } 163 164 NS_IMPL_ISUPPORTS(FileSystemShutdownBlocker, nsIAsyncShutdownBlocker) 165 166 /* nsIAsyncShutdownBlocker methods */ 167 NS_IMETHODIMP 168 FileSystemShutdownBlocker::GetName(nsAString& /* aName */) { return NS_OK; } 169 170 NS_IMETHODIMP 171 FileSystemShutdownBlocker::GetState(nsIPropertyBag** /* aBagOut */) { 172 return NS_OK; 173 } 174 175 NS_IMETHODIMP 176 FileSystemShutdownBlocker::BlockShutdown( 177 nsIAsyncShutdownClient* /* aBarrier */) { 178 return NS_OK; 179 } 180 181 } // namespace mozilla::dom::fs