Bug 773798 - Multi-process support for MediaStorage - Use PBlob. r=bent
authorDoug Turner <dougt@dougt.org>
Thu, 09 Aug 2012 15:41:18 -0700
changeset 102017 3664e5ab11b3981c3eb76cfe60438e64e8a22b93
parent 102016 cc583bf8519cc620daf6f957d74b8bd8dfcf074f
child 102018 ef06eb15d5208fe3b2b8b90f9d040dfb7af09c85
push id23261
push useremorley@mozilla.com
push dateFri, 10 Aug 2012 08:25:35 +0000
treeherdermozilla-central@b5ae446888f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs773798
milestone17.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 773798 - Multi-process support for MediaStorage - Use PBlob. r=bent
dom/devicestorage/DeviceStorageRequestChild.cpp
dom/devicestorage/DeviceStorageRequestParent.cpp
dom/devicestorage/DeviceStorageRequestParent.h
dom/devicestorage/PDeviceStorageRequest.ipdl
dom/devicestorage/nsDeviceStorage.cpp
dom/devicestorage/nsDeviceStorage.h
dom/ipc/ContentParent.cpp
dom/ipc/PContent.ipdl
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -2,16 +2,17 @@
 /* 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 "DeviceStorageRequestChild.h"
 #include "nsDeviceStorage.h"
 #include "nsDOMFile.h"
+#include "mozilla/dom/ipc/Blob.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 DeviceStorageRequestChild::DeviceStorageRequestChild()
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestChild);
@@ -23,16 +24,17 @@ DeviceStorageRequestChild::DeviceStorage
   , mFile(aFile)
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestChild);
 }
 
 DeviceStorageRequestChild::~DeviceStorageRequestChild() {
   MOZ_COUNT_DTOR(DeviceStorageRequestChild);
 }
+
 bool
 DeviceStorageRequestChild::Recv__delete__(const DeviceStorageResponseValue& aValue)
 {
   switch (aValue.type()) {
 
     case DeviceStorageResponseValue::TErrorResponse:
     {
       ErrorResponse r = aValue;
@@ -45,29 +47,18 @@ DeviceStorageRequestChild::Recv__delete_
       jsval result = StringToJsval(mRequest->GetOwner(), mFile->mPath);
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
-
-      // I am going to hell for this.  bent says he'll save me.
-      const InfallibleTArray<PRUint8> bits = r.bits();
-      void* buffer = PR_Malloc(bits.Length());
-      memcpy(buffer, (void*) bits.Elements(), bits.Length());
-
-      nsString mimeType;
-      mimeType.AssignWithConversion(r.contentType());
-
-      nsCOMPtr<nsIDOMBlob> blob = new nsDOMMemoryFile(buffer,
-                                                      bits.Length(),
-                                                      mFile->mPath,
-                                                      mimeType);
+      BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
+      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
 
       jsval result = BlobToJsval(mRequest->GetOwner(), blob);
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TEnumerationResponse:
     {
@@ -75,17 +66,17 @@ DeviceStorageRequestChild::Recv__delete_
       nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
 
       PRUint32 count = r.paths().Length();
       for (PRUint32 i = 0; i < count; i++) {
         nsCOMPtr<nsIFile> f;
         NS_NewLocalFile(r.paths()[i].fullpath(), false, getter_AddRefs(f));
 
         nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-        dsf->SetPath(r.paths()[i].path());
+        dsf->SetPath(r.paths()[i].name());
         cursor->mFiles.AppendElement(dsf);
       }
 
       nsCOMPtr<ContinueCursorEvent> event = new ContinueCursorEvent(cursor);
       NS_DispatchToMainThread(event);
       break;
     }
 
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -3,16 +3,19 @@
  * 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 "DeviceStorageRequestParent.h"
 #include "nsDOMFile.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "mozilla/unused.h"
+#include "mozilla/dom/ipc/Blob.h"
+#include "ContentParent.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 DeviceStorageRequestParent::DeviceStorageRequestParent(const DeviceStorageParams& aParams)
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestParent);
@@ -21,65 +24,73 @@ DeviceStorageRequestParent::DeviceStorag
     case DeviceStorageParams::TDeviceStorageAddParams:
     {
       DeviceStorageAddParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<WriteFileEvent> r = new WriteFileEvent(this, dsf, p.bits());
+
+      BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
+      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+
+      nsCOMPtr<nsIInputStream> stream;
+      blob->GetInternalStream(getter_AddRefs(stream));
+
+      nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageGetParams:
     {
       DeviceStorageGetParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<ReadFileEvent> r = new ReadFileEvent(this, dsf);
+      dsf->SetPath(p.name());
+      nsRefPtr<CancelableRunnable> r = new ReadFileEvent(this, dsf);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageDeleteParams:
     {
       DeviceStorageDeleteParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<DeleteFileEvent> r = new DeleteFileEvent(this, dsf);
+      nsRefPtr<CancelableRunnable> r = new DeleteFileEvent(this, dsf);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageEnumerationParams:
     {
       DeviceStorageEnumerationParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<EnumerateFileEvent> r = new EnumerateFileEvent(this, dsf, p.since());
+      nsRefPtr<CancelableRunnable> r = new EnumerateFileEvent(this, dsf, p.since());
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
     default:
     {
@@ -89,227 +100,251 @@ DeviceStorageRequestParent::DeviceStorag
   }
 }
 
 DeviceStorageRequestParent::~DeviceStorageRequestParent()
 {
   MOZ_COUNT_DTOR(DeviceStorageRequestParent);
 }
 
+NS_IMPL_THREADSAFE_ADDREF(DeviceStorageRequestParent);
+NS_IMPL_THREADSAFE_RELEASE(DeviceStorageRequestParent);
+
+void
+DeviceStorageRequestParent::ActorDestroy(ActorDestroyReason)
+{
+  PRInt32 count = mRunnables.Length();
+  for (PRInt32 index = 0; index < count; index++) {
+    mRunnables[index]->Cancel();
+  }
+}
+
 DeviceStorageRequestParent::PostErrorEvent::PostErrorEvent(DeviceStorageRequestParent* aParent,
                                                            const char* aError)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
 {
-  mError.AssignWithConversion(aError);
+  CopyASCIItoUTF16(aError, mError);
 }
 
 DeviceStorageRequestParent::PostErrorEvent::~PostErrorEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostErrorEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostErrorEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   ErrorResponse response(mError);
   unused << mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::PostSuccessEvent::PostSuccessEvent(DeviceStorageRequestParent* aParent)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
 {
 }
 
 DeviceStorageRequestParent::PostSuccessEvent::~PostSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   SuccessResponse response;
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent* aParent,
-                                                                       void* aBuffer,
+                                                                       DeviceStorageFile* aFile,
                                                                        PRUint32 aLength,
                                                                        nsACString& aMimeType)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
+  , mLength(aLength)
+  , mFile(aFile)
   , mMimeType(aMimeType)
 {
-  mBits.SetCapacity(aLength);
-  void* bits = mBits.Elements();
-  memcpy(bits, aBuffer, aLength);
 }
 
 DeviceStorageRequestParent::PostBlobSuccessEvent::~PostBlobSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostBlobSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  BlobResponse response(mBits, mMimeType);
+  nsString mime;
+  mime.AssignWithConversion(mMimeType);
+  CopyASCIItoUTF16(mMimeType, mime);
+
+  nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(mFile->mPath, mime, mLength, mFile->mFile);
+
+  ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
+  BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
+
+  BlobResponse response;
+  response.blobParent() = actor;
+
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::PostEnumerationSuccessEvent::PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent,
                                                                                      InfallibleTArray<DeviceStorageFileValue>& aPaths)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mPaths(aPaths)
 {
 }
 
 DeviceStorageRequestParent::PostEnumerationSuccessEvent::~PostEnumerationSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostEnumerationSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   EnumerationResponse response(mPaths);
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::WriteFileEvent::WriteFileEvent(DeviceStorageRequestParent* aParent,
                                                            DeviceStorageFile* aFile,
-                                                           InfallibleTArray<PRUint8>& aBits)
-  : mParent(aParent)
+                                                           nsIInputStream* aInputStream)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
-  , mBits(aBits)
+  , mInputStream(aInputStream)
 {
 }
 
 DeviceStorageRequestParent::WriteFileEvent::~WriteFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::WriteFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
   nsRefPtr<nsRunnable> r;
-  nsresult rv = mFile->Write(mBits);
+
+  if (!mInputStream) {
+    r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
+    NS_DispatchToMainThread(r);
+    return NS_OK;
+  }
+
+  nsresult rv = mFile->Write(mInputStream);
 
   if (NS_FAILED(rv)) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
   }
   else {
     r = new PostPathResultEvent(mParent, mFile->mPath);
   }
 
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::DeleteFileEvent::DeleteFileEvent(DeviceStorageRequestParent* aParent,
                                                              DeviceStorageFile* aFile)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
 {
 }
 
 DeviceStorageRequestParent::DeleteFileEvent::~DeleteFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::DeleteFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   mFile->mFile->Remove(true);
 
   nsRefPtr<nsRunnable> r;
 
   bool check = false;
   mFile->mFile->Exists(&check);
   if (check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
   }
   else {
     r = new PostPathResultEvent(mParent, mFile->mPath);
   }
+
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::ReadFileEvent::ReadFileEvent(DeviceStorageRequestParent* aParent,
                                                          DeviceStorageFile* aFile)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
 {
   nsCOMPtr<nsIMIMEService> mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID);
   if (mimeService) {
     nsresult rv = mimeService->GetTypeFromFile(mFile->mFile, mMimeType);
     if (NS_FAILED(rv)) {
       mMimeType.Truncate();
     }
   }
 }
 
 DeviceStorageRequestParent::ReadFileEvent::~ReadFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::ReadFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   nsCOMPtr<nsIRunnable> r;
   bool check = false;
   mFile->mFile->Exists(&check);
+
   if (!check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   PRInt64 fileSize;
   nsresult rv = mFile->mFile->GetFileSize(&fileSize);
   if (NS_FAILED(rv)) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
-  
-  PRFileDesc *fileHandle;
-  rv = mFile->mFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
 
-  // i am going to hell.  this is temp until bent provides seralizaiton of blobs.
-  void* buf = (void*) malloc(fileSize);
-  PRInt32 read = PR_Read(fileHandle, buf, fileSize); 
-  if (read != fileSize) {
-    r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
-    NS_DispatchToMainThread(r);
-    return NS_OK;
-  }
-
-  r = new PostBlobSuccessEvent(mParent, buf, fileSize, mMimeType);
-
-  PR_Free(buf);
-  PR_Close(fileHandle);
-
+  r = new PostBlobSuccessEvent(mParent, mFile, fileSize, mMimeType);
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::EnumerateFileEvent::EnumerateFileEvent(DeviceStorageRequestParent* aParent,
                                                                    DeviceStorageFile* aFile,
                                                                    PRUint32 aSince)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
   , mSince(aSince)
 {
 }
 
 DeviceStorageRequestParent::EnumerateFileEvent::~EnumerateFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::EnumerateFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   nsCOMPtr<nsIRunnable> r;
   bool check = false;
   mFile->mFile->Exists(&check);
   if (!check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
@@ -318,39 +353,39 @@ DeviceStorageRequestParent::EnumerateFil
   mFile->CollectFiles(files, mSince);
 
   InfallibleTArray<DeviceStorageFileValue> values;
 
   PRUint32 count = files.Length();
   for (PRUint32 i = 0; i < count; i++) {
     nsString fullpath;
     files[i]->mFile->GetPath(fullpath);
-    DeviceStorageFileValue dsvf(fullpath, files[i]->mPath);
+    DeviceStorageFileValue dsvf(files[i]->mPath, fullpath);
     values.AppendElement(dsvf);
   }
 
   r = new PostEnumerationSuccessEvent(mParent, values);
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::PostPathResultEvent::PostPathResultEvent(DeviceStorageRequestParent* aParent,
-                                                             const nsAString& aPath)
-  : mParent(aParent)
+                                                                     const nsAString& aPath)
+  : CancelableRunnable(aParent)
   , mPath(aPath)
 {
 }
 
 DeviceStorageRequestParent::PostPathResultEvent::~PostPathResultEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostPathResultEvent::Run()
+nsresult
+DeviceStorageRequestParent::PostPathResultEvent::CancelableRun()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   SuccessResponse response;
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
--- a/dom/devicestorage/DeviceStorageRequestParent.h
+++ b/dom/devicestorage/DeviceStorageRequestParent.h
@@ -6,131 +6,172 @@
 #ifndef mozilla_dom_devicestorage_DeviceStorageRequestParent_h
 #define mozilla_dom_devicestorage_DeviceStorageRequestParent_h
 
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestParent.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "nsThreadUtils.h"
 #include "nsDeviceStorage.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 class DeviceStorageRequestParent : public PDeviceStorageRequestParent
 {
 public:
   DeviceStorageRequestParent(const DeviceStorageParams& aParams);
+
+  NS_IMETHOD_(nsrefcnt) AddRef();
+  NS_IMETHOD_(nsrefcnt) Release();
+  virtual void ActorDestroy(ActorDestroyReason);
+
+protected:
   ~DeviceStorageRequestParent();
 
 private:
-  class PostErrorEvent : public nsRunnable
+  nsAutoRefCnt mRefCnt;
+
+  class CancelableRunnable : public nsRunnable
+  {
+  public:
+    CancelableRunnable(DeviceStorageRequestParent* aParent)
+      : mParent(aParent)
+      , mCanceled(false)
+    {
+      mParent->AddRunnable(this);
+    }
+
+    virtual ~CancelableRunnable() {
+    }
+
+    NS_IMETHOD Run() {
+      nsresult rv = NS_OK;
+      if (!mCanceled) {
+        rv = CancelableRun();
+        mParent->RemoveRunnable(this);
+      }
+      return rv;
+    }
+
+    void Cancel() {
+      mCanceled = true;
+    }
+
+    virtual nsresult CancelableRun() = 0;
+
+  protected:
+    nsRefPtr<DeviceStorageRequestParent> mParent;
+  private:
+    bool mCanceled;
+  };
+
+  class PostErrorEvent : public CancelableRunnable
   {
     public:
       PostErrorEvent(DeviceStorageRequestParent* aParent, const char* aError);
-      ~PostErrorEvent();
-      NS_IMETHOD Run();
+      virtual ~PostErrorEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsString mError;
   };
 
-  class PostSuccessEvent : public nsRunnable
+  class PostSuccessEvent : public CancelableRunnable
   {
     public:
       PostSuccessEvent(DeviceStorageRequestParent* aParent);
-      ~PostSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-  };
-
-  class PostBlobSuccessEvent : public nsRunnable
-  {
-    public:
-      PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, void* aBuffer, PRUint32 aLength, nsACString& aMimeType);
-      ~PostBlobSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      InfallibleTArray<PRUint8> mBits;
-      nsCString mMimeType;
-  };
-
-  class PostEnumerationSuccessEvent : public nsRunnable
-  {
-    public:
-      PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent, InfallibleTArray<DeviceStorageFileValue>& aPaths);
-      ~PostEnumerationSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      InfallibleTArray<DeviceStorageFileValue> mPaths;
+      virtual ~PostSuccessEvent();
+      virtual nsresult CancelableRun();
   };
 
-  class WriteFileEvent : public nsRunnable
-  {
-    public:
-      WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, InfallibleTArray<PRUint8>& aBits);
-      ~WriteFileEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      nsRefPtr<DeviceStorageFile> mFile;
-    InfallibleTArray<PRUint8> mBits; // another copy?
-  };
-
-  class DeleteFileEvent : public nsRunnable
+  class PostBlobSuccessEvent : public CancelableRunnable
   {
     public:
-      DeleteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
-      ~DeleteFileEvent();
-      NS_IMETHOD Run();
+      PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, PRUint32 aLength, nsACString& aMimeType);
+      virtual ~PostBlobSuccessEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
-      nsRefPtr<DeviceStorageFile> mFile;
-  };
-
-  class ReadFileEvent : public nsRunnable
-  {
-    public:
-      ReadFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
-      ~ReadFileEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
+      PRUint32 mLength;
       nsRefPtr<DeviceStorageFile> mFile;
       nsCString mMimeType;
   };
 
-  class EnumerateFileEvent : public nsRunnable
+  class PostEnumerationSuccessEvent : public CancelableRunnable
+  {
+    public:
+      PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent, InfallibleTArray<DeviceStorageFileValue>& aPaths);
+      virtual ~PostEnumerationSuccessEvent();
+      virtual nsresult CancelableRun();
+    private:
+      InfallibleTArray<DeviceStorageFileValue> mPaths;
+  };
+
+  class WriteFileEvent : public CancelableRunnable
+  {
+    public:
+      WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, nsIInputStream* aInputStream);
+      virtual ~WriteFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+      nsCOMPtr<nsIInputStream> mInputStream;
+  };
+
+  class DeleteFileEvent : public CancelableRunnable
+  {
+    public:
+      DeleteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
+      virtual ~DeleteFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+  };
+
+  class ReadFileEvent : public CancelableRunnable
+  {
+    public:
+      ReadFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
+      virtual ~ReadFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+      nsCString mMimeType;
+  };
+
+  class EnumerateFileEvent : public CancelableRunnable
   {
     public:
       EnumerateFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, PRUint32 aSince);
-      ~EnumerateFileEvent();
-      NS_IMETHOD Run();
+      virtual ~EnumerateFileEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsRefPtr<DeviceStorageFile> mFile;
       PRUint32 mSince;
   };
 
-  class PostPathResultEvent : public nsRunnable
+  class PostPathResultEvent : public CancelableRunnable
   {
     public:
       PostPathResultEvent(DeviceStorageRequestParent* aParent, const nsAString& aPath);
-      ~PostPathResultEvent();
-      NS_IMETHOD Run();
+      virtual ~PostPathResultEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsRefPtr<DeviceStorageFile> mFile;
-      InfallibleTArray<PRUint8> mBits;
       nsString mPath;
   };
 
+protected:
+  void AddRunnable(CancelableRunnable* aRunnable) {
+    mRunnables.AppendElement(aRunnable);
+  }
+  void RemoveRunnable(CancelableRunnable* aRunnable) {
+    mRunnables.RemoveElement(aRunnable);
+  }
+  nsTArray<nsRefPtr<CancelableRunnable> > mRunnables;
 };
 
 } // namespace devicestorage
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/devicestorage/PDeviceStorageRequest.ipdl
+++ b/dom/devicestorage/PDeviceStorageRequest.ipdl
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 protocol PBlob;
 include protocol PContent;
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 
 struct ErrorResponse
@@ -16,32 +17,28 @@ struct ErrorResponse
 };
 
 struct SuccessResponse
 {
 };
 
 struct BlobResponse
 {
-  // todo going away
-  PRUint8[] bits;
-  nsCString contentType;
+  PBlob blob;
 };
 
 struct DeviceStorageFileValue
 {
-  // todo going away
+  nsString name;
   nsString fullpath;
-  nsString path;
 };
 
 struct EnumerationResponse
 {
   DeviceStorageFileValue[] paths;
-  // todo bent PBlob
 };
 
 union DeviceStorageResponseValue
 {
   ErrorResponse;
   SuccessResponse;
   BlobResponse;
   EnumerationResponse;
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1,14 +1,15 @@
 /* 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 "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PContentPermissionRequestChild.h"
 
 #include "nsDeviceStorage.h"
 
 #include "nsDOMEvent.h"
 #include "nsServiceManagerUtils.h"
@@ -141,27 +142,29 @@ DeviceStorageFile::AppendRelativePath() 
   }
   mFile->AppendRelativePath(temp);
 #else
   mFile->AppendRelativePath(mPath);
 #endif
 }
 
 nsresult
-DeviceStorageFile::Write(nsIDOMBlob* aBlob)
+DeviceStorageFile::Write(nsIInputStream* aInputStream)
 {
+  if (!aInputStream) {
+    return NS_ERROR_FAILURE;
+  }
+
   nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  nsCOMPtr<nsIInputStream> stream;
-  aBlob->GetInternalStream(getter_AddRefs(stream));
 
   PRUint32 bufSize;
-  stream->Available(&bufSize);
+  aInputStream->Available(&bufSize);
 
   nsCOMPtr<nsIOutputStream> outputStream;
   NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile);
 
   if (!outputStream) {
     return NS_ERROR_FAILURE;
   }
 
@@ -170,17 +173,17 @@ DeviceStorageFile::Write(nsIDOMBlob* aBl
                              outputStream,
                              4096*4);
 
   if (!bufferedOutputStream) {
     return NS_ERROR_FAILURE;
   }
 
   PRUint32 wrote;
-  bufferedOutputStream->WriteFrom(stream, bufSize, &wrote);
+  bufferedOutputStream->WriteFrom(aInputStream, bufSize, &wrote);
   bufferedOutputStream->Close();
   outputStream->Close();
   if (bufSize != wrote) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
@@ -527,17 +530,16 @@ public:
     else {
       mError.Append(NS_LITERAL_STRING("null path"));
     }
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
     mRequest->FireError(mError);
     mRequest = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<DOMRequest> mRequest;
   nsString mError;
@@ -555,17 +557,16 @@ ContinueCursorEvent::ContinueCursorEvent
 
 ContinueCursorEvent::~ContinueCursorEvent() {}
 
 NS_IMETHODIMP
 ContinueCursorEvent::Run() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   jsval val;
-
   nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
   if (cursor->mFiles.Length() == 0) {
     val = JSVAL_NULL;
   }
   else {
     nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0];
     cursor->mFiles.RemoveElementAt(0);
 
@@ -813,17 +814,20 @@ public:
     }
 
   ~WriteFileEvent() {}
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
-    nsresult rv = mFile->Write(mBlob);
+    nsCOMPtr<nsIInputStream> stream;
+    mBlob->GetInternalStream(getter_AddRefs(stream));
+
+    nsresult rv = mFile->Write(stream);
 
     if (NS_FAILED(rv)) {
       mFile->mFile->Remove(false);
 
       nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
                                                           POST_ERROR_EVENT_UNKNOWN,
                                                           mFile);
       NS_DispatchToMainThread(event);
@@ -854,17 +858,16 @@ public:
 
   ~ReadFileEvent() {}
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     nsRefPtr<nsRunnable> r;
-
     if (!mFile->mEditable) {
       bool check = false;
       mFile->mFile->Exists(&check);
       if (!check) {
         r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
       }
     }
 
@@ -898,17 +901,17 @@ public:
 
     mFile->mFile->Remove(true);
 
     nsRefPtr<nsRunnable> r;
 
     bool check = false;
     mFile->mFile->Exists(&check);
     if (check) {
-      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_UNKNOWN, mFile);
+      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
     }
     else {
       r = new PostResultEvent(mRequest, mFile->mPath);
     }
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
@@ -1048,44 +1051,40 @@ public:
     switch(mRequestType) {
       case DEVICE_STORAGE_REQUEST_WRITE:
       {
         if (!mBlob) {
           return NS_ERROR_FAILURE;
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
-          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
 
-          nsCOMPtr<nsIInputStream> stream;
-          mBlob->GetInternalStream(getter_AddRefs(stream));
-
-          InfallibleTArray<PRUint8> bits;
-          PRUint32 bufSize, numRead;
+	  BlobChild* actor = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+	  if (!actor) {
+	    return NS_ERROR_FAILURE;
+	  }
 
-          stream->Available(&bufSize);
-          bits.SetCapacity(bufSize);
+          DeviceStorageAddParams params;
+	  params.blobChild() = actor;
+	  params.name() = mFile->mPath;
+	  params.fullpath() = fullpath;
 
-          void* buffer = (void*) bits.Elements();
-
-          stream->Read((char*)buffer, bufSize, &numRead);
-
-          DeviceStorageAddParams params(fullpath, bits);
+          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
         r = new WriteFileEvent(mBlob, mFile, mRequest);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_READ:
       {
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
-          DeviceStorageGetParams params(fullpath);
+          DeviceStorageGetParams params(mFile->mPath, fullpath);
           ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
 
         r = new ReadFileEvent(mFile, mRequest);
         break;
       }
 
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -48,18 +48,18 @@ public:
   void SetPath(const nsAString& aPath);
   void SetEditable(bool aEditable);
 
   NS_DECL_ISUPPORTS
 
   // we want to make sure that the names of file can't reach
   // outside of the type of storage the user asked for.
   bool IsSafePath();
-  
-  nsresult Write(nsIDOMBlob* blob);
+
+  nsresult Write(nsIInputStream* aInputStream);
   nsresult Write(InfallibleTArray<PRUint8>& bits);
   void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince = 0);
   void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince, nsAString& aRootPath);
 
 private:
   void NormalizeFilePath();
   void AppendRelativePath();
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -957,23 +957,26 @@ ContentParent::DeallocPBrowser(PBrowserP
     TabParent* parent = static_cast<TabParent*>(frame);
     NS_RELEASE(parent);
     return true;
 }
 
 PDeviceStorageRequestParent*
 ContentParent::AllocPDeviceStorageRequest(const DeviceStorageParams& aParams)
 {
-  return new DeviceStorageRequestParent(aParams);
+  DeviceStorageRequestParent* result = new DeviceStorageRequestParent(aParams);
+  NS_ADDREF(result);
+  return result;
 }
 
 bool
 ContentParent::DeallocPDeviceStorageRequest(PDeviceStorageRequestParent* doomed)
 {
-  delete doomed;
+  DeviceStorageRequestParent *parent = static_cast<DeviceStorageRequestParent*>(doomed);
+  NS_RELEASE(parent);
   return true;
 }
 
 PBlobParent*
 ContentParent::AllocPBlob(const BlobConstructorParams& aParams)
 {
   return BlobParent::Create(aParams);
 }
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -68,22 +68,24 @@ struct FontListEntry {
     PRUint16  weight;
     PRInt16   stretch;
     PRUint8   italic;
     PRUint8   index;
 };
 
 struct DeviceStorageAddParams
 {
+  PBlob blob;
+  nsString name;
   nsString fullpath;
-  PRUint8[] bits;
 };
 
 struct DeviceStorageGetParams
 {
+  nsString name;
   nsString fullpath;
 };
 
 struct DeviceStorageDeleteParams
 {
   nsString fullpath;
 };