Backout 9d9d8bf66243 (bug 785662) for mochitest-other leaks on Windows
authorEd Morley <emorley@mozilla.com>
Tue, 25 Sep 2012 13:46:25 +0100
changeset 108000 3ee0ff72fdf3e433db2c5670234803b60ff18ec7
parent 107999 eae123c9c88434a7987082ce155d25dcd7cdad76
child 108001 3218db438fdfeb51fb025b31bbfe9114fc682452
push id15321
push useremorley@mozilla.com
push dateTue, 25 Sep 2012 12:46:40 +0000
treeherdermozilla-inbound@3ee0ff72fdf3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs785662
milestone18.0a1
backs out9d9d8bf662436bd9e2ec0b96f0de95922d077456
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
Backout 9d9d8bf66243 (bug 785662) for mochitest-other leaks on Windows
content/media/nsMediaCache.cpp
xpcom/build/nsXPComInit.cpp
xpcom/io/Makefile.in
xpcom/io/nsAnonymousTemporaryFile.cpp
xpcom/io/nsAnonymousTemporaryFile.h
xpcom/io/nsIFile.idl
xpcom/io/nsMediaCacheRemover.cpp
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -3,27 +3,29 @@
 /* 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/ReentrantMonitor.h"
 #include "mozilla/XPCOM.h"
 
 #include "nsMediaCache.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsXULAppAPI.h"
 #include "nsNetUtil.h"
 #include "prio.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "MediaResource.h"
 #include "nsMathUtils.h"
 #include "prlog.h"
 #include "mozilla/Preferences.h"
 #include "FileBlockCache.h"
 #include "mozilla/Attributes.h"
-#include "nsAnonymousTemporaryFile.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gMediaCacheLog;
 #define LOG(type, msg) PR_LOG(gMediaCacheLog, type, msg)
 #else
 #define LOG(type, msg)
@@ -512,18 +514,57 @@ nsMediaCacheStream::BlockList::NotifyBlo
 }
 
 nsresult
 nsMediaCache::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   NS_ASSERTION(!mFileCache, "Cache file already open?");
 
+  // In single process Gecko, store the media cache in the profile directory
+  // so that multiple users can use separate media caches concurrently.
+  // In multi-process Gecko, there is no profile dir, so just store it in the
+  // system temp directory instead.
+  nsresult rv;
+  nsCOMPtr<nsIFile> tmpFile;
+  const char* dir = (XRE_GetProcessType() == GeckoProcessType_Content) ?
+    NS_OS_TEMP_DIR : NS_APP_USER_PROFILE_LOCAL_50_DIR;
+  rv = NS_GetSpecialDirectory(dir, getter_AddRefs(tmpFile));
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  // We put the media cache file in
+  // ${TempDir}/mozilla-media-cache/media_cache
+  rv = tmpFile->AppendNative(nsDependentCString("mozilla-media-cache"));
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
+    // Ensure the permissions are 0700. If not, we won't be able to create,
+    // read to and write from the media cache file in its subdirectory on
+    // non-Windows platforms.
+    uint32_t perms;
+    rv = tmpFile->GetPermissions(&perms);
+    NS_ENSURE_SUCCESS(rv,rv);
+    if (perms != 0700) {
+      rv = tmpFile->SetPermissions(0700);
+      NS_ENSURE_SUCCESS(rv,rv);
+    }
+  } else {
+    NS_ENSURE_SUCCESS(rv,rv);
+  }
+
+  rv = tmpFile->AppendNative(nsDependentCString("media_cache"));
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700);
+  NS_ENSURE_SUCCESS(rv,rv);
+
   PRFileDesc* fileDesc = nullptr;
-  nsresult rv = NS_OpenAnonymousTemporaryFile(&fileDesc);
+  rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsIFile::DELETE_ON_CLOSE,
+                                 PR_IRWXU, &fileDesc);
   NS_ENSURE_SUCCESS(rv,rv);
 
   mFileCache = new FileBlockCache();
   rv = mFileCache->Open(fileDesc);
   NS_ENSURE_SUCCESS(rv,rv);
 
 #ifdef PR_LOGGING
   if (!gMediaCacheLog) {
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -136,17 +136,17 @@ static BrowserProcessSubThread* sIOThrea
 // We hook into this function locally to create and register the registry
 // Since noone outside xpcom needs to know about this and nsRegistry.cpp
 // does not have a local include file, we are putting this definition
 // here rather than in nsIRegistry.h
 extern nsresult NS_RegistryGetFactory(nsIFactory** aFactory);
 extern nsresult NS_CategoryManagerGetFactory( nsIFactory** );
 
 #ifdef XP_WIN
-extern nsresult ScheduleAnonTempFileRemover();
+extern nsresult ScheduleMediaCacheRemover();
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsIDImpl)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsStringImpl)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCStringImpl)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRBoolImpl)
@@ -459,17 +459,17 @@ NS_InitXPCOM2(nsIServiceManager* *result
     mozilla::scache::StartupCache::GetSingleton();
     mozilla::AvailableMemoryTracker::Activate();
 
     // Notify observers of xpcom autoregistration start
     NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, 
                                   nullptr,
                                   NS_XPCOM_STARTUP_OBSERVER_ID);
 #ifdef XP_WIN
-    ScheduleAnonTempFileRemover();
+    ScheduleMediaCacheRemover();
 #endif
 
     mozilla::MapsMemoryReporter::Init();
 
     mozilla::Telemetry::Init();
 
     mozilla::HangMonitor::Startup();
 
--- a/xpcom/io/Makefile.in
+++ b/xpcom/io/Makefile.in
@@ -21,17 +21,16 @@ LIBXUL_LIBRARY  = 1
 ifdef GNU_CC 
 ifneq ($(OS_ARCH), Darwin)
 MODULE_OPTIMIZE_FLAGS = $(MOZ_OPTIMIZE_FLAGS) -fno-strict-aliasing
 endif
 endif
 
 CPPSRCS		= \
 		Base64.cpp \
-		nsAnonymousTemporaryFile.cpp \
 		nsAppFileLocationProvider.cpp \
 		nsBinaryStream.cpp \
 		nsDirectoryService.cpp \
 		nsEscape.cpp \
 		nsInputStreamTee.cpp \
 		nsLinebreakConverter.cpp \
 		nsLocalFileCommon.cpp \
 		nsMultiplexInputStream.cpp \
@@ -54,24 +53,23 @@ CMMSRCS		+= \
 		CocoaFileUtils.mm \
 		$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 CPPSRCS		+= nsLocalFileOS2.cpp
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-CPPSRCS		+= nsLocalFileWin.cpp
+CPPSRCS		+= nsLocalFileWin.cpp nsMediaCacheRemover.cpp
 else
 CPPSRCS		+= nsLocalFileUnix.cpp
 endif # windows
 endif # OS2
 
 EXPORTS		= \
-		nsAnonymousTemporaryFile.h \
 		nsAppDirectoryServiceDefs.h \
 		nsDirectoryService.h \
 		nsDirectoryServiceAtomList.h \
 		nsEscape.h \
 		nsLinebreakConverter.h \
 		nsLocalFile.h \
 		nsMultiplexInputStream.h \
 		nsNativeCharsetUtils.h \
deleted file mode 100644
--- a/xpcom/io/nsAnonymousTemporaryFile.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; 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 "nsAnonymousTemporaryFile.h"
-#include "nsDirectoryServiceUtils.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsXULAppAPI.h"
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsAppDirectoryServiceDefs.h"
-
-#ifdef XP_WIN
-#include "nsIObserver.h"
-#include "nsIIdleService.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIFile.h"
-#include "nsAutoPtr.h"
-#include "nsITimer.h"
-#endif
-
-
-// We store the temp files in the system temp dir on non-Windows systems.
-// On Windows systems we use a subdirectory of the profile dir, because:
-//   1. DELETE_ON_CLOSE is unreliable on Windows, in particular if we power
-//      cycle (and perhaps if we crash) the files are not deleted. We store
-//      the temporary files in a known subdir so that we can find and delete
-//      them easily and quickly.
-//   2. We can be sure the user always has write privileges to their own
-//      profile directory; if the subdir was in the system temp directory and
-//      was created by a privileged user it's possible that other users
-//      wouldn't have write access to this folder.
-#ifdef XP_WIN
-#define ANON_TEMP_DIR NS_APP_USER_PROFILE_LOCAL_50_DIR
-#else
-#define ANON_TEMP_DIR NS_OS_TEMP_DIR
-#endif
-
-nsresult
-NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc)
-{
-  NS_ENSURE_ARG(aOutFileDesc);
-  nsresult rv;
-
-  nsCOMPtr<nsIFile> tmpFile;
-  rv = NS_GetSpecialDirectory(ANON_TEMP_DIR, getter_AddRefs(tmpFile));
-  NS_ENSURE_SUCCESS(rv,rv);
-
-#ifdef XP_WIN
-  // On windows DELETE_ON_CLOSE is unreliable, so we store temporary files
-  // in a subdir of the temp dir and delete that in an idle service observer
-  // to ensure it's been cleared.
-  rv = tmpFile->AppendNative(nsDependentCString("mozilla-temp-files"));
-  NS_ENSURE_SUCCESS(rv,rv);    
-  rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
-  NS_ENSURE_TRUE(rv == NS_ERROR_FILE_ALREADY_EXISTS || NS_SUCCEEDED(rv), rv);
-#endif
-
-  // Give the temp file a name with a random element. CreateUnique will also
-  // append a counter to the name if it encounters a name collision. Adding
-  // a random element to the name reduces the likelihood of a name collision,
-  // so that CreateUnique() doesn't end up trying a lot of name variants in
-  // its "try appending an incrementing counter" loop, as file IO can be
-  // expensive on some mobile flash drives.
-  nsAutoString name(NS_LITERAL_STRING("mozilla-temp-"));
-  name.AppendInt(rand());
-
-  rv = tmpFile->Append(name);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsIFile::DELETE_ON_CLOSE,
-                                 PR_IRWXU, aOutFileDesc);
-
-  return rv;    
-}
-
-#ifdef XP_WIN
-
-// On Windows we have an idle service observer that runs some time after
-// startup and deletes any stray anonymous temporary files...
-
-// Duration of idle time before we'll get a callback whereupon we attempt to
-// remove any stray and unused anonymous temp files.
-#define TEMP_FILE_IDLE_TIME 30
-
-// The nsAnonTempFileRemover is created in a timer, which sets an idle observer.
-// This is expiration time (in ms) which initial timer is set for (3 minutes).
-#define SCHEDULE_TIMEOUT 3 * 60 * 1000
-
-// This class adds itself as an idle observer. When the application has
-// been idle for about 30 seconds we'll get a notification, whereupon we'll
-// attempt to delete ${TempDir}/mozilla-temp-files/. This is to ensure all
-// temp files that were supposed to be deleted on application exit were actually
-// deleted as they may not be if we previously crashed. See bugs 572579 and
-// 785662. This is only needed on some versions of Windows,
-// nsIFile::DELETE_ON_CLOSE works on other platforms.
-class nsAnonTempFileRemover : public nsIObserver {
-public:
-  NS_DECL_ISUPPORTS
-
-  nsAnonTempFileRemover() {
-    MOZ_COUNT_CTOR(nsAnonTempFileRemover);
-  }
-
-  ~nsAnonTempFileRemover() {
-    MOZ_COUNT_DTOR(nsAnonTempFileRemover);
-  }
-
-  NS_IMETHODIMP Observe(nsISupports *subject,
-                        const char *topic,
-                        const PRUnichar *data)
-  {
-    if (strcmp(topic, "idle") == 0) {
-      // The user has been idle for a while, clean up the temp files.
-      // The idle service will drop its reference to this object after
-      // we exit, destroying this object.
-      RemoveAnonTempFileFiles();
-    }
-    return NS_OK;
-  }
-
-  nsresult RegisterIdleObserver() {
-    // Add this as an idle observer. When we've been idle for 
-    // TEMP_FILE_IDLE_TIME seconds, we'll get a notification, and we'll then
-    // try to delete any stray temp files.
-    nsCOMPtr<nsIIdleService> idleSvc =
-      do_GetService("@mozilla.org/widget/idleservice;1");
-    if (!idleSvc)
-      return NS_ERROR_FAILURE;
-    return idleSvc->AddIdleObserver(this, TEMP_FILE_IDLE_TIME);
-  }
-
-  void RemoveAnonTempFileFiles() {
-    nsCOMPtr<nsIIdleService> idleSvc =
-      do_GetService("@mozilla.org/widget/idleservice;1");
-    if (idleSvc)
-      idleSvc->RemoveIdleObserver(this, TEMP_FILE_IDLE_TIME);
-
-    nsCOMPtr<nsIFile> tmpDir;
-    nsresult rv = NS_GetSpecialDirectory(ANON_TEMP_DIR,
-                                         getter_AddRefs(tmpDir));
-    if (NS_FAILED(rv))
-      return;
-
-    rv = tmpDir->AppendNative(nsDependentCString("mozilla-temp-files"));
-    if (NS_FAILED(rv))
-      return;
-
-    // Remove the directory recursively.  
-    tmpDir->Remove(true);
-  }
-};
-
-NS_IMPL_ISUPPORTS1(nsAnonTempFileRemover, nsIObserver)
-
-// Stores a reference to the timer we use to trigger CreateAnonTempFileRemover.
-// We need to keep a reference to it to stop the timer being released before
-// it fires.
-static nsITimer* sAnonTempFileTimer = nullptr;
-
-void CreateAnonTempFileRemover(nsITimer* aTimer, void* aClosure) {
-  // Create a new nsAnonTempFileRemover, and register it as an idle observer.
-  // If it is successfully registered as an idle observer, its owning reference
-  // will be held by the idle service, otherwise it will be destroyed by the
-  // refptr here when it goes out of scope.
-  nsRefPtr<nsAnonTempFileRemover> t = new nsAnonTempFileRemover();
-  t->RegisterIdleObserver();
-  NS_IF_RELEASE(sAnonTempFileTimer);
-  sAnonTempFileTimer = nullptr;
-}
-
-nsresult ScheduleAnonTempFileRemover() {
-  NS_ASSERTION(sAnonTempFileTimer == nullptr, "Don't init timer twice!");
-  // We create the nsAnonTempFileRemover in a timer, so that the app has enough
-  // time to start up before we add the idle observer. If we register the
-  // idle observer too early, it will be registered before the fake idle
-  // service is installed when running in xpcshell, and this interferes with
-  // the fake idle service, causing xpcshell-test failures.
-  nsCOMPtr<nsITimer> t = do_CreateInstance(NS_TIMER_CONTRACTID);
-  if (NS_SUCCEEDED(t->InitWithFuncCallback(CreateAnonTempFileRemover,
-                                           nullptr,
-                                           SCHEDULE_TIMEOUT,
-                                           nsITimer::TYPE_ONE_SHOT))) {
-    t.forget(&sAnonTempFileTimer);
-  }
-  return NS_OK;
-}
-
-#endif
-
deleted file mode 100644
--- a/xpcom/io/nsAnonymousTemporaryFile.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-#pragma once
-
-#include "prio.h"
-#include "nscore.h"
-
-/**
- * OpenAnonymousTemporaryFile
- *
- * Creates and opens a temporary file which has a random name. Callers have no
- * control over the file name, and the file is opened in a temporary location
- * which is appropriate for the platform.
- *
- * Upon success, aOutFileDesc contains an opened handle to the temporary file.
- * The caller is responsible for closing the file when they're finished with it.
- *
- * The file will be deleted when the file handle is closed. On non-Windows
- * platforms the file will be unlinked before this function returns. On Windows
- * the OS supplied delete-on-close mechanism is unreliable if the application
- * crashes or the computer power cycles unexpectedly, so unopened temporary
- * files are purged at some time after application startup.
- *
- */ 
-nsresult
-NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc);
-
--- a/xpcom/io/nsIFile.idl
+++ b/xpcom/io/nsIFile.idl
@@ -339,39 +339,30 @@ interface nsIFile : nsISupports
      *
      *  This attribute will determine if the nsLocalFile will auto
      *  resolve symbolic links.  By default, this value will be false
      *  on all non unix systems.  On unix, this attribute is effectively
      *  a noop.  
      */
     attribute boolean followLinks;  
 
