diff --git a/dom/filesystem/FileSystemTaskBase.cpp b/dom/filesystem/FileSystemTaskBase.cpp index 34cfd8f01826..ac62e71a80ce 100644 --- a/dom/filesystem/FileSystemTaskBase.cpp +++ b/dom/filesystem/FileSystemTaskBase.cpp @@ -218,7 +218,28 @@ NS_IMETHODIMP FileSystemTaskParentBase::Run() { // This method can run in 2 different threads. Here why: // 1. We are are on the I/O thread and we call IOWork(). - // 2. After step 1, it returns back to the PBackground thread. + // 2. After step 1, if we need to run some code in the main-thread, we + // dispatch a runnable to this thread. + // 3. The final step happens in the PBackground thread. + + // If we are here, it's because the I/O work has been done, but we have + // something to do on the main-thread. + if (NS_IsMainThread()) { + MOZ_ASSERT(MainThreadNeeded()); + + nsresult rv = MainThreadWork(); + if (NS_WARN_IF(NS_FAILED(rv))) { + SetError(rv); + } + + // Let's go back to PBackground thread to finish the work. + rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; + } // Run I/O thread tasks if (!mozilla::ipc::IsOnBackgroundThread()) { @@ -227,6 +248,14 @@ FileSystemTaskParentBase::Run() { SetError(rv); } + if (MainThreadNeeded()) { + rv = GetMainThreadSerialEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; + } + // Let's go back to PBackground thread to finish the work. rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { diff --git a/dom/filesystem/FileSystemTaskBase.h b/dom/filesystem/FileSystemTaskBase.h index 3d440403cc49..56cabdd4e7ec 100644 --- a/dom/filesystem/FileSystemTaskBase.h +++ b/dom/filesystem/FileSystemTaskBase.h @@ -53,9 +53,18 @@ class FileSystemParams; * | | | | ---------> [IOWork] | | * | | IPC | | | | | * | | | | | | (5) | | - * | | | | -------------- | | - * | | | | | |_____________| | - * | | | | | | + * | | | | -------------* | | + * | | | | | |_____|_______| | + * | | | | | __________|_______ | + * | | | | | | | | | + * | | | | | | Main | | | + * | | | | | | Thread | | | + * | | | | | | V | | + * | | | | | | [MainThreadWork] | | + * | | IPC | | | (5.1) | | | + * | | | | | | | | | + * | | | | |<------------ | | + * | | | | | |__________________| | * | | | | V | * | | | | [HandleResult] | * | | | | | | @@ -87,6 +96,7 @@ class FileSystemParams; * during the operation, call [SetError] to record the error and then abort. * (5) After finishing the task operation, call [HandleResult] to send the * result back to the child process though the IPC. + * (5.1) Optional, we need to run some code in the main-thread. * (6) Call [GetRequestResult] request result to prepare the parameters of the * IPC. Because the formats of the error result for different task are the * same, FileSystemTaskChildBase can handle the error message without @@ -199,6 +209,16 @@ class FileSystemTaskParentBase : public Runnable { */ virtual nsresult IOWork() = 0; + // In case `MainThreadNeeded()` returns true, the following method is called. + virtual nsresult MainThreadWork() { + MOZ_CRASH("This method should be implemented"); + return NS_OK; + } + + // If this returns true, after I/O work, we schedule a runnable to the + // main-thread before resolving the task on the PBackground one. + virtual bool MainThreadNeeded() const { return false; }; + /* * Wrap the task success result to FileSystemResponseValue for sending it * through IPC. This method runs in the PBackground thread. diff --git a/dom/filesystem/GetDirectoryListingTask.cpp b/dom/filesystem/GetDirectoryListingTask.cpp index f78a04a9d0be..9ac3dc9bbf2b 100644 --- a/dom/filesystem/GetDirectoryListingTask.cpp +++ b/dom/filesystem/GetDirectoryListingTask.cpp @@ -16,7 +16,9 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/ipc/BackgroundParent.h" +#include "nsCExternalHandlerService.h" #include "nsIFile.h" +#include "nsIMIMEService.h" #include "nsString.h" namespace mozilla::dom { @@ -218,8 +220,18 @@ FileSystemResponseValue GetDirectoryListingTaskParent::GetSuccessRequestResult( continue; } + nsAutoString fileName; + path->GetLeafName(fileName); + + int64_t fileSize = 0; + rv = path->GetFileSize(&fileSize); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + FileSystemDirectoryListingResponseFile fileData; - RefPtr blobImpl = new FileBlobImpl(path); + RefPtr blobImpl = new FileBlobImpl( + fileName, mTargetData[i].mContentType, fileSize, path); nsAutoString filePath; filePath.Assign(mDOMPath); @@ -364,6 +376,55 @@ nsresult GetDirectoryListingTaskParent::IOWork() { return NS_OK; } +nsresult GetDirectoryListingTaskParent::MainThreadWork() { + MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); + MOZ_ASSERT(NS_IsMainThread(), "Only call on main-thread!"); + + nsresult rv; + nsCOMPtr mimeService = + do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + for (unsigned i = 0; i < mTargetData.Length(); i++) { + if (mTargetData[i].mType != FileOrDirectoryPath::eFilePath) { + continue; + } + + nsCOMPtr file; + nsresult rv = + NS_NewLocalFile(mTargetData[i].mPath, true, getter_AddRefs(file)); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + nsAutoCString mimeType; + rv = mimeService->GetTypeFromFile(file, mimeType); + if (NS_FAILED(rv)) { + mimeType.Truncate(); + } + + AppendUTF8toUTF16(mimeType, mTargetData[i].mContentType); + } + + return NS_OK; +} + +bool GetDirectoryListingTaskParent::MainThreadNeeded() const { + MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); + + // We need to go to the main-thread only if we have files in the list of + // target. + for (const FileOrDirectoryPath& data : mTargetData) { + if (data.mType == FileOrDirectoryPath::eFilePath) { + return true; + } + } + + return false; +} + nsresult GetDirectoryListingTaskParent::GetTargetPath(nsAString& aPath) const { return mTargetPath->GetPath(aPath); } diff --git a/dom/filesystem/GetDirectoryListingTask.h b/dom/filesystem/GetDirectoryListingTask.h index afb5296ac54e..e54ca10323ed 100644 --- a/dom/filesystem/GetDirectoryListingTask.h +++ b/dom/filesystem/GetDirectoryListingTask.h @@ -72,6 +72,10 @@ class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase { virtual nsresult IOWork() override; + virtual nsresult MainThreadWork() override; + + virtual bool MainThreadNeeded() const override; + nsCOMPtr mTargetPath; nsString mDOMPath; nsString mFilters; @@ -79,6 +83,9 @@ class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase { struct FileOrDirectoryPath { nsString mPath; + // Set on the main-thread + nsString mContentType; + enum { eFilePath, eDirectoryPath } mType; };