Backed out changeset b416fc68c0a2 (bug 1257180) for crash in test_performance_user_timing.html on Android debug. r=backout on a CLOSED TREE
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 12 Apr 2016 17:56:15 +0200
changeset 316625 99c2637bbc2652d11926c9c39909cc2dbec33bda
parent 316624 c8b356c569cecd317802e4503b876ba94eda57b3
child 316626 498c618afddf075175a8436b6775f0bfa764e9e0
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1257180
milestone48.0a1
backs outb416fc68c0a2d4ea2640a31826233aa053c058c8
Backed out changeset b416fc68c0a2 (bug 1257180) for crash in test_performance_user_timing.html on Android debug. r=backout on a CLOSED TREE
dom/base/FileList.cpp
dom/base/test/test_postMessages.html
dom/filesystem/Directory.cpp
dom/filesystem/Directory.h
dom/filesystem/FileSystemBase.h
dom/filesystem/FileSystemPermissionRequest.cpp
dom/filesystem/FileSystemPermissionRequest.h
dom/filesystem/FileSystemTaskBase.cpp
dom/filesystem/GetDirectoryListingTask.cpp
dom/filesystem/OSFileSystem.cpp
dom/filesystem/OSFileSystem.h
dom/filesystem/tests/mochitest.ini
dom/filesystem/tests/test_worker_basic.html
dom/filesystem/tests/worker_basic.js
dom/webidl/Directory.webidl
dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
dom/workers/test/test_worker_interfaces.js
--- a/dom/base/FileList.cpp
+++ b/dom/base/FileList.cpp
@@ -110,18 +110,17 @@ FileList::ToSequence(Sequence<OwningFile
     aSequence[i] = mFilesOrDirectories[i];
   }
 }
 
 bool
 FileList::ClonableToDifferentThreadOrProcess() const
 {
   for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
-    if (mFilesOrDirectories[i].IsDirectory() &&
-        !mFilesOrDirectories[i].GetAsDirectory()->ClonableToDifferentThreadOrProcess()) {
+    if (mFilesOrDirectories[i].IsDirectory()) {
       return false;
     }
   }
 
   return true;
 }
 
 } // namespace dom
--- a/dom/base/test/test_postMessages.html
+++ b/dom/base/test/test_postMessages.html
@@ -56,40 +56,40 @@ function compare(a, b) {
   }
 
   if (type != 'null') {
     is (a.toSource(), b.toSource(), 'Matching using toSource()');
   }
 }
 
 var clonableObjects = [
-  'hello world',
-  123,
-  null,
-  true,
-  new Date(),
-  [ 1, 'test', true, new Date() ],
-  { a: true, b:  null, c: new Date(), d: [ true, false, {} ] },
-  new Blob([123], { type: 'plain/text' }),
-  new ImageData(2, 2),
+  { crossThreads: true, data: 'hello world' },
+  { crossThreads: true, data: 123 },
+  { crossThreads: true, data: null },
+  { crossThreads: true, data: true },
+  { crossThreads: true, data: new Date() },
+  { crossThreads: true, data: [ 1, 'test', true, new Date() ] },
+  { crossThreads: true, data: { a: true, b:  null, c: new Date(), d: [ true, false, {} ] } },
+  { crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
+  { crossThreads: true, data: new ImageData(2, 2) },
 ];
 
 function create_fileList_forFile() {
   var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
 
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
 
     // Just a simple test
     var domFile = fileList.files[0];
     is(domFile.name, "prefs.js", "fileName should be prefs.js");
 
-    clonableObjects.push(fileList.files);
+    clonableObjects.push({ crossThreads: true, data: fileList.files });
     script.destroy();
     next();
   }
 
   script.addMessageListener("file.opened", onOpened);
   script.sendAsyncMessage("file.open");
 }
 
@@ -100,17 +100,17 @@ function create_fileList_forDir() {
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
 
     // Just a simple test
     is(fileList.files.length, 1, "Filelist has 1 element");
     ok(fileList.files[0] instanceof Directory, "We have a directory.");
 
-    clonableObjects.push(fileList.files);
+    clonableObjects.push({ crossThreads: false, data: fileList.files });
     script.destroy();
     next();
   }
 
   script.addMessageListener("dir.opened", onOpened);
   script.sendAsyncMessage("dir.open");
 }
 
@@ -130,18 +130,25 @@ function runTests(obj) {
     function runClonableTest() {
       if (clonableObjectsId >= clonableObjects.length) {
         resolve();
         return;
       }
 
       var object = clonableObjects[clonableObjectsId++];
 
-      obj.send(object, []).then(function(received) {
-        compare(received.data, object);
+      // If this test requires a cross-thread structured clone algorithm, maybe
+      // we have to skip it.
+      if (!object.crossThread && obj.crossThread) {
+        runClonableTest();
+        return;
+      }
+
+      obj.send(object.data, []).then(function(received) {
+        compare(received.data, object.data);
         runClonableTest();
       });
     }
 
     runClonableTest();
   })
 
   // transfering tests
@@ -220,16 +227,17 @@ function test_windowToWindow() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: e.ports });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: true,
+    crossThread: false,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         resolve = r;
 
         try {
           postMessage(what, '*', ports);
         } catch(e) {
           resolve = null;
@@ -273,16 +281,17 @@ function test_windowToIframeURL(url) {
   }
 
   var ifr = document.createElement('iframe');
   ifr.src = url;
   ifr.onload = function() {
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: false,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             ifr.contentWindow.postMessage(what, '*', ports);
           } catch(e) {
             resolve = null;
             rr();
@@ -320,16 +329,17 @@ function test_workers() {
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             w.postMessage(what, ports);
           } catch(e) {
             resolve = null;
             rr();
@@ -363,16 +373,17 @@ function test_broadcastChannel() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: [] });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: false,
+    crossThread: true,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         if (ports.length) {
           rr();
           return;
         }
 
         resolve = r;
@@ -408,16 +419,17 @@ function test_broadcastChannel_inWorkers
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: false,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           if (ports.length) {
             rr();
             return;
           }
 
           resolve = r;
@@ -449,16 +461,17 @@ function test_messagePort() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: e.ports });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: true,
+    crossThread: true,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         resolve = r;
         try {
           mc.port1.postMessage(what, ports);
         } catch(e) {
           resolve = null;
           rr();
@@ -494,16 +507,17 @@ function test_messagePort_inWorkers() {
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             mc.port1.postMessage(what, ports);
           } catch(e) {
             resolve = null;
             rr();
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -106,31 +106,20 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCA
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-/* static */ bool
-Directory::DeviceStorageEnabled(JSContext* aCx, JSObject* aObj)
-{
-  if (!NS_IsMainThread()) {
-    return false;
-  }
-
-  return Preferences::GetBool("device.storage.enabled", false);
-}
-
-/* static */ already_AddRefed<Promise>
+// static
+already_AddRefed<Promise>
 Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aFileSystem);
 
   nsCOMPtr<nsIFile> path;
   aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->LocalOrDeviceStorageRootPath()),
                               true, getter_AddRefs(path));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