-    /**
-     * Flag for openNSPRFileDesc(), to hint to the OS that the file will be
-     * read sequentially with agressive readahead.
-     */
     const unsigned long OS_READAHEAD = 0x40000000;
-    
-    /**
-     * Flag for openNSPRFileDesc(). Deprecated and unreliable!
-     * Instead use NS_OpenAnonymousTemporaryFile() to create a temporary
-     * file which will be deleted upon close!
-     */
     const unsigned long DELETE_ON_CLOSE = 0x80000000;
 
     /**
      * Return the result of PR_Open on the file.  The caller is
      * responsible for calling PR_Close on the result.
      *
      * @param flags the PR_Open flags from prio.h, plus optionally
      * OS_READAHEAD or DELETE_ON_CLOSE. OS_READAHEAD is a hint to the
      * OS that the file will be read sequentially with agressive
-     * readahead. DELETE_ON_CLOSE is unreliable on Windows and is deprecated.
-     * Instead use NS_OpenAnonymousTemporaryFile() to create a temporary
-     * file which will be deleted upon close.
+     * readahead. DELETE_ON_CLOSE may be implemented by removing the
+     * file (by path name) immediately after opening it, so beware of
+     * possible races; the file should be exclusively owned by this
+     * process.
      */
     [noscript] PRFileDescStar openNSPRFileDesc(in long flags, in long mode);
 
     /**
      * Return the result of fopen on the file.  The caller is
      * responsible for calling fclose on the result.
      */
     [noscript] FILE           openANSIFileDesc(in string mode);
