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 131677 044d554846ff020bebc1503a5e00fdd6c21fd97e
parent 131676 ba7496b49c06b6a670a62a7c2d275eee52d38f1b
child 131678 6380de7328874e88b380b54c9cb8f1861360cf56
push id1614
push userryanvm@gmail.com
push dateMon, 13 May 2013 20:34:17 +0000
treeherderfx-team@ccd3e170abb4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs861894
milestone23.0a1
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