Bug 1355346 - Call nsCocoaFileUtils::AddOriginMetadataToFile off of the main-thread when completing downloads. r=mstange
authorMike Conley <mconley@mozilla.com>
Fri, 17 Aug 2018 19:07:51 -0400
changeset 487731 566a5b21073a2899b9ee539236ac057d3b81b382
parent 487730 dade0d8f79ea0db4e7a6741fd3931a5a5362cb0a
child 487732 acfaacaca4cbe91eb413abb206d2187f304fad0d
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1355346
milestone63.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 1355346 - Call nsCocoaFileUtils::AddOriginMetadataToFile off of the main-thread when completing downloads. r=mstange Tags: #secure-revision Bug #: 1355346 Differential Revision: https://phabricator.services.mozilla.com/D3674
toolkit/components/downloads/DownloadPlatform.cpp
toolkit/components/downloads/DownloadPlatform.h
xpcom/io/CocoaFileUtils.h
xpcom/io/CocoaFileUtils.mm
--- a/toolkit/components/downloads/DownloadPlatform.cpp
+++ b/toolkit/components/downloads/DownloadPlatform.cpp
@@ -8,22 +8,27 @@
 #include "nsString.h"
 #include "nsINestedURI.h"
 #include "nsIProtocolHandler.h"
 #include "nsIURI.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsDirectoryServiceDefs.h"
+#include "nsThreadUtils.h"
 
+#include "mozilla/LazyIdleThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 
 #define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs"
 
+// The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
+#define DEFAULT_THREAD_TIMEOUT_MS 10000
+
 #ifdef XP_WIN
 #include <shlobj.h>
 #include <urlmon.h>
 #include "nsILocalFileWin.h"
 #endif
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
@@ -93,16 +98,22 @@ CFURLRef CreateCFURLFromNSIURI(nsIURI *a
                                          NULL);
 
   ::CFRelease(urlStr);
 
   return url;
 }
 #endif
 
+DownloadPlatform::DownloadPlatform()
+{
+  mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
+                                 NS_LITERAL_CSTRING("DownloadPlatform"));
+}
+
 nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIFile* aTarget,
                                         const nsACString& aContentType, bool aIsPrivate)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) \
  || defined(MOZ_WIDGET_GTK)
 
   nsAutoString path;
   if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) {
@@ -164,35 +175,43 @@ nsresult DownloadPlatform::DownloadDone(
     CFStringRef pathCFStr = NULL;
     if (!path.IsEmpty()) {
       pathCFStr = ::CFStringCreateWithCharacters(kCFAllocatorDefault,
                                                  (const UniChar*)path.get(),
                                                  path.Length());
     }
     if (pathCFStr && !aIsPrivate) {
       bool isFromWeb = IsURLPossiblyFromWeb(aSource);
-
-      CFURLRef sourceCFURL = CreateCFURLFromNSIURI(aSource);
-      CFURLRef referrerCFURL = CreateCFURLFromNSIURI(aReferrer);
+      nsCOMPtr<nsIURI> source(aSource);
+      nsCOMPtr<nsIURI> referrer(aReferrer);
 
-      CocoaFileUtils::AddOriginMetadataToFile(pathCFStr,
-                                              sourceCFURL,
-                                              referrerCFURL);
-      CocoaFileUtils::AddQuarantineMetadataToFile(pathCFStr,
+      nsresult rv = mIOThread->Dispatch(NS_NewRunnableFunction(
+        "DownloadPlatform::DownloadDone",
+        [pathCFStr, isFromWeb, source, referrer] {
+          CFURLRef sourceCFURL = CreateCFURLFromNSIURI(source);
+          CFURLRef referrerCFURL = CreateCFURLFromNSIURI(referrer);
+
+          CocoaFileUtils::AddOriginMetadataToFile(pathCFStr,
                                                   sourceCFURL,
-                                                  referrerCFURL,
-                                                  isFromWeb);
+                                                  referrerCFURL);
+          CocoaFileUtils::AddQuarantineMetadataToFile(pathCFStr,
+                                                      sourceCFURL,
+                                                      referrerCFURL,
+                                                      isFromWeb);
+          ::CFRelease(pathCFStr);
+          if (sourceCFURL) {
+            ::CFRelease(sourceCFURL);
+          }
+          if (referrerCFURL) {
+            ::CFRelease(referrerCFURL);
+          }
+        }
+      ));
 
-      ::CFRelease(pathCFStr);
-      if (sourceCFURL) {
-        ::CFRelease(sourceCFURL);
-      }
-      if (referrerCFURL) {
-        ::CFRelease(referrerCFURL);
-      }
+      return rv;
     }
 #endif
   }
 
 #endif
 
   return NS_OK;
 }
--- a/toolkit/components/downloads/DownloadPlatform.h
+++ b/toolkit/components/downloads/DownloadPlatform.h
@@ -3,32 +3,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __DownloadPlatform_h__
 #define __DownloadPlatform_h__
 
 #include "mozIDownloadPlatform.h"
 
 #include "nsCOMPtr.h"
