/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "fs/FileSystemShutdownBlocker.h" #include "MainThreadUtils.h" #include "mozilla/Services.h" #include "mozilla/dom/quota/QuotaCommon.h" #include "mozilla/dom/quota/ResultExtensions.h" #include "nsComponentManagerUtils.h" #include "nsIAsyncShutdown.h" #include "nsISupportsImpl.h" #include "nsIWritablePropertyBag2.h" #include "nsStringFwd.h" namespace mozilla::dom::fs { namespace { nsString CreateBlockerName() { const int32_t blockerIdLength = 32; nsAutoCString blockerId; blockerId.SetLength(blockerIdLength); NS_MakeRandomString(blockerId.BeginWriting(), blockerIdLength); nsString blockerName = u"OPFS_"_ns; blockerName.Append(NS_ConvertUTF8toUTF16(blockerId)); return blockerName; } class FileSystemWritableBlocker : public FileSystemShutdownBlocker { public: FileSystemWritableBlocker() : mName(CreateBlockerName()) {} void SetCallback(std::function&& aCallback) override; NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIASYNCSHUTDOWNBLOCKER NS_IMETHODIMP Block() override; NS_IMETHODIMP Unblock() override; protected: virtual ~FileSystemWritableBlocker() = default; Result, nsresult> GetBarrier() const; private: const nsString mName; std::function mCallback; }; void FileSystemWritableBlocker::SetCallback(std::function&& aCallback) { mCallback = std::move(aCallback); } NS_IMPL_ISUPPORTS_INHERITED(FileSystemWritableBlocker, FileSystemShutdownBlocker, nsIAsyncShutdownBlocker) NS_IMETHODIMP FileSystemWritableBlocker::Block() { MOZ_ASSERT(NS_IsMainThread()); QM_TRY_UNWRAP(nsCOMPtr barrier, GetBarrier()); QM_TRY(MOZ_TO_RESULT(barrier->AddBlocker( this, NS_ConvertUTF8toUTF16(nsCString(__FILE__)), __LINE__, NS_ConvertUTF8toUTF16(nsCString(__func__))))); return NS_OK; } NS_IMETHODIMP FileSystemWritableBlocker::Unblock() { MOZ_ASSERT(NS_IsMainThread()); QM_TRY_UNWRAP(nsCOMPtr barrier, GetBarrier()); MOZ_ASSERT(NS_SUCCEEDED(barrier->RemoveBlocker(this))); return NS_OK; } Result, nsresult> FileSystemWritableBlocker::GetBarrier() const { nsCOMPtr svc = services::GetAsyncShutdownService(); QM_TRY(OkIf(svc), Err(NS_ERROR_FAILURE)); nsCOMPtr barrier; QM_TRY(MOZ_TO_RESULT(svc->GetXpcomWillShutdown(getter_AddRefs(barrier)))); return barrier.forget(); } NS_IMETHODIMP FileSystemWritableBlocker::GetName(nsAString& aName) { aName = mName; return NS_OK; } NS_IMETHODIMP FileSystemWritableBlocker::GetState(nsIPropertyBag** aBagOut) { MOZ_ASSERT(aBagOut); nsCOMPtr propertyBag = do_CreateInstance("@mozilla.org/hash-property-bag;1"); QM_TRY(OkIf(propertyBag), NS_ERROR_OUT_OF_MEMORY) propertyBag.forget(aBagOut); return NS_OK; } NS_IMETHODIMP FileSystemWritableBlocker::BlockShutdown( nsIAsyncShutdownClient* /* aBarrier */) { MOZ_ASSERT(NS_IsMainThread()); if (mCallback) { auto callback = std::move(mCallback); callback(); } return NS_OK; } class FileSystemNullBlocker : public FileSystemShutdownBlocker { public: void SetCallback(std::function&& aCallback) override {} NS_IMETHODIMP Block() override { return NS_OK; } NS_IMETHODIMP Unblock() override { return NS_OK; } protected: virtual ~FileSystemNullBlocker() = default; }; } // namespace /* static */ already_AddRefed FileSystemShutdownBlocker::CreateForWritable() { // The shutdown blocker watches for xpcom-will-shutdown which is not fired // during content process shutdown in release builds. #ifdef DEBUG if (NS_IsMainThread()) { RefPtr shutdownBlocker = new FileSystemWritableBlocker(); return shutdownBlocker.forget(); } #endif RefPtr shutdownBlocker = new FileSystemNullBlocker(); return shutdownBlocker.forget(); } NS_IMPL_ISUPPORTS(FileSystemShutdownBlocker, nsIAsyncShutdownBlocker) /* nsIAsyncShutdownBlocker methods */ NS_IMETHODIMP FileSystemShutdownBlocker::GetName(nsAString& /* aName */) { return NS_OK; } NS_IMETHODIMP FileSystemShutdownBlocker::GetState(nsIPropertyBag** /* aBagOut */) { return NS_OK; } NS_IMETHODIMP FileSystemShutdownBlocker::BlockShutdown( nsIAsyncShutdownClient* /* aBarrier */) { return NS_OK; } } // namespace mozilla::dom::fs