Bug 861894 - Avoid apps to schedule new offline cache downloads while device free space is low. r=honzab
authorFernando Jiménez <ferjmoreno@gmail.com>
Fri, 10 May 2013 16:16:56 +0200
changeset 143452 044d554846ff020bebc1503a5e00fdd6c21fd97e
parent 143451 ba7496b49c06b6a670a62a7c2d275eee52d38f1b
child 143453 6380de7328874e88b380b54c9cb8f1861360cf56
push id350
push userbbajaj@mozilla.com
push dateMon, 29 Jul 2013 23:00:49 +0000
treeherdermozilla-release@064965b37dbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs861894
milestone23.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 861894 - Avoid apps to schedule new offline cache downloads while device free space is low. r=honzab
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
uriloader/prefetch/nsOfflineCacheUpdateService.cpp
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -1773,16 +1773,26 @@ nsOfflineCacheUpdate::Begin()
 {
     LOG(("nsOfflineCacheUpdate::Begin [%p]", this));
 
     // Keep the object alive through a ProcessNextURI()/Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
     mItemsInProgress = 0;
 
+    if (mState == STATE_CANCELLED) {
+      nsRefPtr<nsRunnableMethod<nsOfflineCacheUpdate> > errorNotification =
+        NS_NewRunnableMethod(this,
+                             &nsOfflineCacheUpdate::AsyncFinishWithError);
+      nsresult rv = NS_DispatchToMainThread(errorNotification);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      return NS_OK;
+    }
+
     if (mPartialUpdate) {
         mState = STATE_DOWNLOADING;
         NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING);
         ProcessNextURI();
         return NS_OK;
     }
 
     // Start checking the manifest.
@@ -2148,16 +2158,23 @@ nsOfflineCacheUpdate::Finish()
 {
     nsresult rv = FinishNoNotify();
 
     NotifyState(nsIOfflineCacheUpdateObserver::STATE_FINISHED);
 
     return rv;
 }
 
+void
+nsOfflineCacheUpdate::AsyncFinishWithError()
+{
+    NotifyState(nsOfflineCacheUpdate::STATE_ERROR);
+    Finish();
+}
+
 static nsresult
 EvictOneOfCacheGroups(nsIApplicationCacheService *cacheService,
                       uint32_t count, const char * const *groups)
 {
     nsresult rv;
     unsigned int i;
 
     for (i = 0; i < count; i++) {
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -234,16 +234,18 @@ private:
     bool CheckUpdateAvailability();
     void NotifyUpdateAvailability(bool updateAvailable);
 
     void GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers);
     void NotifyState(uint32_t state);
     nsresult Finish();
     nsresult FinishNoNotify();
 
+    void AsyncFinishWithError();
+
     // Find one non-pinned cache group and evict it.
     nsresult EvictOneNonPinned();
 
     enum {
         STATE_UNINITIALIZED,
         STATE_INITIALIZED,
         STATE_CHECKING,
         STATE_DOWNLOADING,
@@ -350,11 +352,12 @@ public:
 
 private:
     nsresult ProcessNextUpdate();
 
     nsTArray<nsRefPtr<nsOfflineCacheUpdate> > mUpdates;
 
     bool mDisabled;
     bool mUpdateRunning;
+    bool mLowFreeSpace;
 };
 
 #endif
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -41,16 +41,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 #include "prlog.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
+#include "nsIDiskSpaceWatcher.h"
 
 using namespace mozilla;
 
 static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr;
 
 typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent;
 typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild;
 typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue;
@@ -256,16 +257,17 @@ NS_IMPL_ISUPPORTS3(nsOfflineCacheUpdateS
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateService <public>
 //-----------------------------------------------------------------------------
 
 nsOfflineCacheUpdateService::nsOfflineCacheUpdateService()
     : mDisabled(false)
     , mUpdateRunning(false)
+    , mLowFreeSpace(false)
 {
 }
 
 nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
 {
     gOfflineCacheUpdateService = nullptr;
 }
 
@@ -283,16 +285,29 @@ nsOfflineCacheUpdateService::Init()
     if (!observerService)
       return NS_ERROR_FAILURE;
 
     nsresult rv = observerService->AddObserver(this,
                                                NS_XPCOM_SHUTDOWN_OBSERVER_ID,
                                                true);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    // Get the current status of the disk in terms of free space and observe
+    // low device storage notifications.
+    nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcherService =
+      do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
+    if (diskSpaceWatcherService) {
+      diskSpaceWatcherService->GetIsDiskFull(&mLowFreeSpace);
+    } else {
+      NS_WARNING("Could not get disk status from nsIDiskSpaceWatcher");
+    }
+
+    rv = observerService->AddObserver(this, "disk-space-watcher", false);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     gOfflineCacheUpdateService = this;
 
     return NS_OK;
 }
 
 /* static */
 nsOfflineCacheUpdateService *
 nsOfflineCacheUpdateService::GetInstance()
@@ -403,16 +418,21 @@ nsOfflineCacheUpdateService::ProcessNext
     if (mDisabled)
         return NS_ERROR_ABORT;
 
     if (mUpdateRunning)
         return NS_OK;
 
     if (mUpdates.Length() > 0) {
         mUpdateRunning = true;
+        // Canceling the update before Begin() call will make the update
+        // asynchronously finish with an error.
+        if (mLowFreeSpace) {
+            mUpdates[0]->Cancel();
+        }
         return mUpdates[0]->Begin();
     }
 
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
@@ -594,16 +614,27 @@ nsOfflineCacheUpdateService::Observe(nsI
                                      const PRUnichar *aData)
 {
     if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
         if (mUpdates.Length() > 0)
             mUpdates[0]->Cancel();
         mDisabled = true;
     }
 
+    if (!strcmp(aTopic, "disk-space-watcher")) {
+        if (NS_LITERAL_STRING("full").Equals(aData)) {
+            mLowFreeSpace = true;
+            for (uint32_t i = 0; i < mUpdates.Length(); i++) {
+                mUpdates[i]->Cancel();
+            }
+        } else if (NS_LITERAL_STRING("free").Equals(aData)) {
+            mLowFreeSpace = false;
+        }
+    }
+
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateService::nsIOfflineCacheUpdateService
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP