Backout 4ebd50016f35 & 9033700cc24f (bug 807757) for failing to build on a CLOSED TREE
authorEd Morley <emorley@mozilla.com>
Thu, 13 Dec 2012 18:46:38 +0000
changeset 115957 85d46df9a1257db4a846273a5280c087d938705e
parent 115956 4b218334f0e3939aabf0cff5a143638e2455bef3
child 115958 bcc487178c04933d7fe528303c3179863655f637
push id24034
push useremorley@mozilla.com
push dateFri, 14 Dec 2012 15:28:57 +0000
treeherdermozilla-central@50d8f411d305 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs807757
milestone20.0a1
backs out4ebd50016f357f481078944aa69e3e5925bb2c02
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 4ebd50016f35 & 9033700cc24f (bug 807757) for failing to build on a CLOSED TREE
embedding/tests/winEmbed/WebBrowserChrome.cpp
extensions/pref/autoconfig/src/nsAutoConfig.cpp
extensions/pref/autoconfig/src/nsAutoConfig.h
profile/dirserviceprovider/public/nsProfileDirServiceProvider.h
profile/public/Makefile.in
profile/public/notifications.txt
profile/public/nsIProfile.idl
profile/public/nsIProfileChangeStatus.idl
security/manager/locales/en-US/chrome/pipnss/pipnss.properties
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
toolkit/components/startup/nsAppStartup.cpp
toolkit/xre/nsXREDirProvider.cpp
--- a/embedding/tests/winEmbed/WebBrowserChrome.cpp
+++ b/embedding/tests/winEmbed/WebBrowserChrome.cpp
@@ -40,16 +40,17 @@
 #include "nsStringAPI.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIRequest.h"
 #include "nsIURI.h"
 #include "nsIWebProgress.h"
 #include "nsCWebBrowser.h"
+#include "nsIProfileChangeStatus.h"
 
 // Glue APIs (not frozen, but safe to use because they are statically linked)
 #include "nsComponentManagerUtils.h"
 
 // NON-FROZEN APIS!
 #include "nsIWebNavigation.h"
 
 WebBrowserChrome::WebBrowserChrome()
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -9,16 +9,17 @@
 #endif
 #include "nsAutoConfig.h"
 #include "nsIURI.h"
 #include "nsIHttpChannel.h"
 #include "nsIFileStreams.h"
 #include "nsThreadUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "prmem.h"
+#include "nsIProfile.h"
 #include "nsIObserverService.h"
 #include "nsLiteralString.h"
 #include "nsIPromptService.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsCRT.h"
 #include "nspr.h"
 
