Bug 1526891 - Part 7: Move base dir path initialization to a profile observer; r=asuth
authorJan Varga <jan.varga@gmail.com>
Sat, 23 Feb 2019 17:12:09 +0100
changeset 520820 bb96024458d0e147889b755048cd19c5b8573a01
parent 520819 4733f0d7f7c5dd802a5bda3e040dd20946da3023
child 520821 1213eb6430d9e5a10323be7fec19883a19873823
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1526891
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1526891 - Part 7: Move base dir path initialization to a profile observer; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D20916
dom/quota/ActorsParent.cpp
dom/quota/QuotaManager.h
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -213,16 +213,18 @@ enum AppId {
 #define METADATA_TMP_FILE_NAME ".metadata-tmp"
 #define METADATA_V2_FILE_NAME ".metadata-v2"
 #define METADATA_V2_TMP_FILE_NAME ".metadata-v2-tmp"
 
 #define WEB_APPS_STORE_FILE_NAME "webappsstore.sqlite"
 #define LS_ARCHIVE_FILE_NAME "ls-archive.sqlite"
 #define LS_ARCHIVE_TMP_FILE_NAME "ls-archive-tmp.sqlite"
 
+const char kProfileDoChangeTopic[] = "profile-do-change";
+
 /******************************************************************************
  * SQLite functions
  ******************************************************************************/
 
 int32_t MakeStorageVersion(uint32_t aMajorStorageVersion,
                            uint32_t aMinorStorageVersion) {
   return int32_t((aMajorStorageVersion << 16) + aMinorStorageVersion);
 }
@@ -415,23 +417,21 @@ class DirectoryLockImpl final : public D
  private:
   ~DirectoryLockImpl();
 };
 
 class QuotaManager::CreateRunnable final : public BackgroundThreadObject,
                                            public Runnable {
   nsCOMPtr<nsIEventTarget> mMainEventTarget;
   nsTArray<nsCOMPtr<nsIRunnable>> mCallbacks;
-  nsString mBaseDirPath;
   RefPtr<QuotaManager> mManager;
   nsresult mResultCode;
 
   enum class State {
     Initial,
-    CreatingManager,
     RegisteringObserver,
     CallingCallbacks,
     Completed
   };
 
   State mState;
 
  public:
@@ -450,18 +450,16 @@ class QuotaManager::CreateRunnable final
     mCallbacks.AppendElement(aCallback);
   }
 
  private:
   ~CreateRunnable() {}
 
   nsresult Init();
 
-  nsresult CreateManager();
-
   nsresult RegisterObserver();
 
   void CallCallbacks();
 
   State GetNextState(nsCOMPtr<nsIEventTarget>& aThread);
 
   NS_DECL_NSIRUNNABLE
 };
@@ -493,16 +491,33 @@ class QuotaManager::ShutdownObserver fin
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
  private:
   ~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
 };
 
+class QuotaManager::Observer final : public nsIObserver {
+ public:
+  static nsresult Initialize();
+
+ private:
+  Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+
+  ~Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+
+  nsresult Init();
+
+  nsresult Shutdown();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+};
+
 namespace {
 
 /*******************************************************************************
  * Local class declarations
  ******************************************************************************/
 
 }  // namespace
 