new file mode 100644
--- /dev/null
+++ b/xpcom/io/nsMediaCacheRemover.cpp
@@ -0,0 +1,118 @@
+/* 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/. */
+
+#ifndef XP_WIN
+#error nsMediaCacheRemover only needed on Windows.
+#endif
+
+#include "nsIObserver.h"
+#include "nsIIdleService.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIFile.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsXULAppAPI.h"
+#include "nsString.h"
+#include "nsAutoPtr.h"
+#include "nsITimer.h"
+
+// Duration of idle time before we'll get a callback whereupon we attempt to
+// remove any stray and unused media cache temp files.
+#define TEMP_FILE_IDLE_TIME 30
+
+// The nsMediaCacheRemover is created in a timer, which sets an idle observer.
+// This is expiration time (in ms) which initial timer is set for (3 minutes).
+#define SCHEDULE_TIMEOUT 3 * 60 * 1000
+
+// This class adds itself as an idle observer. When the application has
+// been idle for about 30 seconds we'll get a notification, whereupon we'll
+// attempt to delete ${TempDir}/mozilla-media-cache/. This is to ensure all
+// media cache temp files which were supposed to be deleted on application
+// exit were actually deleted as they may not be if we previously crashed.
+// See bug 572579. This is only needed on some versions of Windows,
+// nsIFile::DELETE_ON_CLOSE works on other platforms.
+class nsMediaCacheRemover : public nsIObserver {
+public:
+  NS_DECL_ISUPPORTS
+
+  nsMediaCacheRemover() {
+    MOZ_COUNT_CTOR(nsMediaCacheRemover);
+  }
+
+  ~nsMediaCacheRemover() {
+    MOZ_COUNT_DTOR(nsMediaCacheRemover);
+  }
+
+  NS_IMETHODIMP Observe(nsISupports *subject,
+                        const char *topic,
+                        const PRUnichar *data)
+  {
+    if (strcmp(topic, "idle") == 0) {
+      // The user has been idle for a while, clean up the temp files.
+      // The idle service will drop its reference to this object after
+      // we exit, destroying this object.
+      RemoveMediaCacheFiles();
+    }
+    return NS_OK;
+  }
+
+  nsresult RegisterIdleObserver() {
+    // Add this as an idle observer. When we've been idle for 
+    // TEMP_FILE_IDLE_TIME seconds, we'll get a notification, and we'll then
+    // try to delete any stray media cache temp files.
+    nsCOMPtr<nsIIdleService> idleSvc =
+      do_GetService("@mozilla.org/widget/idleservice;1");
+    if (!idleSvc)
+      return NS_ERROR_FAILURE;
+    return idleSvc->AddIdleObserver(this, TEMP_FILE_IDLE_TIME);
+  }
+
+  void RemoveMediaCacheFiles() {
+    nsCOMPtr<nsIIdleService> idleSvc =
+      do_GetService("@mozilla.org/widget/idleservice;1");
+    if (idleSvc)
+      idleSvc->RemoveIdleObserver(this, TEMP_FILE_IDLE_TIME);
+
+    nsCOMPtr<nsIFile> tmpDir;
+    nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
+                                         getter_AddRefs(tmpDir));
+    if (NS_FAILED(rv))
+      return;
+
+    NS_ABORT_IF_FALSE(XRE_GetProcessType() == GeckoProcessType_Default,
+                      "Need to update media cache file location");
+
+    rv = tmpDir->AppendNative(nsDependentCString("mozilla-media-cache"));
+    if (NS_FAILED(rv))
+      return;
+
+    // Remove the directory recursively.  
+    tmpDir->Remove(true);
+  }
+};
+
+NS_IMPL_ISUPPORTS1(nsMediaCacheRemover, nsIObserver)
+
+void CreateMediaCacheRemover(nsITimer* aTimer, void* aClosure) {
+  // Create a new nsMediaCacheRemover, and register it as an idle observer.
+  // If it is successfully registered as an idle observer, its owning reference
+  // will be held by the idle service, otherwise it will be destroyed by the
+  // refptr here when it goes out of scope.
+  nsRefPtr<nsMediaCacheRemover> t = new nsMediaCacheRemover();
+  t->RegisterIdleObserver();
+}
+
+nsresult ScheduleMediaCacheRemover() {
+  // We create the nsMediaCacheRemover in a timer, so that the app has enough
+  // time to start up before we add the idle observer. If we register the
+  // idle observer too early, it will be registered before the fake idle
+  // service is installed when running in xpcshell, and this interferes with
+  // the fake idle service, causing xpcshell-test failures.
+  nsCOMPtr<nsITimer> t = do_CreateInstance(NS_TIMER_CONTRACTID);
+  nsresult res = t->InitWithFuncCallback(CreateMediaCacheRemover,
+                                         0,
+                                         SCHEDULE_TIMEOUT,
+                                         nsITimer::TYPE_ONE_SHOT);
+  return res;
+}