@@ -174,16 +175,31 @@ NS_IMETHODIMP nsAutoConfig::Notify(nsITi
 
 NS_IMETHODIMP nsAutoConfig::Observe(nsISupports *aSubject, 
                                     const char *aTopic, 
                                     const PRUnichar *someData)
 {
     nsresult rv = NS_OK;
     if (!nsCRT::strcmp(aTopic, "profile-after-change")) {
 
+        // Getting the current profile name since we already have the 
+        // pointer to the object.
+        nsCOMPtr<nsIProfile> profile = do_QueryInterface(aSubject);
+        if (profile) {
+            nsXPIDLString profileName;
+            rv = profile->GetCurrentProfile(getter_Copies(profileName));
+            if (NS_SUCCEEDED(rv)) {
+                // setting the member variable to the current profile name
+                CopyUTF16toUTF8(profileName, mCurrProfile);
+            }
+            else {
+                NS_WARNING("nsAutoConfig::GetCurrentProfile() failed");
+            }
+        } 
+
         // We will be calling downloadAutoConfig even if there is no profile 
         // name. Nothing will be passed as a parameter to the URL and the
         // default case will be picked up by the script.
         
         rv = downloadAutoConfig();
 
     }  
    
@@ -475,18 +491,18 @@ nsresult nsAutoConfig::getEmailAddr(nsAC
         emailAddr = prefValue;
     }
     else {
         // look for 4.x pref in case we just migrated.
         rv = mPrefBranch->GetCharPref("mail.identity.useremail", 
                                   getter_Copies(prefValue));
         if (NS_SUCCEEDED(rv) && !prefValue.IsEmpty())
             emailAddr = prefValue;
-        else
-            PromptForEMailAddress(emailAddr);
+        else if (NS_FAILED(PromptForEMailAddress(emailAddr))  && (!mCurrProfile.IsEmpty()))
+            emailAddr = mCurrProfile;
     }
     
     return NS_OK;
 }
         
 nsresult nsAutoConfig::PromptForEMailAddress(nsACString &emailAddress)
 {
     nsresult rv;
--- a/extensions/pref/autoconfig/src/nsAutoConfig.h
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.h
@@ -35,14 +35,14 @@ class nsAutoConfig : public nsIAutoConfi
     protected:
   
         nsresult downloadAutoConfig();
         nsresult readOfflineFile();
         nsresult evaluateLocalFile(nsIFile *file);
         nsresult writeFailoverFile();
         nsresult getEmailAddr(nsACString & emailAddr);
         nsresult PromptForEMailAddress(nsACString &emailAddress);
-        nsCString mBuf;
+        nsCString mBuf, mCurrProfile;
         nsCOMPtr<nsIPrefBranch> mPrefBranch;
         bool mLoaded;
         nsCOMPtr<nsITimer> mTimer;
         nsCString mConfigURL;
 };
--- a/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h
+++ b/profile/dirserviceprovider/public/nsProfileDirServiceProvider.h
@@ -99,14 +99,14 @@ protected:
 
 // --------------------------------------------------------------------------------------
 
 /**
  * Global method to create an instance of nsProfileDirServiceProvider
  *
  * @param aNotifyObservers    If true, will send out profile startup
  *                            notifications when the profile directory is set.
- *                            See notifications.txt
+ *                            See nsIProfileChangeStatus.
  */
  
 nsresult NS_NewProfileDirServiceProvider(bool aNotifyObservers,
                                          nsProfileDirServiceProvider** aProvider);
 
--- a/profile/public/Makefile.in
+++ b/profile/public/Makefile.in
@@ -7,14 +7,19 @@ DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= profile
 
+SDK_XPIDLSRCS	= \
+		nsIProfile.idl \
+		nsIProfileChangeStatus.idl \
+		$(NULL)
+
 XPIDLSRCS	= \
 	        nsIProfileUnlocker.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/profile/public/notifications.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-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/.
-
-nsIObserver topics for profile changing. Profile changing happens in phases
-in the order given below. An observer may register separately for each phase
-of the process depending on its needs.
-
-"profile-change-teardown"
-  All async activity must be stopped in this phase. Typically,
-  the application level observer will close all open windows.
-  This is the last phase in which the subject's vetoChange()
-  method may still be called.
-  The next notification will be either
-  profile-change-teardown-veto or profile-before-change.
-
-"profile-before-change"
-  Called before the profile has changed. Use this notification
-  to prepare for the profile going away. If a component is
-  holding any state which needs to be flushed to a profile-relative
-  location, it should be done here.
-
-"profile-do-change"
-  Called after the profile has changed. Do the work to
-  respond to having a new profile. Any change which
-  affects others must be done in this phase.
-
-"profile-after-change"
-  Called after the profile has changed. Use this notification
-  to make changes that are dependent on what some other listener
-  did during its profile-do-change. For example, to respond to
-  new preferences.
-
-"profile-initial-state"
-  Called after all phases of a change have completed. Typically
-  in this phase, an application level observer will open a new window.
-
-Contexts for profile changes. These are passed as the someData param to the
-observer's Observe() method.
-
-"startup"
-  Going from no profile to a profile.
-  The following topics happen in this context:
-      profile-do-change
-      profile-after-change
-
-"shutdown-persist"
-  The user is logging out and whatever data the observer stores
-  for the current profile should be released from memory and
-  saved to disk.
-  The following topics happen in this context:
-      profile-change-net-teardown
-      profile-change-teardown
-      profile-before-change
-
-See https://wiki.mozilla.org/XPCOM_Shutdown for more details about the shutdown
-process.
-
-NOTE: Long ago there was be a "shutdown-cleanse" version of shutdown which was
-intended to clear profile data. This is no longer sent and observer code should
-remove support for it.
new file mode 100644
--- /dev/null
+++ b/profile/public/nsIProfile.idl
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsISupports.idl"
+#include "nsIFile.idl"
+
+%{C++
+      
+#define NS_PROFILE_CID                                 \
+  { /* {02b0625b-e7f3-11d2-9f5a-006008a6efe9} */       \
+    0x02b0625b,                                        \
+    0xe7f3,                                            \
+    0x11d2,                                            \
+    { 0x9f, 0x5a, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9 } \
+  }
+
+#define NS_PROFILE_CONTRACTID	\
+	"@mozilla.org/profile/manager;1"
+
+#define NS_PROFILE_STARTUP_CATEGORY \
+        "profile-startup-category"
+%}
+
+/**
+ * nsIProfile
+ * 
+ * @version 1.0
+ */
+
+[scriptable, uuid(02b0625a-e7f3-11d2-9f5a-006008a6efe9)]
+interface nsIProfile : nsISupports {
+    
+    readonly attribute long profileCount;
+    void getProfileList(out unsigned long length, [retval, array, size_is(length)] out wstring profileNames); 
+    boolean profileExists(in wstring profileName);
+
+    attribute wstring currentProfile;
+
+    const unsigned long SHUTDOWN_PERSIST      = 0x00000001;
+    const unsigned long SHUTDOWN_CLEANSE      = 0x00000002;
+    
+    void shutDownCurrentProfile(in unsigned long shutDownType);
+
+    void createNewProfile(in wstring profileName, 
+                          in wstring nativeProfileDir, 
+                          in wstring langcode,
+                          in boolean useExistingDir);    
+
+    void renameProfile(in wstring oldName, in wstring newName);
+    void deleteProfile(in wstring name, in boolean canDeleteFiles);
+    void cloneProfile(in wstring profileName);
+};
new file mode 100644
--- /dev/null
+++ b/profile/public/nsIProfileChangeStatus.idl
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsISupports.idl"
+
+%{C++
+
+   /**
+    * nsIObserver topics for profile changing. Profile changing happens in phases
+    * in the order given below. An observer may register separately for each phase
+    * of the process depending on its needs. The subject passed to the observer's
+    * Observe() method can be QI'd to an nsIProfileChangeStatus.
+    *
+    * "profile-approve-change"
+    *   Called before a profile change is attempted. Typically,
+    *   the application level observer will ask the user if
+    *   he/she wants to stop all network activity, close all open
+    *   windows, etc. If the user says NO, the observer should
+    *   call the subject's vetoChange(). If any observer does
+    *   this, the profile will not be changed.
+    *
+    * "profile-change-teardown"
+    *   All async activity must be stopped in this phase. Typically,
+    *   the application level observer will close all open windows.
+    *   This is the last phase in which the subject's vetoChange()
+    *   method may still be called. 
+    *   The next notification will be either 
+    *   profile-change-teardown-veto or profile-before-change.
+    *
+    * "profile-change-teardown-veto"
+    *   This notification will only be sent, if the profile change 
+    *   was vetoed during the profile-change-teardown phase.
+    *   This allows components to bring back required resources,
+    *   that were tore down on profile-change-teardown.
+    *
+    * "profile-before-change"
+    *   Called before the profile has changed. Use this notification
+    *   to prepare for the profile going away. If a component is
+    *   holding any state which needs to be flushed to a profile-relative
+    *   location, it should be done here.
+    *
+    * "profile-do-change"
+    *   Called after the profile has changed. Do the work to
+    *   respond to having a new profile. Any change which
+    *   affects others must be done in this phase.
+    *
+    * "profile-after-change"
+    *   Called after the profile has changed. Use this notification
+    *   to make changes that are dependent on what some other listener
+    *   did during its profile-do-change. For example, to respond to
+    *   new preferences. 
+    *
+    * "profile-initial-state"
+    *   Called after all phases of a change have completed. Typically
+    *   in this phase, an application level observer will open a new window.
+    *
+    * Contexts for profile changes. These are passed as the someData param to the
+    * observer's Observe() method.
+    
+    * "startup"
+    *   Going from no profile to a profile.
+    *
+    *   The following topics happen in this context:
+    *       profile-do-change
+    *       profile-after-change
+    *
+    * "shutdown-persist"
+    *   The user is logging out and whatever data the observer stores
+    *   for the current profile should be released from memory and
+    *   saved to disk.
+    *
+    * "shutdown-cleanse"
+    *   The user is logging out and whatever data the observer stores
+    *   for the current profile should be released from memory and
+    *   deleted from disk.
+    *
+    *   The following topics happen in both shutdown contexts:
+    *       profile-approve-change
+    *       profile-change-teardown
+    *       profile-before-change
+    *
+    * "switch"
+    *   Going from one profile to another.
+    *
+    *   All of the above topics happen in a profile switch.
+    *
+    */  
+%}
+
+
+[scriptable, uuid(2f977d43-5485-11d4-87e2-0010a4e75ef2)]
+interface nsIProfileChangeStatus : nsISupports {
+        
+    void vetoChange();
+    
+   /**
+    * Called by a profile change observer when a fatal error
+    * occurred during the attempt to switch the profile.
+    *
+    * The profile should be considered in an unsafe condition,
+    * and the profile manager should inform the user and
+    * exit immediately.
+    *
+    */
+    void changeFailed();
+
+};
--- a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties
@@ -344,16 +344,18 @@ CrlImportFailureExpired=A more recent ve
 CrlImportFailureBadSignature=CRL has an invalid Signature.
 CrlImportFailureInvalid=New CRL has an invalid format.
 CrlImportFailureOld=New CRL is older than the current one.
 CrlImportFailureNotYetValid=The CRL is not yet valid. You might want to check your system clock.
 CrlImportFailureNetworkProblem=Download of the CRL failed due to Network problems.
 CrlImportFailureReasonUnknown=Error Importing CRL to local Database. Error Code: 
 CrlImportFailure2=Please ask your system administrator for assistance.
 NSSInitProblemX=Could not initialize the application's security component. The most likely cause is problems with files in your application's profile directory. Please check that this directory has no read/write restrictions and your hard disk is not full or close to full. It is recommended that you exit the application and fix the problem. If you continue to use this session, you might see incorrect application behaviour when accessing security features.
+ProfileSwitchSocketsStillActive=The operation cannot be completed because of an internal failure. A secure network communication has not been cleaned up correctly.
+ProfileSwitchCryptoUIActive=This operation is impossible at the current time. Please complete the operation that requests your attention in one of the other open windows.
 VerifyExpired=<Expired>
 VerifyRevoked=<Revoked>
 VerifyNotTrusted=<Not Trusted>
 VerifyIssuerNotTrusted=<Issuer Not Trusted>
 VerifyIssuerUnknown=<Issuer Unknown>
 VerifyInvalidCA=<Invalid CA>
 VerifyDisabledAlgorithm=<Signature Algorithm Not Secure>
 VerifyUnknown=<Unknown>
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -19,16 +19,17 @@
 #include "nsIStreamListener.h"
 #include "nsIStringBundle.h"
 #include "nsIDirectoryService.h"
 #include "nsIDOMNode.h"
 #include "nsCURILoader.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIX509Cert.h"
 #include "nsIX509CertDB.h"
+#include "nsIProfileChangeStatus.h"
 #include "nsNSSCertificate.h"
 #include "nsNSSHelper.h"
 #include "nsSmartCardMonitor.h"
 #include "prlog.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIDateTimeFormat.h"
 #include "nsDateTimeFormatCID.h"
@@ -1824,17 +1825,17 @@ nsNSSComponent::InitializeNSS(bool showW
     if (showWarningBox) {
       ShowAlertFromStringBundle("NSSInitProblemX");
     }
   }
 
   return NS_OK;
 }
 
-void
+nsresult
 nsNSSComponent::ShutdownNSS()
 {
   // Can be called both during init and profile change,
   // needs mutex protection.
   
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::ShutdownNSS\n"));
 
   MutexAutoLock lock(mutex);
@@ -2148,41 +2149,50 @@ nsNSSComponent::RandomUpdate(void *entro
       return NS_ERROR_NOT_INITIALIZED;
 
   PK11_RandomUpdate(entropy, bufLen);
   return NS_OK;
 }
 
 #define PROFILE_CHANGE_NET_TEARDOWN_TOPIC "profile-change-net-teardown"
 #define PROFILE_CHANGE_NET_RESTORE_TOPIC "profile-change-net-restore"
+#define PROFILE_APPROVE_CHANGE_TOPIC "profile-approve-change"
 #define PROFILE_CHANGE_TEARDOWN_TOPIC "profile-change-teardown"
+#define PROFILE_CHANGE_TEARDOWN_VETO_TOPIC "profile-change-teardown-veto"
 #define PROFILE_BEFORE_CHANGE_TOPIC "profile-before-change"
 #define PROFILE_DO_CHANGE_TOPIC "profile-do-change"
 
 NS_IMETHODIMP
 nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, 
                         const PRUnichar *someData)
 {
-  if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_TOPIC) == 0) {
+  if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) {
+    DoProfileApproveChange(aSubject);
+  }
+  else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_TOPIC) == 0) {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("in PSM code, receiving change-teardown\n"));
     DoProfileChangeTeardown(aSubject);
   }