@@ -1351,16 +1366,18 @@ void ReportInternalError(const char* aFi
       NS_ConvertUTF8toUTF16(
           nsPrintfCString("Quota %s: %s:%" PRIu32, aStr, aFile, aLine)),
       "quota",
       false /* Quota Manager is not active in private browsing mode */);
 }
 
 namespace {
 
+nsString gBaseDirPath;
+
 #ifdef DEBUG
 bool gQuotaManagerInitialized = false;
 #endif
 
 StaticRefPtr<QuotaManager> gInstance;
 bool gCreateFailed = false;
 StaticRefPtr<QuotaManager::CreateRunnable> gCreateRunnable;
 mozilla::Atomic<bool> gShutdown(false);
@@ -2161,16 +2178,20 @@ nsresult GetTemporaryStorageLimit(nsIFil
  * Exported functions
  ******************************************************************************/
 
 void InitializeQuotaManager() {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!gQuotaManagerInitialized);
 
+  if (NS_FAILED(QuotaManager::Initialize())) {
+    NS_WARNING("Failed to initialize quota manager!");
+  }
+
 #ifdef DEBUG
   gQuotaManagerInitialized = true;
 #endif
 }
 
 PQuotaParent* AllocPQuotaParent() {
   AssertIsOnBackgroundThread();
 
@@ -2287,47 +2308,23 @@ void DirectoryLockImpl::NotifyOpenListen
   }
 
   mOpenListener = nullptr;
 
   mQuotaManager->RemovePendingDirectoryLock(this);
 }
 
 nsresult QuotaManager::CreateRunnable::Init() {
-  MOZ_ASSERT(NS_IsMainThread());
+  AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::Initial);
-
-  nsresult rv;
-
-  nsCOMPtr<nsIFile> baseDir;
-  rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
-                              getter_AddRefs(baseDir));
-  if (NS_FAILED(rv)) {
-    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                getter_AddRefs(baseDir));
-  }
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = baseDir->GetPath(mBaseDirPath);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult QuotaManager::CreateRunnable::CreateManager() {
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(mState == State::CreatingManager);
+  MOZ_ASSERT(!gBaseDirPath.IsEmpty());
 
   mManager = new QuotaManager();
 
-  nsresult rv = mManager->Init(mBaseDirPath);
+  nsresult rv = mManager->Init(gBaseDirPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult QuotaManager::CreateRunnable::RegisterObserver() {
@@ -2402,19 +2399,16 @@ void QuotaManager::CreateRunnable::CallC
     Unused << callback->Run();
   }
 }
 
 auto QuotaManager::CreateRunnable::GetNextState(
     nsCOMPtr<nsIEventTarget>& aThread) -> State {
   switch (mState) {
     case State::Initial:
-      aThread = mOwningThread;
-      return State::CreatingManager;
-    case State::CreatingManager:
       if (mMainEventTarget) {
         aThread = mMainEventTarget;
       } else {
         aThread = GetMainThreadEventTarget();
       }
       return State::RegisteringObserver;
     case State::RegisteringObserver:
       aThread = mOwningThread;
@@ -2431,20 +2425,16 @@ NS_IMETHODIMP
 QuotaManager::CreateRunnable::Run() {
   nsresult rv;
 
   switch (mState) {
     case State::Initial:
       rv = Init();
       break;
 
-    case State::CreatingManager:
-      rv = CreateManager();
-      break;
-
     case State::RegisteringObserver:
       rv = RegisterObserver();
       break;
 
     case State::CallingCallbacks:
       CallCallbacks();
       rv = NS_OK;
       break;
@@ -2528,16 +2518,116 @@ QuotaManager::ShutdownObserver::Observe(
   bool done = false;
 
   RefPtr<ShutdownRunnable> shutdownRunnable = new ShutdownRunnable(done);
   MOZ_ALWAYS_SUCCEEDS(
       mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
 
   MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
 
+  gBaseDirPath.Truncate();
+
+  return NS_OK;
+}
+
+// static
+nsresult QuotaManager::Observer::Initialize() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<Observer> observer = new Observer();
+
+  nsresult rv = observer->Init();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult QuotaManager::Observer::Init() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = obs->AddObserver(this, kProfileDoChangeTopic, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+nsresult QuotaManager::Observer::Shutdown() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ALWAYS_SUCCEEDS(obs->RemoveObserver(this, kProfileDoChangeTopic));
+  MOZ_ALWAYS_SUCCEEDS(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
+
+  // In general, the instance will have died after the latter removal call, so
+  // it's not safe to do anything after that point.
+  // However, Shutdown is currently called from Observe which is called by the
+  // Observer Service which holds a strong reference to the observer while the
+  // Observe method is being called.
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(QuotaManager::Observer, nsIObserver)
+
+NS_IMETHODIMP
+QuotaManager::Observer::Observe(nsISupports* aSubject, const char* aTopic,
+                                const char16_t* aData) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv;
+
+  if (!strcmp(aTopic, kProfileDoChangeTopic)) {
+    nsCOMPtr<nsIFile> baseDir;
+    rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
+                                getter_AddRefs(baseDir));
+    if (NS_FAILED(rv)) {
+      rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                  getter_AddRefs(baseDir));
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = baseDir->GetPath(gBaseDirPath);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    return NS_OK;
+  }
+
+  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+    rv = Shutdown();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    return NS_OK;
+  }
+
+  NS_WARNING("Unknown observer topic!");
   return NS_OK;
 }
 
 /*******************************************************************************
  * Quota object
  ******************************************************************************/
 
 void QuotaObject::AddRef() {
@@ -2859,16 +2949,28 @@ QuotaManager::QuotaManager()
   MOZ_ASSERT(!gInstance);
 }
 
 QuotaManager::~QuotaManager() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!gInstance || gInstance == this);
 }
 
+// static
+nsresult QuotaManager::Initialize() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv = Observer::Initialize();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 void QuotaManager::GetOrCreate(nsIRunnable* aCallback,
                                nsIEventTarget* aMainEventTarget) {
   AssertIsOnBackgroundThread();
 
   if (IsShuttingDown()) {
     MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!");
     return;
   }
@@ -2876,22 +2978,17 @@ void QuotaManager::GetOrCreate(nsIRunnab
   if (gInstance || gCreateFailed) {
     MOZ_ASSERT(!gCreateRunnable);
     MOZ_ASSERT_IF(gCreateFailed, !gInstance);
 
     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(aCallback));
   } else {
     if (!gCreateRunnable) {
       gCreateRunnable = new CreateRunnable(aMainEventTarget);
-      if (aMainEventTarget) {
-        MOZ_ALWAYS_SUCCEEDS(
-            aMainEventTarget->Dispatch(gCreateRunnable, NS_DISPATCH_NORMAL));
-      } else {
-        MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(gCreateRunnable));
-      }
+      NS_DispatchToCurrentThread(gCreateRunnable);
     }
 
     gCreateRunnable->AddCallback(aCallback);
   }
 }
 
 // static
 QuotaManager* QuotaManager::Get() {
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -96,20 +96,23 @@ class QuotaManager final : public Backgr
       DirectoryLockTable;
 
  public:
   class CreateRunnable;
 
  private:
   class ShutdownRunnable;
   class ShutdownObserver;
+  class Observer;
 
  public:
   NS_INLINE_DECL_REFCOUNTING(QuotaManager)
 
+  static nsresult Initialize();
+
   static bool IsRunningXPCShellTests() {
     static bool kRunningXPCShellTests =
         !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
     return kRunningXPCShellTests;
   }
 
   static bool IsRunningGTests() {
     static bool kRunningGTests = !!PR_GetEnv("MOZ_RUN_GTEST");