@@ -145,16 +134,17 @@ Directory::GetRoot(FileSystemBase* aFile
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 /* static */ already_AddRefed<Directory>
 Directory::Create(nsISupports* aParent, nsIFile* aFile,
                   DirectoryType aType, FileSystemBase* aFileSystem)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(aFile);
 
 #ifdef DEBUG
   bool isDir;
   nsresult rv = aFile->IsDirectory(&isDir);
   MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
 
@@ -174,16 +164,17 @@ Directory::Create(nsISupports* aParent, 
 Directory::Directory(nsISupports* aParent,
                      nsIFile* aFile,
                      DirectoryType aType,
                      FileSystemBase* aFileSystem)
   : mParent(aParent)
   , mFile(aFile)
   , mType(aType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aFile);
 
   // aFileSystem can be null. In this case we create a OSFileSystem when needed.
   if (aFileSystem) {
     // More likely, this is a OSFileSystem. This object keeps a reference of
     // mParent but it's not cycle collectable and to avoid manual
     // addref/release, it's better to have 1 object per directory. For this
     // reason we clone it here.
@@ -225,19 +216,16 @@ Directory::GetName(nsAString& aRetval, E
   aRv = mFile->GetLeafName(aRetval);
   NS_WARN_IF(aRv.Failed());
 }
 
 already_AddRefed<Promise>
 Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
                       ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
-
   RefPtr<Blob> blobData;
   InfallibleTArray<uint8_t> arrayData;
   bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
 
   // Get the file content.
   if (aOptions.mData.WasPassed()) {
     auto& data = aOptions.mData.Value();
     if (data.IsString()) {
@@ -275,19 +263,16 @@ Directory::CreateFile(const nsAString& a
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 already_AddRefed<Promise>
 Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
-
   nsCOMPtr<nsIFile> realPath;
   nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
 
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
@@ -300,19 +285,16 @@ Directory::CreateDirectory(const nsAStri
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 already_AddRefed<Promise>
 Directory::Get(const nsAString& aPath, ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
-
   nsCOMPtr<nsIFile> realPath;
   nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
 
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
@@ -326,36 +308,29 @@ Directory::Get(const nsAString& aPath, E
   task->SetError(error);
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 already_AddRefed<Promise>
 Directory::Remove(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
   return RemoveInternal(aPath, false, aRv);
 }
 
 already_AddRefed<Promise>
 Directory::RemoveDeep(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
   return RemoveInternal(aPath, true, aRv);
 }
 
 already_AddRefed<Promise>
 Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                           ErrorResult& aRv)
 {
-  // Only exposed for DeviceStorage.
-  MOZ_ASSERT(NS_IsMainThread());
-
   nsresult error = NS_OK;
   nsCOMPtr<nsIFile> realPath;
 
   // Check and get the target path.
 
   RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -502,22 +477,10 @@ Directory::DOMPathToRealPath(const nsASt
       return rv;
     }
   }
 
   file.forget(aFile);
   return NS_OK;
 }
 
-bool
-Directory::ClonableToDifferentThreadOrProcess() const
-{
-  // If we don't have a fileSystem we are going to create a OSFileSystem that is
-  // clonable everywhere.
-  if (!mFileSystem) {
-    return true;
-  }
-
-  return mFileSystem->ClonableToDifferentThreadOrProcess();
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -48,19 +48,16 @@ public:
       eFilePath,
       eDirectoryPath
     } mType;
   };
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
 
-  static bool
-  DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
-
   static already_AddRefed<Promise>
   GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
 
   enum DirectoryType {
     // When a directory is selected using a HTMLInputElement, that will be the
     // DOM root directory and its name will be '/'. All the sub directory will
     // be called with they real name. We use this enum to mark what we must
     // consider the '/' of this DOM filesystem.
@@ -142,19 +139,16 @@ public:
   FileSystemBase*
   GetFileSystem(ErrorResult& aRv);
 
   DirectoryType Type() const
   {
     return mType;
   }
 
-  bool
-  ClonableToDifferentThreadOrProcess() const;
-
 private:
   Directory(nsISupports* aParent,
             nsIFile* aFile, DirectoryType aType,
             FileSystemBase* aFileSystem = nullptr);
   ~Directory();
 
   /*
    * Convert relative DOM path to the absolute real path.
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -122,19 +122,16 @@ public:
   // See how these 2 methods are used in FileSystemTaskChildBase.
 
   virtual bool
   NeedToGoToMainThread() const { return false; }
 
   virtual nsresult
   MainThreadWork() { return NS_ERROR_FAILURE; }
 
-  virtual bool
-  ClonableToDifferentThreadOrProcess() const { return false; }
-
   // CC methods
   virtual void Unlink() {}
   virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {}
 
   void
   AssertIsOnOwningThread() const;
 
 protected:
--- a/dom/filesystem/FileSystemPermissionRequest.cpp
+++ b/dom/filesystem/FileSystemPermissionRequest.cpp
@@ -6,127 +6,30 @@
 #include "FileSystemPermissionRequest.h"
 
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "nsIDocument.h"
-#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsPIDOMWindow.h"
 #include "nsContentPermissionHelper.h"
 
 namespace mozilla {
 namespace dom {
 
-namespace {
-
-// This class takes care of the PBackground initialization and, once this step
-// is completed, it starts the task.
-class PBackgroundInitializer final : public nsIIPCBackgroundChildCreateCallback
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
-
-  static void
-  ScheduleTask(FileSystemTaskChildBase* aTask)
-  {
-    MOZ_ASSERT(aTask);
-    RefPtr<PBackgroundInitializer> pb = new PBackgroundInitializer(aTask);
-  }
-
-private:
-  explicit PBackgroundInitializer(FileSystemTaskChildBase* aTask)
-    : mTask(aTask)
-  {
-    MOZ_ASSERT(aTask);
-
-    PBackgroundChild* actor =
-      mozilla::ipc::BackgroundChild::GetForCurrentThread();
-    if (actor) {
-      ActorCreated(actor);
-    } else {
-      if (NS_WARN_IF(
-          !mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) {
-        MOZ_CRASH();
-      }
-    }
-  }
-
-  ~PBackgroundInitializer()
-  {}
-
-  RefPtr<FileSystemTaskChildBase> mTask;
-};
-
-NS_IMPL_ISUPPORTS(PBackgroundInitializer,
+NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
+                  nsIContentPermissionRequest,
                   nsIIPCBackgroundChildCreateCallback)
 
-void
-PBackgroundInitializer::ActorFailed()
-{
-  MOZ_CRASH("Failed to create a PBackgroundChild actor!");
-}
-
-void
-PBackgroundInitializer::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
-{
-  mTask->Start();
-}
-
-// This must be a CancelableRunnable because it can be dispatched to a worker
-// thread. But we don't care about the Cancel() because in that case, Run() is
-// not called and the task is deleted by the DTOR.
-class AsyncStartRunnable final : public nsCancelableRunnable
-{
-public:
-  explicit AsyncStartRunnable(FileSystemTaskChildBase* aTask)
-    : mTask(aTask)
-  {
-    MOZ_ASSERT(aTask);
-  }
-
-  NS_IMETHOD
-  Run() override
-  {
-    PBackgroundInitializer::ScheduleTask(mTask);
-    return NS_OK;
-  }
-
-private:
-  RefPtr<FileSystemTaskChildBase> mTask;
-};
-
-} // anonymous namespace
-
-NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
-                  nsIContentPermissionRequest)
-
 /* static */ void
 FileSystemPermissionRequest::RequestForTask(FileSystemTaskChildBase* aTask)
 {
-  MOZ_ASSERT(aTask);
-
-  RefPtr<FileSystemBase> filesystem = aTask->GetFileSystem();
-  if (!filesystem) {
-    return;
-  }
-
-  if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckNotRequired) {
-    // Let's make the scheduling of this task asynchronous.
-    RefPtr<AsyncStartRunnable> runnable = new AsyncStartRunnable(aTask);
-    NS_DispatchToCurrentThread(runnable);
-    return;
-  }
-
-  // We don't need any permission check for the FileSystem API. If we are here
-  // it's because we are dealing with a DeviceStorage API that is main-thread
-  // only.
+  MOZ_ASSERT(aTask, "aTask should not be null!");
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<FileSystemPermissionRequest> request =
     new FileSystemPermissionRequest(aTask);
   NS_DispatchToCurrentThread(request);
 }
 
 FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskChildBase* aTask)
@@ -248,15 +151,36 @@ FileSystemPermissionRequest::GetRequeste
   NS_ENSURE_ARG_POINTER(aRequester);
 
   nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
   requester.forget(aRequester);
   return NS_OK;
 }
 
 void
+FileSystemPermissionRequest::ActorFailed()
+{
+  MOZ_CRASH("Failed to create a PBackgroundChild actor!");
+}
+
+void
+FileSystemPermissionRequest::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
+{
+  mTask->Start();
+}
+
+void
 FileSystemPermissionRequest::ScheduleTask()
 {
-  PBackgroundInitializer::ScheduleTask(mTask);
+  PBackgroundChild* actor =
+    mozilla::ipc::BackgroundChild::GetForCurrentThread();
+  if (actor) {
+    ActorCreated(actor);
+  } else {
+    if (NS_WARN_IF(
+        !mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) {
+      MOZ_CRASH();
+    }
+  }
 }
 
 } /* namespace dom */
 } /* namespace mozilla */
--- a/dom/filesystem/FileSystemPermissionRequest.h
+++ b/dom/filesystem/FileSystemPermissionRequest.h
@@ -5,47 +5,49 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FileSystemPermissionRequest_h
 #define mozilla_dom_FileSystemPermissionRequest_h
 
 #include "nsAutoPtr.h"
 #include "nsIRunnable.h"
 #include "nsIContentPermissionPrompt.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "nsString.h"
 
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class FileSystemTaskChildBase;
 
 class FileSystemPermissionRequest final
   : public nsIContentPermissionRequest
   , public nsIRunnable
+  , public nsIIPCBackgroundChildCreateCallback
 {
 public:
   // Request permission for the given task.
   static void
   RequestForTask(FileSystemTaskChildBase* aTask);
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSIRUNNABLE
+  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
 
 private:
   explicit FileSystemPermissionRequest(FileSystemTaskChildBase* aTask);
 
   ~FileSystemPermissionRequest();
 
   // Once the permission check has been done, we must run the task using IPC and
   // PBackground. This method checks if the PBackground thread is ready to
-  // receive the task and in case waits for ActorCreated() to be called using
-  // the PBackgroundInitializer class (see FileSystemPermissionRequest.cpp).
+  // receive the task and in case waits for ActorCreated() to be called.
   void
   ScheduleTask();
 
   nsCString mPermissionType;
   nsCString mPermissionAccess;
   RefPtr<FileSystemTaskChildBase> mTask;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIPrincipal> mPrincipal;
--- a/dom/filesystem/FileSystemTaskBase.cpp
+++ b/dom/filesystem/FileSystemTaskBase.cpp
@@ -70,54 +70,28 @@ DispatchToIOThread(nsIRunnable* aRunnabl
 
   nsCOMPtr<nsIEventTarget> target
     = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   MOZ_ASSERT(target);
 
   return target->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
 }
 
-// This runnable is used when an error value is set before doing any real
-// operation on the I/O thread. In this case we skip all and we directly
-// communicate the error.
-class ErrorRunnable final : public nsCancelableRunnable
-{
-public:
-  explicit ErrorRunnable(FileSystemTaskChildBase* aTask)
-    : mTask(aTask)
-  {
-    MOZ_ASSERT(aTask);
-  }
-
-  NS_IMETHOD
-  Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mTask->HasError());
-
-    mTask->HandlerCallback();
-    return NS_OK;
-  }
-
-private:
-  RefPtr<FileSystemTaskChildBase> mTask;
-};
-
 } // anonymous namespace
 
 /**
  * FileSystemTaskBase class
  */
 
 FileSystemTaskChildBase::FileSystemTaskChildBase(FileSystemBase* aFileSystem)
   : mErrorValue(NS_OK)
   , mFileSystem(aFileSystem)
 {
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
-  aFileSystem->AssertIsOnOwningThread();
 }
 
 FileSystemTaskChildBase::~FileSystemTaskChildBase()
 {
   mFileSystem->AssertIsOnOwningThread();
 }
 
 FileSystemBase*
@@ -128,20 +102,19 @@ FileSystemTaskChildBase::GetFileSystem()
 }
 
 void
 FileSystemTaskChildBase::Start()
 {
   mFileSystem->AssertIsOnOwningThread();
 
   if (HasError()) {
-    // In this case we don't want to use IPC at all.
-    RefPtr<ErrorRunnable> runnable = new ErrorRunnable(this);
-    nsresult rv = NS_DispatchToCurrentThread(runnable);
-    NS_WARN_IF(NS_FAILED(rv));
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethod(this, &FileSystemTaskChildBase::HandlerCallback);
+    NS_DispatchToMainThread(runnable);
     return;
   }
 
   if (mFileSystem->IsShutdown()) {
     return;
   }
 
   nsAutoString serialization;
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -29,18 +29,18 @@ namespace dom {
 
 /* static */ already_AddRefed<GetDirectoryListingTaskChild>
 GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
                                      nsIFile* aTargetPath,
                                      Directory::DirectoryType aType,
                                      const nsAString& aFilters,
                                      ErrorResult& aRv)
 {
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
-  aFileSystem->AssertIsOnOwningThread();
 
   RefPtr<GetDirectoryListingTaskChild> task =
     new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aType, aFilters);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetParentObject());