+  else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC) == 0) {
+    mShutdownObjectList->allowUI();
+  }
   else if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n"));
     DoProfileBeforeChange(aSubject);
   }
   else if (nsCRT::strcmp(aTopic, PROFILE_DO_CHANGE_TOPIC) == 0) {
     if (someData && NS_LITERAL_STRING("startup").Equals(someData)) {
       // The application is initializing against a known profile directory for
       // the first time during process execution.
       // However, earlier code execution might have already triggered NSS init.
       // We must ensure that NSS gets shut down prior to any attempt to init
       // it again. We use the same cleanup functionality used when switching
       // profiles. The order of function calls must correspond to the order
       // of notifications sent by Profile Manager (nsProfile).
+      DoProfileApproveChange(aSubject);
       DoProfileChangeNetTeardown();
       DoProfileChangeTeardown(aSubject);
       DoProfileBeforeChange(aSubject);
       DoProfileChangeNetRestore();
     }
   
     bool needsInit = true;
 
@@ -2194,16 +2204,20 @@ nsNSSComponent::Observe(nsISupports *aSu
         // no need to do it again
         needsInit = false;
       }
     }
     
     if (needsInit) {
       if (NS_FAILED(InitializeNSS(false))) { // do not show a warning box on failure
         PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS after profile switch.\n"));
+        nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+        if (status) {
+          status->ChangeFailed();
+        }
       }
     }
 
     InitializeCRLUpdateTimer();
   }
   else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
 
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent: XPCom shutdown observed\n"));
@@ -2395,17 +2409,19 @@ nsNSSComponent::RegisterObservers()
     // Once we are loaded, don't allow being removed from memory.
     // This makes sense, as initializing NSS is expensive.
 
     // By using false for parameter ownsWeak in AddObserver,
     // we make sure that we won't get unloaded until the application shuts down.
 
     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