+#include "nsIThread.h"
+
 class nsIURI;
 
 class DownloadPlatform : public mozIDownloadPlatform
 {
 protected:
 
   virtual ~DownloadPlatform() { }
 
 public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_MOZIDOWNLOADPLATFORM
 
-  DownloadPlatform() { }
+  DownloadPlatform();
 
   static DownloadPlatform *gDownloadPlatformService;
 
   static DownloadPlatform* GetDownloadPlatform();
 
 private:
+  nsCOMPtr<nsIThread> mIOThread;
   static bool IsURLPossiblyFromWeb(nsIURI* aURI);
 };
 
 #endif
--- a/xpcom/io/CocoaFileUtils.h
+++ b/xpcom/io/CocoaFileUtils.h
@@ -17,23 +17,28 @@
 namespace CocoaFileUtils {
 
 nsresult RevealFileInFinder(CFURLRef aUrl);
 nsresult OpenURL(CFURLRef aUrl);
 nsresult GetFileCreatorCode(CFURLRef aUrl, OSType* aCreatorCode);
 nsresult SetFileCreatorCode(CFURLRef aUrl, OSType aCreatorCode);
 nsresult GetFileTypeCode(CFURLRef aUrl, OSType* aTypeCode);
 nsresult SetFileTypeCode(CFURLRef aUrl, OSType aTypeCode);
+
+// Can be called off of the main thread.
 void     AddOriginMetadataToFile(const CFStringRef filePath,
                                  const CFURLRef sourceURL,
                                  const CFURLRef referrerURL);
+// Can be called off of the main thread.
 void     AddQuarantineMetadataToFile(const CFStringRef filePath,
                                      const CFURLRef sourceURL,
                                      const CFURLRef referrerURL,
                                      const bool isFromWeb,
                                      const bool createProps=false);
+// Can be called off of the main thread.
 void CopyQuarantineReferrerUrl(const CFStringRef aFilePath,
                                nsAString& aReferrer);
+
 CFURLRef GetTemporaryFolderCFURLRef();
 
 } // namespace CocoaFileUtils
 
 #endif
--- a/xpcom/io/CocoaFileUtils.mm
+++ b/xpcom/io/CocoaFileUtils.mm
@@ -139,16 +139,17 @@ nsresult SetFileTypeCode(CFURLRef url, O
   NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode] forKey:NSFileHFSTypeCode];
   BOOL success = [[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:[(NSURL*)url path] error:nil];
   [ap release];
   return (success ? NS_OK : NS_ERROR_FAILURE);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
+// Can be called off of the main thread.
 void AddOriginMetadataToFile(const CFStringRef filePath,
                              const CFURLRef sourceURL,
                              const CFURLRef referrerURL) {
   typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef, CFTypeRef);
   static MDItemSetAttribute_type mdItemSetAttributeFunc = NULL;
 
   static bool did_symbol_lookup = false;
   if (!did_symbol_lookup) {
@@ -188,23 +189,25 @@ void AddOriginMetadataToFile(const CFStr
   }
 
   mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
 
   ::CFRelease(list);
   ::CFRelease(mdItem);
 }
 
+// Can be called off of the main thread.
 CFStringRef GetQuarantinePropKey() {
   if (nsCocoaFeatures::OnYosemiteOrLater()) {
     return kCFURLQuarantinePropertiesKey;
   }
   return kLSItemQuarantineProperties;
 }
 
+// Can be called off of the main thread.
 CFMutableDictionaryRef CreateQuarantineDictionary(const CFURLRef aFileURL,
                                                   const bool aCreateProps) {
   // The properties key changed in 10.10:
   CFDictionaryRef quarantineProps = NULL;
   if (aCreateProps) {
     quarantineProps = ::CFDictionaryCreate(NULL, NULL, NULL, 0,
                                            &kCFTypeDictionaryKeyCallBacks,
                                            &kCFTypeDictionaryValueCallBacks);
@@ -230,16 +233,17 @@ CFMutableDictionaryRef CreateQuarantineD
   CFMutableDictionaryRef mutQuarantineProps =
     ::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0,
                                     (CFDictionaryRef)quarantineProps);
   ::CFRelease(quarantineProps);
 
   return mutQuarantineProps;
 }
 
+// Can be called off of the main thread.
 void AddQuarantineMetadataToFile(const CFStringRef filePath,
                                  const CFURLRef sourceURL,
                                  const CFURLRef referrerURL,
                                  const bool isFromWeb,
                                  const bool createProps /* = false */) {
   CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                                      filePath,
                                                      kCFURLPOSIXPathStyle,
@@ -279,16 +283,17 @@ void AddQuarantineMetadataToFile(const C
                                    GetQuarantinePropKey(),
                                    mutQuarantineProps,
                                    NULL);
 
   ::CFRelease(fileURL);
   ::CFRelease(mutQuarantineProps);
 }
 
+// Can be called off of the main thread.
 void CopyQuarantineReferrerUrl(const CFStringRef aFilePath,
                                nsAString& aReferrer)
 {
   CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                                      aFilePath,
                                                      kCFURLPOSIXPathStyle,
                                                      false);