@@ -61,55 +61,54 @@ GetDirectoryListingTaskChild::GetDirecto
                                                            nsIFile* aTargetPath,
                                                            Directory::DirectoryType aType,
                                                            const nsAString& aFilters)
   : FileSystemTaskChildBase(aFileSystem)
   , mTargetPath(aTargetPath)
   , mFilters(aFilters)
   , mType(aType)
 {
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
-  aFileSystem->AssertIsOnOwningThread();
 }
 
 GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  mFileSystem->AssertIsOnOwningThread();
 }
 
 already_AddRefed<Promise>
 GetDirectoryListingTaskChild::GetPromise()
 {
-  mFileSystem->AssertIsOnOwningThread();
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   return RefPtr<Promise>(mPromise).forget();
 }
 
 FileSystemParams
 GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
                                                ErrorResult& aRv) const
 {
-  mFileSystem->AssertIsOnOwningThread();
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
 
   nsAutoString path;
   aRv = mTargetPath->GetPath(path);
   if (NS_WARN_IF(aRv.Failed())) {
     return FileSystemGetDirectoryListingParams();
   }
 
   return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
                                              mType == Directory::eDOMRootDirectory,
                                              mFilters);
 }
 
 void
 GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
                                                       ErrorResult& aRv)
 {
-  mFileSystem->AssertIsOnOwningThread();
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aValue.type() ==
                FileSystemResponseValue::TFileSystemDirectoryListingResponse);
 
   FileSystemDirectoryListingResponse r = aValue;
   for (uint32_t i = 0; i < r.data().Length(); ++i) {
     const FileSystemDirectoryListingResponseData& data = r.data()[i];
 
     Directory::FileOrDirectoryPath element;
@@ -129,18 +128,17 @@ GetDirectoryListingTaskChild::SetSuccess
       return;
     }
   }
 }
 
 void
 GetDirectoryListingTaskChild::HandlerCallback()
 {
-  mFileSystem->AssertIsOnOwningThread();
-
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
     return;
   }
 
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
--- a/dom/filesystem/OSFileSystem.cpp
+++ b/dom/filesystem/OSFileSystem.cpp
@@ -39,16 +39,17 @@ OSFileSystem::Clone()
 
   return fs.forget();
 }
 
 void
 OSFileSystem::Init(nsISupports* aParent)
 {
   AssertIsOnOwningThread();
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(!mParent, "No duple Init() calls");
   MOZ_ASSERT(aParent);
 
   mParent = aParent;
 
 #ifdef DEBUG
   nsCOMPtr<nsIGlobalObject> obj = do_QueryInterface(aParent);
   MOZ_ASSERT(obj);
--- a/dom/filesystem/OSFileSystem.h
+++ b/dom/filesystem/OSFileSystem.h
@@ -35,19 +35,16 @@ public:
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
   IsSafeDirectory(Directory* aDir) const override;
 
   virtual void
   SerializeDOMPath(nsAString& aOutput) const override;
 
-  virtual bool
-  ClonableToDifferentThreadOrProcess() const override { return true; }
-
   // CC methods
   virtual void Unlink() override;
   virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
 
 private:
   virtual ~OSFileSystem() {}
 
   nsCOMPtr<nsISupports> mParent;
--- a/dom/filesystem/tests/mochitest.ini
+++ b/dom/filesystem/tests/mochitest.ini
@@ -1,7 +1,5 @@
 [DEFAULT]
 support-files =
   script_fileList.js
-  worker_basic.js
 
 [test_basic.html]
-[test_worker_basic.html]
deleted file mode 100644
--- a/dom/filesystem/tests/test_worker_basic.html
+++ /dev/null
@@ -1,70 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for Directory API in workers</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-
-<body>
-<input id="fileList" type="file"></input>
-<script type="application/javascript;version=1.7">
-
-function create_fileList() {
-  var url = SimpleTest.getTestFileURL("script_fileList.js");
-  var script = SpecialPowers.loadChromeScript(url);
-
-  function onOpened(message) {
-    var fileList = document.getElementById('fileList');
-    SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
-
-    // Just a simple test
-    is(fileList.files.length, 1, "Filelist has 1 element");
-    ok(fileList.files[0] instanceof Directory, "We have a directory.");
-
-    script.destroy();
-    next();
-  }
-
-  script.addMessageListener("dir.opened", onOpened);
-  script.sendAsyncMessage("dir.open", { path: 'ProfD' });
-}
-
-function test_worker() {
-  var fileList = document.getElementById('fileList');
-
-  var worker = new Worker('worker_basic.js');
-  worker.onmessage = function(e) {
-    if (e.data.type == 'finish') {
-      next();
-      return;
-    }
-
-    if (e.data.type == 'test') {
-      ok(e.data.test, e.data.message);
-    }
-  }
-
-  worker.postMessage(fileList.files);
-}
-
-var tests = [
-  create_fileList,
-  test_worker,
-];
-
-function next() {
-  if (!tests.length) {
-    SimpleTest.finish();
-    return;
-  }
-
-  var test = tests.shift();
-  test();
-}
-
-SimpleTest.waitForExplicitFinish();
-next();
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/filesystem/tests/worker_basic.js
+++ /dev/null
@@ -1,58 +0,0 @@
-function finish() {
-  postMessage({ type: 'finish' });
-}
-
-function ok(a, msg) {
-  postMessage({ type: 'test', test: !!a, message: msg });
-}
-
-function is(a, b, msg) {
-  ok(a === b, msg);
-}
-
-function isnot(a, b, msg) {
-  ok(a != b, msg);
-}
-
-function checkSubDir(dir) {
-  return dir.getFilesAndDirectories().then(
-    function(data) {
-      for (var i = 0; i < data.length; ++i) {
-        ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
-        if (data[i] instanceof Directory) {
-          isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
-          isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
-          isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
-          is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
-        }
-      }
-    }
-  );
-}
-
-onmessage = function(e) {
-  var fileList = e.data;
-  ok(fileList instanceof FileList, "This is a fileList.");
-  is(fileList.length, 1, "We want just 1 element.");
-  ok(fileList[0] instanceof Directory, "This is a directory.");
-
-  fileList[0].getFilesAndDirectories().then(
-    function(data) {
-      ok(data.length, "We should have some data.");
-      var promises = [];
-      for (var i = 0; i < data.length; ++i) {
-        ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
-        if (data[i] instanceof Directory) {
-          isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
-          is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
-          promises.push(checkSubDir(data[i]));
-        }
-      }
-
-      return Promise.all(promises);
-    },
-    function() {
-      ok(false, "Something when wrong");
-    }
-  ).then(finish);
-}
--- a/dom/webidl/Directory.webidl
+++ b/dom/webidl/Directory.webidl
@@ -10,17 +10,17 @@
  * path should be a descendent path like "path/to/file.txt" and not contain a
  * segment of ".." or ".". So the paths aren't allowed to walk up the directory
  * tree. For example, paths like "../foo", "..", "/foo/bar" or "foo/../bar" are
  * not allowed.
  *
  * http://w3c.github.io/filesystem-api/#idl-def-Directory
  * https://microsoftedge.github.io/directory-upload/proposal.html#directory-interface
  */
-[Exposed=(Window,Worker)]
+[Exposed=Window]
 interface Directory {
   /*
    * The leaf name of the directory.
    */
   [Throws]
   readonly attribute DOMString name;
 
   /*
@@ -34,72 +34,72 @@ interface Directory {
    * a new file to replace the existing one;
    * If 'ifExists' is 'replace', the path already exists, but is a directory,
    * createFile must fail.
    * Otherwise, if no other error occurs, createFile will create a new file.
    * The 'data' property contains the new file's content.
    * @return If succeeds, the promise is resolved with the new created
    * File object. Otherwise, rejected with a DOM error.
    */
-  [Func="mozilla::dom::Directory::DeviceStorageEnabled", NewObject]
+  [Pref="device.storage.enabled", NewObject]
   Promise<File> createFile(DOMString path, optional CreateFileOptions options);
 
   /*
    * Creates a descendent directory. This method will create any intermediate
    * directories specified by the path segments.
    *
    * @param path The relative path of the new directory to current directory.
    * If path exists, createDirectory must fail.
    * @return If succeeds, the promise is resolved with the new created
    * Directory object. Otherwise, rejected with a DOM error.
    */
-  [Func="mozilla::dom::Directory::DeviceStorageEnabled", NewObject]
+  [Pref="device.storage.enabled", NewObject]
   Promise<Directory> createDirectory(DOMString path);
 
   /*
    * Gets a descendent file or directory with the given path.
    *
    * @param path The descendent entry's relative path to current directory.
    * @return If the path exists and no error occurs, the promise is resolved
    * with a File or Directory object, depending on the entry's type. Otherwise,
    * rejected with a DOM error.
    */
-  [Func="mozilla::dom::Directory::DeviceStorageEnabled", NewObject]
+  [Pref="device.storage.enabled", NewObject]
   Promise<(File or Directory)> get(DOMString path);
 
   /*
    * Deletes a file or an empty directory. The target must be a descendent of
    * current directory.
    * @param path If a DOM string is passed, it is the relative path of the
    * target. Otherwise, the File or Directory object of the target should be
    * passed.
    * @return If the target is a non-empty directory, or if deleting the target
    * fails, the promise is rejected with a DOM error. If the target did not
    * exist, the promise is resolved with boolean false. If the target did exist
    * and was successfully deleted, the promise is resolved with boolean true.
    */
-  [Func="mozilla::dom::Directory::DeviceStorageEnabled", NewObject]
+  [Pref="device.storage.enabled", NewObject]
   Promise<boolean> remove((DOMString or File or Directory) path);
 
   /*
    * Deletes a file or a directory recursively. The target should be a
    * descendent of current directory.
    * @param path If a DOM string is passed, it is the relative path of the
    * target. Otherwise, the File or Directory object of the target should be
    * passed.
    * @return If the target exists, but deleting the target fails, the promise is
    * rejected with a DOM error. If the target did not exist, the promise is
    * resolved with boolean false. If the target did exist and was successfully
    * deleted, the promise is resolved with boolean true.
    */
-  [Func="mozilla::dom::Directory::DeviceStorageEnabled", NewObject]
+  [Pref="device.storage.enabled", NewObject]
   Promise<boolean> removeDeep((DOMString or File or Directory) path);
 };
 
-[Exposed=(Window,Worker)]
+[Exposed=Window]
 partial interface Directory {
   // Already defined in the main interface declaration:
   //readonly attribute DOMString name;
 
   /*
    * The path of the Directory (includes both its basename and leafname).
    * The path begins with the name of the ancestor Directory that was
    * originally exposed to content (say via a directory picker) and traversed
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -92,18 +92,16 @@ var interfaceNamesInGlobalScope =
     "Crypto",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CustomEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DataStore", b2g: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DataStoreCursor", b2g: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "Directory",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMCursor",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMError",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMException",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMRequest",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -90,18 +90,16 @@ var interfaceNamesInGlobalScope =
     "CustomEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DedicatedWorkerGlobalScope",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DataStore", b2g: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DataStoreCursor", b2g: true },
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "Directory",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMCursor",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMError",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMException",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DOMRequest",
 // IMPORTANT: Do not change this list without review from a DOM peer!