+    observerService->AddObserver(this, PROFILE_APPROVE_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC, false);
+    observerService->AddObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC, false);
     observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_DO_CHANGE_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC, false);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, false);
   }
   return NS_OK;
 }
 
@@ -2418,17 +2434,19 @@ nsNSSComponent::DeregisterObservers()
   nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
   NS_ASSERTION(observerService, "could not get observer service");
   if (observerService) {
     mObserversRegistered = false;
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent: removing observers\n"));
 
     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
 
+    observerService->RemoveObserver(this, PROFILE_APPROVE_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC);
+    observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC);
     observerService->RemoveObserver(this, PROFILE_BEFORE_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_DO_CHANGE_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC);
     observerService->RemoveObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC);
   }
   return NS_OK;
 }
 
@@ -2458,28 +2476,61 @@ nsNSSComponent::RememberCert(CERTCertifi
   
   if (!PL_HashTableAdd(hashTableCerts, (void*)&myDupCert->certKey, myDupCert)) {
     CERT_DestroyCertificate(myDupCert);
   }
   
   return NS_OK;
 }
 
+static const char PROFILE_SWITCH_CRYPTO_UI_ACTIVE[] =
+                        "ProfileSwitchCryptoUIActive";
+static const char PROFILE_SWITCH_SOCKETS_STILL_ACTIVE[] =
+                        "ProfileSwitchSocketsStillActive";
+
+void
+nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject)
+{
+  if (mShutdownObjectList->isUIActive()) {
+    ShowAlertFromStringBundle(PROFILE_SWITCH_CRYPTO_UI_ACTIVE);
+    nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+    if (status) {
+      status->VetoChange();
+    }
+  }
+}
+
 void
 nsNSSComponent::DoProfileChangeNetTeardown()
 {
   if (mCertVerificationThread)
     mCertVerificationThread->requestExit();
   mIsNetworkDown = true;
 }
 
 void
 nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject)
 {
-  mShutdownObjectList->ifPossibleDisallowUI();
+  bool callVeto = false;
+
+  if (!mShutdownObjectList->ifPossibleDisallowUI()) {
+    callVeto = true;
+    ShowAlertFromStringBundle(PROFILE_SWITCH_CRYPTO_UI_ACTIVE);
+  }
+  else if (mShutdownObjectList->areSSLSocketsActive()) {
+    callVeto = true;
+    ShowAlertFromStringBundle(PROFILE_SWITCH_SOCKETS_STILL_ACTIVE);
+  }
+
+  if (callVeto) {
+    nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+    if (status) {
+      status->VetoChange();
+    }
+  }
 }
 
 void
 nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject)
 {
   NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity");
 
   bool needsCleanup = true;
@@ -2493,17 +2544,22 @@ nsNSSComponent::DoProfileBeforeChange(ns
       // multiple times.
       needsCleanup = false;
     }
   }
     
   StopCRLUpdateTimer();
 
   if (needsCleanup) {
-    ShutdownNSS();
+    if (NS_FAILED(ShutdownNSS())) {
+      nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
+      if (status) {
+        status->ChangeFailed();
+      }
+    }
   }
   mShutdownObjectList->allowUI();
 }
 
 void
 nsNSSComponent::DoProfileChangeNetRestore()
 {
   /* XXX this doesn't work well, since nothing expects null pointers */
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -265,17 +265,17 @@ public:
 
   NS_IMETHOD GetDefaultCERTValInParam(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out);
   NS_IMETHOD GetDefaultCERTValInParamLocalOnly(
                   mozilla::RefPtr<nsCERTValInParamWrapper> &out);
 private:
 
   nsresult InitializeNSS(bool showWarningBox);
-  void ShutdownNSS();
+  nsresult ShutdownNSS();
 
 #ifdef XP_MACOSX
   void TryCFM2MachOMigration(nsIFile *cfmPath, nsIFile *machoPath);
 #endif
   
   void InstallLoadableRoots();
   void UnloadLoadableRoots();
   void LaunchSmartCardThreads();
@@ -289,16 +289,17 @@ private:
   nsresult DeregisterObservers();
   nsresult DownloadCrlSilently();
   nsresult PostCRLImportEvent(const nsCSubstring &urlString, nsIStreamListener *psmDownloader);
   nsresult getParamsForNextCrlToDownload(nsAutoString *url, PRTime *time, nsAutoString *key);
   nsresult DispatchEventToWindow(nsIDOMWindow *domWin, const nsAString &eventType, const nsAString &token);
 
   // Methods that we use to handle the profile change notifications (and to
   // synthesize a full profile change when we're just doing a profile startup):
+  void DoProfileApproveChange(nsISupports* aSubject);
   void DoProfileChangeNetTeardown();
   void DoProfileChangeTeardown(nsISupports* aSubject);
   void DoProfileBeforeChange(nsISupports* aSubject);
   void DoProfileChangeNetRestore();
   
   Mutex mutex;
   
   nsCOMPtr<nsIScriptSecurityManager> mScriptSecurityManager;
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -7,16 +7,17 @@
 
 #include "nsIAppShellService.h"
 #include "nsPIDOMWindow.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
+#include "nsIProfileChangeStatus.h"
 #include "nsIPromptService.h"
 #include "nsIStringBundle.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWindowMediator.h"
 #include "nsIWindowWatcher.h"
 #include "nsIXULRuntime.h"
 #include "nsIXULWindow.h"
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -10,16 +10,17 @@
 #include "jsapi.h"
 
 #include "nsIJSRuntimeService.h"
 #include "nsIAppStartup.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsIFile.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
+#include "nsIProfileChangeStatus.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIToolkitChromeRegistry.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsCategoryManagerUtils.h"
@@ -829,44 +830,71 @@ nsXREDirProvider::DoStartup()
     }
     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
 
     obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
   }
   return NS_OK;
 }
 
+class ProfileChangeStatusImpl MOZ_FINAL : public nsIProfileChangeStatus
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPROFILECHANGESTATUS
+  ProfileChangeStatusImpl() { }
+private:
+  ~ProfileChangeStatusImpl() { }
+};
+
+NS_IMPL_ISUPPORTS1(ProfileChangeStatusImpl, nsIProfileChangeStatus)
+
+NS_IMETHODIMP
+ProfileChangeStatusImpl::VetoChange()
+{
+  NS_ERROR("Can't veto change!");
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+ProfileChangeStatusImpl::ChangeFailed()
+{
+  NS_ERROR("Profile change cancellation.");
+  return NS_ERROR_FAILURE;
+}
+
 void
 nsXREDirProvider::DoShutdown()
 {
   if (mProfileNotified) {
     nsCOMPtr<nsIObserverService> obsSvc =
       mozilla::services::GetObserverService();
     NS_ASSERTION(obsSvc, "No observer service?");
     if (obsSvc) {
+      nsCOMPtr<nsIProfileChangeStatus> cs = new ProfileChangeStatusImpl();
       static const PRUnichar kShutdownPersist[] =
         {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
-      obsSvc->NotifyObservers(nullptr, "profile-change-net-teardown", kShutdownPersist);
-      obsSvc->NotifyObservers(nullptr, "profile-change-teardown", kShutdownPersist);
+      obsSvc->NotifyObservers(cs, "profile-change-net-teardown", kShutdownPersist);
+      obsSvc->NotifyObservers(cs, "profile-change-teardown", kShutdownPersist);
 
       // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
       // resources which are about to go away in "profile-before-change" are destroyed first.
 
       nsCOMPtr<nsIJSRuntimeService> rtsvc
         (do_GetService("@mozilla.org/js/xpc/RuntimeService;1"));
       if (rtsvc)
       {
         JSRuntime *rt = nullptr;
         rtsvc->GetRuntime(&rt);
         if (rt)
           ::JS_GC(rt);
       }
 
       // Phase 3: Notify observers of a profile change
-      obsSvc->NotifyObservers(nullptr, "profile-before-change", kShutdownPersist);
+      obsSvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
     }
     mProfileNotified = false;
   }
 }
 
 #ifdef XP_WIN
 static nsresult
 GetShellFolderPath(int folder, nsAString& _retval)