Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Wed, 01 Feb 2012 10:55:34 +0000
changeset 88776 07edb8ba21b9ddea0adde126d1057ffe940467e2
parent 88725 e18c7bc2c28e8ef21c1c975fb90add478af96bbe (current diff)
parent 88775 a22cb315b248049fea9bc20726e51958cc37091a (diff)
child 88777 2ee864faa073f8d3cc35c9e6c0daf4b0b939b61f
push id783
push userlsblakk@mozilla.com
push dateTue, 24 Apr 2012 17:33:42 +0000
treeherdermozilla-beta@11faed19f136 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
layout/generic/nsObjectFrame.cpp
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -157,16 +157,17 @@
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
+@BINPATH@/components/dom_power.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_sidebar.xpt
 @BINPATH@/components/dom_sms.xpt
 @BINPATH@/components/dom_storage.xpt
 @BINPATH@/components/dom_stylesheets.xpt
 @BINPATH@/components/dom_threads.xpt
 @BINPATH@/components/dom_traversal.xpt
 @BINPATH@/components/dom_views.xpt
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -60,16 +60,17 @@ pref("extensions.strictCompatibility", f
 // Specifies a minimum maxVersion an addon needs to say it's compatible with
 // for it to be compatible by default.
 pref("extensions.minCompatibleAppVersion", "4.0");
 
 // Preferences for AMO integration
 pref("extensions.getAddons.cache.enabled", true);
 pref("extensions.getAddons.maxResults", 15);
 pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%");
+pref("extensions.getAddons.getWithPerformance.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%");
 pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=firefox");
 pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");
 
 // Blocklist preferences
 pref("extensions.blocklist.enabled", true);
 pref("extensions.blocklist.interval", 86400);
 // Controls what level the blocklist switches from warning about items to forcibly
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -397,16 +397,17 @@ user_pref("browser.safebrowsing.provider
 user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
 user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
 user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
 // Make sure opening about:addons won't hit the network
 user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
 // Make sure AddonRepository won't hit the network
 user_pref("extensions.getAddons.maxResults", 0);
 user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
+user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
 user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
 user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
 """ % { "server" : self.webServer + ":" + str(self.httpPort) }
     prefs.append(part)
 
     if useServerLocations == False:
       part = """
 user_pref("capability.principal.codebase.p1.granted", "UniversalXPConnect");
--- a/config/system-headers
+++ b/config/system-headers
@@ -724,16 +724,17 @@ sys/poll.h
 sys/ppc.h
 sys/prctl.h
 sys/priv.h
 sys/procfs.h
 sys/pstat.h
 sys/ptrace.h
 sys/queue.h
 sys/quota.h
+sys/reboot.h
 sys/reg.h
 sys/regset.h
 sys/resource.h
 sys/sched.h
 sys/select.h
 sys/sem.h
 sys/sendfile.h
 sys/shm.h
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -328,17 +328,17 @@ public:
   // the decode monitor held.
   virtual void UpdatePlaybackPosition(PRInt64 aTime) = 0;
 
   virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
 
   virtual PRInt64 VideoQueueMemoryInUse() = 0;
   virtual PRInt64 AudioQueueMemoryInUse() = 0;
 
-  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) = 0;
+  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
 
   // Causes the state machine to switch to buffering state, and to
   // immediately stop playback and buffer downloaded data. Must be called
   // with the decode monitor held. Called on the state machine thread and
   // the main thread.
   virtual void StartBuffering() = 0;
 
   // Sets the current size of the framebuffer used in MozAudioAvailable events.
@@ -499,17 +499,17 @@ class nsBuiltinDecoder : public nsMediaD
 
   virtual PRInt64 AudioQueueMemoryInUse() {
     if (mDecoderStateMachine) {
       return mDecoderStateMachine->AudioQueueMemoryInUse();
     }
     return 0;
   }
 
-  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
+  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) {
     if (mDecoderStateMachine) {
       mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
     }
   }
 
   // Sets the length of the framebuffer used in MozAudioAvailable events.
   // The new size must be between 512 and 16384.
   virtual nsresult RequestFrameBufferLength(PRUint32 aLength);
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -493,17 +493,17 @@ public:
   PRInt64 AudioQueueMemoryInUse() {
     AudioQueueMemoryFunctor functor;
     mAudioQueue.LockedForEach(functor);
     return functor.mResult;
   }
 
   // Only used by nsWebMReader for now, so stub here rather than in every
   // reader than inherits from nsBuiltinDecoderReader.
-  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {}
+  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) {}
 
 protected:
 
   // Pumps the decode until we reach frames required to play at time aTarget
   // (usecs).
   nsresult DecodeToTarget(PRInt64 aTarget);
 
   // Reader decode function. Matches DecodeVideoFrame() and
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -1211,17 +1211,17 @@ void nsBuiltinDecoderStateMachine::Reset
   mVideoFrameEndTime = -1;
   mAudioStartTime = -1;
   mAudioEndTime = -1;
   mAudioCompleted = false;
 }
 
 void nsBuiltinDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
                                                      PRUint32 aLength,
-                                                     PRUint32 aOffset)
+                                                     PRInt64 aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
 
   // While playing an unseekable stream of unknown duration, mEndTime is
   // updated (in AdvanceFrame()) as we play. But if data is being downloaded
   // faster than played, mEndTime won't reflect the end of playable data
   // since we haven't played the frame at the end of buffered data. So update
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -218,17 +218,17 @@ public:
 
   PRInt64 AudioQueueMemoryInUse() {
     if (mReader) {
       return mReader->AudioQueueMemoryInUse();
     }
     return 0;
   }
 
-  void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
+  void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
 
   PRInt64 GetEndMediaTime() const {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
     return mEndTime;
   }
 
   bool IsSeekable() {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -330,17 +330,17 @@ public:
 
   // Called by nsChannelToPipeListener or nsMediaStream when the
   // download has ended. Called on the main thread only. aStatus is
   // the result from OnStopRequest.
   virtual void NotifyDownloadEnded(nsresult aStatus) = 0;
 
   // Called as data arrives on the stream and is read into the cache.  Called
   // on the main thread only.
-  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) = 0;
+  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
 
   // Cleanup internal data structures. Must be called on the main
   // thread by the owning object before that object disposes of this object.
   virtual void Shutdown();
 
   // Suspend any media downloads that are in progress. Called by the
   // media element when it is sent to the bfcache, or when we need
   // to throttle the download. Call on the main thread only. This can
--- a/content/media/webm/nsWebMBufferedParser.cpp
+++ b/content/media/webm/nsWebMBufferedParser.cpp
@@ -252,17 +252,17 @@ void nsWebMBufferedState::CalculateBuffe
   // from the ranges' start and end timestamps, so that those timestamps are
   // normalized in the range [0,duration].
 
   double startTime = (mTimeMapping[start].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S;
   double endTime = (mTimeMapping[end].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S;
   aBuffered->Add(startTime, endTime);
 }
 
-void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset)
+void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   PRUint32 idx;
   if (!mRangeParsers.GreatestIndexLtEq(aOffset, idx)) {
     // If the incoming data overlaps an already parsed range, adjust the
     // buffer so that we only reparse the new data.  It's also possible to
     // have an overlap where the end of the incoming data is within an
     // already parsed range, but we don't bother handling that other than by
--- a/content/media/webm/nsWebMBufferedParser.h
+++ b/content/media/webm/nsWebMBufferedParser.h
@@ -219,17 +219,17 @@ public:
   nsWebMBufferedState() : mReentrantMonitor("nsWebMBufferedState") {
     MOZ_COUNT_CTOR(nsWebMBufferedState);
   }
 
   ~nsWebMBufferedState() {
     MOZ_COUNT_DTOR(nsWebMBufferedState);
   }
 
-  void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
+  void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
   void CalculateBufferedForRange(nsTimeRanges* aBuffered,
                                  PRInt64 aStartOffset, PRInt64 aEndOffset,
                                  PRUint64 aTimecodeScale,
                                  PRInt64 aStartTimeOffsetNS);
 
 private:
   // Synchronizes access to the mTimeMapping array.
   ReentrantMonitor mReentrantMonitor;
--- a/content/media/webm/nsWebMReader.cpp
+++ b/content/media/webm/nsWebMReader.cpp
@@ -795,12 +795,12 @@ nsresult nsWebMReader::GetBuffered(nsTim
                                                 timecodeScale,
                                                 startTimeOffsetNS);
     }
   }
 
   return NS_OK;
 }
 
-void nsWebMReader::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset)
+void nsWebMReader::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset)
 {
   mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
 }
--- a/content/media/webm/nsWebMReader.h
+++ b/content/media/webm/nsWebMReader.h
@@ -156,17 +156,17 @@ public:
   {
     NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
     return mHasVideo;
   }
 
   virtual nsresult ReadMetadata(nsVideoInfo* aInfo);
   virtual nsresult Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime);
   virtual nsresult GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime);
-  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
+  virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
 
 private:
   // Value passed to NextPacket to determine if we are reading a video or an
   // audio packet.
   enum TrackType {
     VIDEO = 0,
     AUDIO = 1
   };
--- a/content/svg/content/test/test_SVGxxxListIndexing.xhtml
+++ b/content/svg/content/test/test_SVGxxxListIndexing.xhtml
@@ -22,18 +22,16 @@ var text = document.getElementById("text
     poly = document.getElementById("poly");
     g    = document.getElementById("g");
 
 function CheckList(aListObject, aExpectedListLength, aListDescription)
 {
   is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".numberOfItems");
   is(aListObject.numberOfItems, aExpectedListLength, aListDescription + ".length");
   for (let i = 0; i < aListObject.length; i++) {
-    if (aListDescription.indexOf("SVGStringList") > -1)
-      continue;
     let item = aListObject.getItem(i);
     ok(aListObject[i] === item, aListDescription + "[" + i + "]");
   }
   ok(aListObject[aListObject.length] === void 0, aListDescription + "[outOfBounds]");
 }
 
 var tests = [
   { element: text,
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -72,16 +72,17 @@ ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 DIRS += \
   interfaces/apps \
   $(NULL)
 endif
 
 DIRS += \
   base \
   battery \
+  power \
   sms \
   src \
   locales \
   network \
   plugins/base \
   plugins/ipc \
   indexedDB \
   system \
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -64,16 +64,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSContextStack.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
+#include "PowerManager.h"
 #include "SmsManager.h"
 #include "nsISmsService.h"
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "Connection.h"
 
 #ifdef MOZ_B2G_RIL
@@ -159,16 +160,18 @@ Navigator::Invalidate()
     mNotification = nsnull;
   }
 
   if (mBatteryManager) {
     mBatteryManager->Shutdown();
     mBatteryManager = nsnull;
   }
 
+  mPowerManager = nsnull;
+
   if (mSmsManager) {
     mSmsManager->Shutdown();
     mSmsManager = nsnull;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mTelephony) {
     mTelephony = nsnull;
@@ -934,16 +937,28 @@ Navigator::GetMozBattery(nsIDOMMozBatter
     mBatteryManager->Init(win, scx);
   }
 
   NS_ADDREF(*aBattery = mBatteryManager);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
+{
+  if (!mPowerManager) {
+    mPowerManager = new power::PowerManager();
+  }
+
+  NS_ADDREF(*aPower = mPowerManager);
+
+  return NS_OK;
+}
+
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorSms
 //*****************************************************************************
 
 bool
 Navigator::IsSmsAllowed() const
 {
   static const bool defaultSmsPermission = false;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -79,16 +79,20 @@ class BatteryManager;
 namespace sms {
 class SmsManager;
 } // namespace sms
 
 namespace network {
 class Connection;
 } // namespace Connection;
 
+namespace power {
+class PowerManager;
+} // namespace power
+
 class Navigator : public nsIDOMNavigator
                 , public nsIDOMClientInformation
                 , public nsIDOMNavigatorGeolocation
                 , public nsIDOMNavigatorDesktopNotification
                 , public nsIDOMMozNavigatorBattery
                 , public nsIDOMMozNavigatorSms
 #ifdef MOZ_B2G_RIL
                 , public nsIDOMNavigatorTelephony
@@ -131,16 +135,17 @@ private:
   bool IsSmsAllowed() const;
   bool IsSmsSupported() const;
 
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
+  nsRefPtr<power::PowerManager> mPowerManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
 #endif
   nsRefPtr<network::Connection> mConnection;
   nsWeakPtr mWindow;
 };
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -483,16 +483,17 @@
 #include "mozilla/dom/Element.h"
 #include "nsHTMLSelectElement.h"
 #include "nsHTMLLegendElement.h"
 
 #include "DOMSVGLengthList.h"
 #include "DOMSVGNumberList.h"
 #include "DOMSVGPathSegList.h"
 #include "DOMSVGPointList.h"
+#include "DOMSVGStringList.h"
 #include "DOMSVGTransformList.h"
 
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/indexedDB/IDBRequest.h"
 #include "mozilla/dom/indexedDB/IDBDatabase.h"
 #include "mozilla/dom/indexedDB/IDBEvents.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
@@ -509,16 +510,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsDOMTouchEvent.h"
 #include "nsIDOMCustomEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "dombindings.h"
 
 #include "nsIDOMBatteryManager.h"
 #include "BatteryManager.h"
+#include "nsIDOMPowerManager.h"
 #include "nsIDOMSmsManager.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsIDOMSmsEvent.h"
 #include "nsIDOMSmsRequest.h"
 #include "nsIDOMSmsFilter.h"
 #include "nsIDOMSmsCursor.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMConnection.h"
@@ -1288,18 +1290,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(SVGPoint, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPointList, nsSVGPointListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGPreserveAspectRatio, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)    
+  NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsSVGStringListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)    
   NS_DEFINE_CLASSINFO_DATA(SVGTransform, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGTransformList, nsSVGTransformListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGZoomEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(HTMLCanvasElement, nsElementSH,
@@ -1438,16 +1440,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(GeoPositionError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozBatteryManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
+  NS_DEFINE_CLASSINFO_DATA(MozPowerManager, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(MozSmsManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozSmsMessage, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozSmsEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -4027,16 +4032,20 @@ nsDOMClassInfo::Init()
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMGeoPositionError)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozBatteryManager, nsIDOMMozBatteryManager)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBatteryManager)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(MozPowerManager, nsIDOMMozPowerManager)
+     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozPowerManager)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(MozSmsManager, nsIDOMMozSmsManager)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsManager)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozSmsMessage, nsIDOMMozSmsMessage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozSmsMessage)
   DOM_CLASSINFO_MAP_END
 
@@ -10876,8 +10885,50 @@ nsSVGListSH<ListInterfaceType, ListType>
     // question doesn't use the nsIDOMSVGXXXList pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
     NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
   }
 #endif
 
   return list->GetItemWithoutAddRef(aIndex);
 }
+
+
+// SVGStringList helper
+
+nsresult
+nsSVGStringListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
+                               nsAString& aResult)
+{
+  if (aIndex < 0) {
+    SetDOMStringToNull(aResult);
+    return NS_OK;
+  }
+
+  DOMSVGStringList* list = static_cast<DOMSVGStringList*>(
+                             static_cast<nsIDOMSVGStringList*>(aNative));
+#ifdef DEBUG
+  {
+    nsCOMPtr<nsIDOMSVGStringList> list_qi = do_QueryInterface(aNative);
+    
+    // If this assertion fires the QI implementation for the object in
+    // question doesn't use the nsIDOMDOMSVGStringList pointer as the
+    // nsISupports pointer. That must be fixed, or we'll crash...
+    NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
+  }
+#endif
+
+  nsresult rv = list->GetItem(aIndex, aResult);
+#ifdef DEBUG
+  if (DOMStringIsNull(aResult)) {
+    PRUint32 length = 0;
+    list->GetLength(&length);
+    NS_ASSERTION(PRUint32(aIndex) >= length, "Item should only return null for out-of-bounds access");
+  }
+#endif
+  if (rv == NS_ERROR_DOM_INDEX_SIZE_ERR) {
+    SetDOMStringToNull(aResult);
+    rv = NS_OK;
+  }
+  return rv;
+}
+
+
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -1743,9 +1743,32 @@ public:
 };
 
 typedef nsSVGListSH<nsIDOMSVGLengthList, mozilla::DOMSVGLengthList> nsSVGLengthListSH;
 typedef nsSVGListSH<nsIDOMSVGNumberList, mozilla::DOMSVGNumberList> nsSVGNumberListSH;
 typedef nsSVGListSH<nsIDOMSVGPathSegList, mozilla::DOMSVGPathSegList> nsSVGPathSegListSH;
 typedef nsSVGListSH<nsIDOMSVGPointList, mozilla::DOMSVGPointList> nsSVGPointListSH;
 typedef nsSVGListSH<nsIDOMSVGTransformList, mozilla::DOMSVGTransformList> nsSVGTransformListSH;
 
+// SVGStringList helper
+
+class nsSVGStringListSH : public nsStringArraySH
+{
+protected:
+  nsSVGStringListSH(nsDOMClassInfoData* aData) : nsStringArraySH(aData)
+  {
+  }
+  
+  virtual ~nsSVGStringListSH()
+  {
+  }
+  
+  virtual nsresult GetStringAt(nsISupports *aNative, PRInt32 aIndex,
+                               nsAString& aResult);
+  
+public:
+  static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
+  {
+    return new nsSVGStringListSH(aData);
+  }
+};
+
 #endif /* nsDOMClassInfo_h___ */
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -425,16 +425,18 @@ DOMCI_CLASS(MessageEvent)
 DOMCI_CLASS(GeoGeolocation)
 DOMCI_CLASS(GeoPosition)
 DOMCI_CLASS(GeoPositionCoords)
 DOMCI_CLASS(GeoPositionAddress)
 DOMCI_CLASS(GeoPositionError)
 
 DOMCI_CLASS(MozBatteryManager)
 
+DOMCI_CLASS(MozPowerManager)
+
 DOMCI_CLASS(MozSmsManager)
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozSmsEvent)
 DOMCI_CLASS(MozSmsRequest)
 DOMCI_CLASS(MozSmsFilter)
 DOMCI_CLASS(MozSmsCursor)
 
 DOMCI_CLASS(MozConnection)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7675,19 +7675,19 @@ void nsGlobalWindow::UpdateTouchState()
   if (!mainWidget)
     return;
 
   if (mMayHaveTouchEventListener) {
     mainWidget->RegisterTouchWindow();
 
     nsCOMPtr<nsIObserverService> observerService =
       do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+
     if (observerService) {
-      nsPIDOMWindow *inner = GetCurrentInnerWindowInternal();
-      observerService->NotifyObservers(mainWidget,
+      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
                                        DOM_TOUCH_LISTENER_ADDED,
                                        nsnull);
     }
   } else {
     mainWidget->UnregisterTouchWindow();
   }
 }
 
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -1,11 +1,12 @@
 DOM_SRCDIRS = \
   dom/base \
   dom/battery \
+  dom/power \
   dom/network/src \
   dom/sms/src \
   dom/src/events \
   dom/src/storage \
   dom/src/offline \
   dom/src/geolocation \
   dom/src/notification \
   dom/workers \
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -124,8 +124,11 @@ interface nsIDOMRange;
 // Crypto
 interface nsIDOMCRMFObject;
 interface nsIDOMCrypto;
 interface nsIDOMPkcs11;
 
 // Used font face (for inspector)
 interface nsIDOMFontFace;
 interface nsIDOMFontFaceList;
+
+// Power
+interface nsIDOMMozPowerManager;
--- a/dom/interfaces/base/nsIDOMNavigator.idl
+++ b/dom/interfaces/base/nsIDOMNavigator.idl
@@ -34,36 +34,37 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(a1ee08c1-0299-4908-a6ba-7cBc8da6531f)]
+[scriptable, uuid(b1f4b1fa-49c2-4375-9ce8-bf97ecf6b428)]
 interface nsIDOMNavigator : nsISupports
 {
-  readonly attribute DOMString           appCodeName;
-  readonly attribute DOMString           appName;
-  readonly attribute DOMString           appVersion;
-  readonly attribute DOMString           language;
-  readonly attribute nsIDOMMimeTypeArray mimeTypes;
-  readonly attribute DOMString           platform;
-  readonly attribute DOMString           oscpu;
-  readonly attribute DOMString           vendor;
-  readonly attribute DOMString           vendorSub;
-  readonly attribute DOMString           product;
-  readonly attribute DOMString           productSub;
-  readonly attribute nsIDOMPluginArray   plugins;
-  readonly attribute DOMString           userAgent;
-  readonly attribute boolean             cookieEnabled;
-  readonly attribute boolean             onLine;
-  readonly attribute DOMString           buildID;
-  readonly attribute DOMString           doNotTrack;
+  readonly attribute DOMString             appCodeName;
+  readonly attribute DOMString             appName;
+  readonly attribute DOMString             appVersion;
+  readonly attribute DOMString             language;
+  readonly attribute nsIDOMMimeTypeArray   mimeTypes;
+  readonly attribute DOMString             platform;
+  readonly attribute DOMString             oscpu;
+  readonly attribute DOMString             vendor;
+  readonly attribute DOMString             vendorSub;
+  readonly attribute DOMString             product;
+  readonly attribute DOMString             productSub;
+  readonly attribute nsIDOMPluginArray     plugins;
+  readonly attribute DOMString             userAgent;
+  readonly attribute boolean               cookieEnabled;
+  readonly attribute boolean               onLine;
+  readonly attribute DOMString             buildID;
+  readonly attribute DOMString             doNotTrack;
+  readonly attribute nsIDOMMozPowerManager mozPower;
 
   boolean                   javaEnabled();
 
   /**
    * Pulse the device's vibrator, if it has one.  If the device does not have a
    * vibrator, this function does nothing.  If the window is hidden, this
    * function does nothing.
    *
new file mode 100644
--- /dev/null
+++ b/dom/power/Makefile.in
@@ -0,0 +1,73 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME     = dom_power_s
+XPIDL_MODULE     = dom_power
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/dom/dom-config.mk
+
+EXPORTS_NAMESPACES = mozilla/dom/power
+
+EXPORTS_mozilla/dom/power = \
+  PowerManagerService.h \
+  $(NULL)
+
+CPPSRCS = \
+  PowerManager.cpp \
+  PowerManagerService.cpp \
+  $(NULL)
+
+XPIDLSRCS = \
+  nsIDOMPowerManager.idl \
+  nsIPowerManagerService.idl \
+  $(NULL)
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/power/PowerManager.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "PowerManager.h"
+#include "nsContentUtils.h"
+#include "nsDOMClassInfoID.h"
+#include "nsIPowerManagerService.h"
+#include "nsServiceManagerUtils.h"
+
+DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
+
+namespace mozilla {
+namespace dom {
+namespace power {
+
+NS_INTERFACE_MAP_BEGIN(PowerManager)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozPowerManager)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozPowerManager)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozPowerManager)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(PowerManager)
+NS_IMPL_RELEASE(PowerManager)
+
+NS_IMETHODIMP
+PowerManager::Reboot()
+{
+  NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
+
+  nsCOMPtr<nsIPowerManagerService> pmService =
+    do_GetService(POWERMANAGERSERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(pmService, NS_OK);
+
+  pmService->Reboot();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PowerManager::PowerOff()
+{
+  NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
+
+  nsCOMPtr<nsIPowerManagerService> pmService =
+    do_GetService(POWERMANAGERSERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(pmService, NS_OK);
+
+  pmService->PowerOff();
+
+  return NS_OK;
+}
+
+} // power
+} // dom
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/dom/power/PowerManager.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef mozilla_dom_power_PowerManager_h
+#define mozilla_dom_power_PowerManager_h
+
+#include "nsIDOMPowerManager.h"
+
+namespace mozilla {
+namespace dom {
+namespace power {
+
+class PowerManager
+  : public nsIDOMMozPowerManager
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMMOZPOWERMANAGER
+
+  PowerManager() {};
+  virtual ~PowerManager() {};
+};
+
+} // namespace power
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_power_PowerManager_h
new file mode 100644
--- /dev/null
+++ b/dom/power/PowerManagerService.cpp
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/Hal.h"
+#include "PowerManagerService.h"
+
+namespace mozilla {
+namespace dom {
+namespace power {
+
+NS_IMPL_ISUPPORTS1(PowerManagerService, nsIPowerManagerService)
+
+/* static */ already_AddRefed<nsIPowerManagerService>
+PowerManagerService::GetInstance()
+{
+  nsCOMPtr<nsIPowerManagerService> pmService;
+
+  pmService = new PowerManagerService();
+
+  return pmService.forget();
+}
+
+NS_IMETHODIMP
+PowerManagerService::Reboot()
+{
+  hal::Reboot();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PowerManagerService::PowerOff()
+{
+  hal::PowerOff();
+  return NS_OK;
+}
+
+} // power
+} // dom
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/dom/power/PowerManagerService.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef mozilla_dom_power_PowerManagerService_h
+#define mozilla_dom_power_PowerManagerService_h
+
+#include "nsIPowerManagerService.h"
+#include "nsCOMPtr.h" // for already_AddRefed
+
+namespace mozilla {
+namespace dom {
+namespace power {
+
+class PowerManagerService
+  : public nsIPowerManagerService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPOWERMANAGERSERVICE
+
+  static already_AddRefed<nsIPowerManagerService> GetInstance();
+};
+
+} // namespace power
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_power_PowerManagerService_h
new file mode 100644
--- /dev/null
+++ b/dom/power/nsIDOMPowerManager.idl
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(6ec16abc-2fe8-4ab3-99b0-0f08405be81b)]
+interface nsIDOMMozPowerManager : nsISupports
+{
+    void powerOff();
+    void reboot();
+};
new file mode 100644
--- /dev/null
+++ b/dom/power/nsIPowerManagerService.idl
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{C++
+#define NS_POWERMANAGERSERVICE_CID { 0x18c2e238, 0x3a0a, 0x4153, {0x89, 0xfc, 0x16, 0x6b, 0x3b, 0x14, 0x65, 0xa1 } }
+#define POWERMANAGERSERVICE_CONTRACTID "@mozilla.org/power/powermanagerservice;1"
+%}
+
+[scriptable, builtinclass, uuid(38919539-4641-4f0b-9f11-6b6294a9386f)]
+interface nsIPowerManagerService : nsISupports
+{
+    void powerOff();
+    void reboot();
+};
new file mode 100644
--- /dev/null
+++ b/dom/power/test/Makefile.in
@@ -0,0 +1,59 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org build system.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH            = ../../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+relativesrcdir   = dom/power/test
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = \
+  test_power_basics.html \
+  $(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
+
+#libs:: $(_CHROME_TEST_FILES)
+#	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/power/test/test_power_basics.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Power API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Power API **/
+
+ok('mozPower' in navigator, "navigator.mozPower should exist");
+
+</script>
+</pre>
+</body>
+</html>
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -367,10 +367,22 @@ GetCurrentNetworkInformation(NetworkInfo
 
 void
 NotifyNetworkChange(const NetworkInformation& aInfo)
 {
   sNetworkObservers.CacheInformation(aInfo);
   sNetworkObservers.BroadcastCachedInformation();
 }
 
+void Reboot()
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(Reboot());
+}
+
+void PowerOff()
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(PowerOff());
+}
+
 } // namespace hal
 } // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -187,16 +187,26 @@ void UnregisterNetworkObserver(NetworkOb
 void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
 
 /**
  * Notify of a change in the network state.
  * @param aNetworkInfo The new network information.
  */
 void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
 
+/**
+ * Reboot the device.
+ */
+void Reboot();
+
+/**
+ * Power off the device.
+ */
+void PowerOff();
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #ifdef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_HAL_NAMESPACE
 #endif
 
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -67,19 +67,19 @@ CPPSRCS = \
   Hal.cpp \
   SandboxHal.cpp \
   WindowIdentifier.cpp \
   $(NULL)
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += AndroidHal.cpp
 else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
-CPPSRCS += GonkHal.cpp
+CPPSRCS += GonkHal.cpp Power.cpp
 else ifeq (Linux,$(OS_TARGET))
-CPPSRCS += LinuxHal.cpp
+CPPSRCS += LinuxHal.cpp Power.cpp
 ifdef MOZ_ENABLE_DBUS
 CPPSRCS += UPowerClient.cpp
 endif
 else ifeq (WINNT,$(OS_TARGET))
 CPPSRCS += WindowsHal.cpp WindowsBattery.cpp
 else
 CPPSRCS += FallbackHal.cpp
 endif
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -168,11 +168,19 @@ GetCurrentNetworkInformation(hal::Networ
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
   }
 
   bridge->GetCurrentNetworkInformation(aNetworkInfo);
 }
 
+void
+Reboot()
+{}
+
+void
+PowerOff()
+{}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -100,10 +100,18 @@ DisableNetworkNotifications()
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
   aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
   aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
 }
 
+void
+Reboot()
+{}
+
+void
+PowerOff()
+{}
+
 } // hal_impl
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/hal/linux/Power.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kan-Ru Chen <kchen@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "Hal.h"
+
+#include <unistd.h>
+#include <sys/reboot.h>
+
+namespace mozilla {
+namespace hal_impl {
+
+void
+Reboot()
+{
+  reboot(RB_AUTOBOOT);
+}
+
+void
+PowerOff()
+{
+  reboot(RB_POWER_OFF);
+}
+
+} // hal_impl
+} // mozilla
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -81,13 +81,16 @@ parent:
       returns (NetworkInformation aNetworkInfo);
 
     sync GetScreenEnabled() returns (bool enabled);
     SetScreenEnabled(bool enabled);
 
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
 
+    Reboot();
+    PowerOff();
+
     __delete__();
 };
 
 } // namespace hal
 } // namespace mozilla
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -147,16 +147,28 @@ GetScreenBrightness()
 }
 
 void
 SetScreenBrightness(double brightness)
 {
   Hal()->SendSetScreenBrightness(brightness);
 }
 
+void
+Reboot()
+{
+  Hal()->SendReboot();
+}
+
+void
+PowerOff()
+{
+  Hal()->SendPowerOff();
+}
+
 class HalParent : public PHalParent
                 , public BatteryObserver
                 , public NetworkObserver
 {
 public:
   NS_OVERRIDE virtual bool
   RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
               const InfallibleTArray<uint64> &id,
@@ -262,16 +274,30 @@ public:
   }
 
   NS_OVERRIDE virtual bool
   RecvSetScreenBrightness(const double &brightness)
   {
     hal::SetScreenBrightness(brightness);
     return true;
   }
+
+  NS_OVERRIDE virtual bool
+  RecvReboot()
+  {
+    hal::Reboot();
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvPowerOff()
+  {
+    hal::PowerOff();
+    return true;
+  }
 };
 
 class HalChild : public PHalChild {
 public:
   NS_OVERRIDE virtual bool
   RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) {
     hal::NotifyBatteryChange(aBatteryInfo);
     return true;
--- a/hal/windows/WindowsHal.cpp
+++ b/hal/windows/WindowsHal.cpp
@@ -79,10 +79,18 @@ DisableNetworkNotifications()
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
   aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
   aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
 }
 
+void
+Reboot()
+{}
+
+void
+PowerOff()
+{}
+
 } // hal_impl
 } // mozilla
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -724,16 +724,17 @@ sys/poll.h
 sys/ppc.h
 sys/prctl.h
 sys/priv.h
 sys/procfs.h
 sys/pstat.h
 sys/ptrace.h
 sys/queue.h
 sys/quota.h
+sys/reboot.h
 sys/reg.h
 sys/regset.h
 sys/resource.h
 sys/sched.h
 sys/select.h
 sys/sem.h
 sys/sendfile.h
 sys/shm.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/Proxy-function-freeze.js
@@ -0,0 +1,115 @@
+// Once a function proxy has been frozen, its handler's traps are no longer called,
+// but its call traps are.
+
+var callTrapCalls;
+function handleCall() {
+    print('call');
+    callTrapCalls++;
+    return 'favor';
+}
+function handleConstruct() {
+    print('construct');
+    callTrapCalls++;
+    return 'compliment';
+}
+
+var descriptorForX = { configurable: true, enumerable: true, writable: true, value: 42 };
+var trapCalls;
+var handler = {
+    getOwnPropertyNames: function () {
+        print('getOwnPropertyNames');
+        trapCalls++;
+        return ['x'];
+    },
+    getPropertyNames: function() {
+        print('getPropertyNames');
+        trapCalls++;
+        return ['x'];
+    },
+    getOwnPropertyDescriptor: function(name) {
+        print('getOwnPropertyDescriptor');
+        trapCalls++;
+        assertEq(name, 'x');
+        return descriptorForX;
+    },
+    getPropertyDescriptor: function(name) {
+        print('getPropertyDescriptor');
+        trapCalls++;
+        assertEq(name, 'x');
+        return descriptorForX;
+    },
+    defineProperty: function(name, propertyDescriptor) {
+        print('defineProperty');
+        trapCalls++;
+    },
+    delete: function(name) {
+        print('delete');
+        trapCalls++;
+        return false;
+    },
+    fix: function() {
+        print('fix');
+        trapCalls++;
+        return { x: descriptorForX };
+    }
+};
+
+var fp = Proxy.createFunction(handler, handleCall, handleConstruct);
+
+trapCalls = callTrapCalls = 0;
+assertEq(Object.getOwnPropertyNames(fp)[0], 'x');
+assertEq(trapCalls > 0, true);
+assertEq(callTrapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42);
+assertEq(trapCalls > 0, true);
+assertEq(callTrapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(delete fp.x, false);
+assertEq(trapCalls > 0, true);
+assertEq(callTrapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(fp(), 'favor');
+assertEq(trapCalls, 0);
+assertEq(callTrapCalls, 1);
+
+trapCalls = callTrapCalls = 0;
+assertEq(new fp, 'compliment');
+assertEq(trapCalls, 0);
+assertEq(callTrapCalls, 1);
+
+trapCalls = callTrapCalls = 0;
+Object.freeze(fp);
+assertEq(trapCalls > 0, true);
+assertEq(callTrapCalls, 0);
+
+// Once the proxy has been frozen, its traps should never be invoked any
+// more.
+trapCalls = callTrapCalls = 0;
+assertEq(Object.getOwnPropertyNames(fp)[0], 'x');
+assertEq(trapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(Object.getOwnPropertyDescriptor(fp, 'x').value, 42);
+assertEq(trapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(delete fp.x, false);
+assertEq(trapCalls, 0);
+
+trapCalls = callTrapCalls = 0;
+assertEq(fp(), 'favor');
+assertEq(trapCalls, 0);
+assertEq(callTrapCalls, 1);
+
+trapCalls = callTrapCalls = 0;
+assertEq(new fp, 'compliment');
+assertEq(trapCalls, 0);
+assertEq(callTrapCalls, 1);
+
+trapCalls = callTrapCalls = 0;
+Object.freeze(fp);
+assertEq(trapCalls, 0);
--- a/js/src/jsclass.h
+++ b/js/src/jsclass.h
@@ -381,22 +381,32 @@ JS_STATIC_ASSERT(offsetof(JSClass, hasIn
 JS_STATIC_ASSERT(offsetof(JSClass, trace) == offsetof(Class, trace));
 JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
 
 static JS_ALWAYS_INLINE JSClass *
 Jsvalify(Class *c)
 {
     return (JSClass *)c;
 }
+static JS_ALWAYS_INLINE const JSClass *
+Jsvalify(const Class *c)
+{
+    return (const JSClass *)c;
+}
 
 static JS_ALWAYS_INLINE Class *
 Valueify(JSClass *c)
 {
     return (Class *)c;
 }
+static JS_ALWAYS_INLINE const Class *
+Valueify(const JSClass *c)
+{
+    return (const Class *)c;
+}
 
 /*
  * Enumeration describing possible values of the [[Class]] internal property
  * value of objects.
  */
 enum ESClassValue { ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean };
 
 /*
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -338,41 +338,21 @@ js::BoxNonStrictThis(JSContext *cx, cons
     return true;
 }
 
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32_t JSSLOT_FOUND_FUNCTION  = 0;
 const uint32_t JSSLOT_SAVED_ID        = 1;
 
-static void
-no_such_method_trace(JSTracer *trc, JSObject *obj)
-{
-    gc::MarkValue(trc, obj->getSlotRef(JSSLOT_FOUND_FUNCTION), "found function");
-    gc::MarkValue(trc, obj->getSlotRef(JSSLOT_SAVED_ID), "saved id");
-}
-
 Class js_NoSuchMethodClass = {
     "NoSuchMethod",
     JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    NULL,                    /* finalize */
-    NULL,                    /* reserved0 */
-    NULL,                    /* checkAccess */
-    NULL,                    /* call */
-    NULL,                    /* construct */
-    NULL,                    /* XDR */
-    NULL,                    /* hasInstance */
-    no_such_method_trace     /* trace */
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
 };
 
 /*
  * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
  * the base object, we search for the __noSuchMethod__ method in the base.
  * If it exists, we store the method and the property's id into an object of
  * NoSuchMethod class and store this object into the callee's stack slot.
  * Later, Invoke will recognise such an object and transfer control to
@@ -2808,16 +2788,22 @@ BEGIN_CASE(JSOP_FUNAPPLY)
         DO_NEXT_OP(len);
     }
 
     TypeMonitorCall(cx, args, construct);
 
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
 
     JSScript *newScript = fun->script();
+
+    if (newScript->compileAndGo && newScript->hasClearedGlobal()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
+        goto error;
+    }
+
     if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, newScript, initial))
         goto error;
 
     RESTORE_INTERP_VARS();
 
     if (!regs.fp()->functionPrologue(cx))
         goto error;
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1455,17 +1455,17 @@ JS_FRIEND_DATA(Class) js::FunctionProxyC
         proxy_SetPropertyAttributes,
         proxy_SetElementAttributes,
         proxy_SetSpecialAttributes,
         proxy_DeleteProperty,
         proxy_DeleteElement,
         proxy_DeleteSpecial,
         NULL,                /* enumerate       */
         proxy_TypeOf,
-        NULL,                /* fix             */
+        proxy_Fix,           /* fix             */
         NULL,                /* thisObject      */
         NULL,                /* clear           */
     }
 };
 
 JS_FRIEND_API(JSObject *)
 js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSObject *proto,
                    JSObject *parent, JSObject *call, JSObject *construct)
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -50,16 +50,20 @@
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeEmitter.h"
 #include "vm/GlobalObject-inl.h"
 
 #include "jsobjinlines.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 
+#ifdef JS_METHODJIT
+#include "methodjit/Retcon.h"
+#endif
+
 using namespace js;
 
 JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     return obj->asGlobal().getOrCreateObjectPrototype(cx);
@@ -355,16 +359,31 @@ GlobalObject::clear(JSContext *cx)
     flags |= FLAGS_CLEARED;
     setSlot(FLAGS, Int32Value(flags));
 
     /*
      * Reset the new object cache in the compartment, which assumes that
      * prototypes cached on the global object are immutable.
      */
     cx->compartment->newObjectCache.reset();
+
+#ifdef JS_METHODJIT
+    /*
+     * Destroy compiled code for any scripts parented to this global. Call ICs
+     * can directly call scripts which have associated JIT code, and do so
+     * without checking whether the script's global has been cleared.
+     */
+    for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
+        if (script->compileAndGo && script->hasJITCode() && script->hasClearedGlobal()) {
+            mjit::Recompiler::clearStackReferences(cx, script);
+            mjit::ReleaseScriptCode(cx, script);
+        }
+    }
+#endif
 }
 
 bool
 GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx)
 {
     HeapValue &v = getSlotRef(RUNTIME_CODEGEN_ENABLED);
     if (v.isUndefined()) {
         JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3243,16 +3243,39 @@ nsXPCComponents_utils_Sandbox::CallOrCon
 
             if (!compartmentPrivate || !compartmentPrivate->key)
                 return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
 
             identity = compartmentPrivate->key->GetPtr();
         }
     }
 
+    // If there is no options object given, or no sandboxName property
+    // specified, use the caller's filename as sandboxName.
+    if (sandboxName.IsEmpty()) {
+        nsXPConnect* xpc = nsXPConnect::GetXPConnect();
+
+        if (!xpc)
+            return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
+
+        // Get the xpconnect native call context.
+        nsAXPCNativeCallContext *cc = nsnull;
+        xpc->GetCurrentNativeCallContext(&cc);
+
+        if (!cc)
+            return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
+
+        // Get the current source info from xpc.
+        nsCOMPtr<nsIStackFrame> frame;
+        xpc->GetCurrentJSStack(getter_AddRefs(frame));
+
+        if (frame)
+            frame->GetFilename(getter_Copies(sandboxName));
+    }
+
     rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays, sandboxName, identity);
 
     if (NS_FAILED(rv)) {
         return ThrowAndFail(rv, cx, _retval);
     }
 
     *_retval = true;
 
@@ -3667,22 +3690,22 @@ nsXPCComponents_Utils::SchedulePreciseSh
 }
 
 /* [implicit_jscontext] jsval nondeterministicGetWeakMapKeys(in jsval aMap); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::NondeterministicGetWeakMapKeys(const jsval &aMap,
                                                       JSContext *aCx,
                                                       jsval *aKeys)
 {
-    if(!JSVAL_IS_OBJECT(aMap)) {
+    if (!JSVAL_IS_OBJECT(aMap)) {
         *aKeys = JSVAL_VOID;
         return NS_OK; 
     }
     JSObject *objRet;
-    if(!JS_NondeterministicGetWeakMapKeys(aCx, JSVAL_TO_OBJECT(aMap), &objRet))
+    if (!JS_NondeterministicGetWeakMapKeys(aCx, JSVAL_TO_OBJECT(aMap), &objRet))
         return NS_ERROR_OUT_OF_MEMORY;
     *aKeys = objRet ? OBJECT_TO_JSVAL(objRet) : JSVAL_VOID;
     return NS_OK;
 }
 
 /* void getGlobalForObject(); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetGlobalForObject(const JS::Value& object,
--- a/js/xpconnect/tests/mochitest/test_bug605167.html
+++ b/js/xpconnect/tests/mochitest/test_bug605167.html
@@ -31,17 +31,18 @@ function go() {
         case 2:
                 frames[0].location = targetUrl;
                 break;
         case 3:
                 try {
                     f().cross_origin_property;
                     ok(false, "should have thrown an exception");
                 } catch (e) {
-                    ok(/Permission denied/.test(e), "threw the correct exception");
+                    ok(/Permission denied/.test(e) || /attempt to run compile-and-go script/.test(e),
+                       "threw the correct exception");
                 }
                 SimpleTest.finish();
                 break;
         }
 }
 
 
 SimpleTest.waitForExplicitFinish();
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -88,16 +88,17 @@ SHARED_LIBRARY_LIBS = \
 	$(DEPTH)/content/xslt/src/xml/$(LIB_PREFIX)txxml_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xslt/src/xpath/$(LIB_PREFIX)txxpath_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xslt/src/xslt/$(LIB_PREFIX)txxslt_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xbl/src/$(LIB_PREFIX)gkconxbl_s.$(LIB_SUFFIX) \
 	$(DEPTH)/content/xul/document/src/$(LIB_PREFIX)gkconxuldoc_s.$(LIB_SUFFIX) \
 	$(DEPTH)/view/src/$(LIB_PREFIX)gkview_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/battery/$(LIB_PREFIX)dom_battery_s.$(LIB_SUFFIX) \
+	$(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/storage/$(LIB_PREFIX)jsdomstorage_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/offline/$(LIB_PREFIX)jsdomoffline_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/geolocation/$(LIB_PREFIX)jsdomgeolocation_s.$(LIB_SUFFIX) \
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -248,19 +248,24 @@ static void Shutdown();
     defined(android)
 #include "nsDeviceMotionSystem.h"
 #endif
 #endif
 #include "nsCSPService.h"
 #include "nsISmsService.h"
 #include "nsISmsDatabaseService.h"
 #include "mozilla/dom/sms/SmsServicesFactory.h"
+#include "nsIPowerManagerService.h"
 
 using namespace mozilla::dom::sms;
 
+#include "mozilla/dom/power/PowerManagerService.h"
+
+using mozilla::dom::power::PowerManagerService;
+
 // Transformiix
 /* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
 #define TRANSFORMIIX_NODESET_CID \
 { 0x5d5d92cd, 0x6bf8, 0x11d9, { 0xbf, 0x4a, 0x0, 0x0a, 0x95, 0xdc, 0x23, 0x4c } }
 
 #define TRANSFORMIIX_NODESET_CONTRACTID \
 "@mozilla.org/transformiix-nodeset;1"
 
@@ -297,16 +302,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceM
 #endif
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback)
 #endif
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsService, SmsServicesFactory::CreateSmsService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsDatabaseService, SmsServicesFactory::CreateSmsDatabaseService)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
+                                         PowerManagerService::GetInstance)
 
 //-----------------------------------------------------------------------------
 
 // Per bug 209804, it is necessary to observe the "xpcom-shutdown" event and
 // perform shutdown of the layout modules at that time instead of waiting for
 // our module destructor to run.  If we do not do this, then we risk holding
 // references to objects in other component libraries that have already been
 // shutdown (and possibly unloaded if 60709 is ever fixed).
@@ -788,16 +795,17 @@ NS_DEFINE_NAMED_CID(NS_STRUCTUREDCLONECO
 NS_DEFINE_NAMED_CID(NS_DEVICE_MOTION_CID);
 #endif
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
 NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID);
 #endif
 #endif
 NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(SMS_DATABASE_SERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 
 static nsresult
 CreateWindowCommandTableConstructor(nsISupports *aOuter,
                                     REFNSIID aIID, void **aResult)
 {
   nsresult rv;
   nsCOMPtr<nsIControllerCommandTable> commandTable =
       do_CreateInstance(NS_CONTROLLERCOMMANDTABLE_CONTRACTID, &rv);
@@ -1058,16 +1066,17 @@ static const mozilla::Module::CIDEntry k
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
   { &kNS_HAPTICFEEDBACK_CID, false, NULL, nsHapticFeedbackConstructor },
 #endif
 #endif
   { &kTHIRDPARTYUTIL_CID, false, NULL, ThirdPartyUtilConstructor },
   { &kNS_STRUCTUREDCLONECONTAINER_CID, false, NULL, nsStructuredCloneContainerConstructor },
   { &kSMS_SERVICE_CID, false, NULL, nsISmsServiceConstructor },
   { &kSMS_DATABASE_SERVICE_CID, false, NULL, nsISmsDatabaseServiceConstructor },
+  { &kNS_POWERMANAGERSERVICE_CID, false, NULL, nsIPowerManagerServiceConstructor },
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   XPCONNECT_CONTRACTS
   { "@mozilla.org/layout/xul-boxobject;1", &kNS_BOXOBJECT_CID },
 #ifdef MOZ_XUL
   { "@mozilla.org/layout/xul-boxobject-listbox;1", &kNS_LISTBOXOBJECT_CID },
@@ -1193,16 +1202,17 @@ static const mozilla::Module::ContractID
 #if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
   { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID },
 #endif
 #endif
   { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
   { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
   { SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
   { SMS_DATABASE_SERVICE_CONTRACTID, &kSMS_DATABASE_SERVICE_CID },
+  { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
   { NULL }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   XPCONNECT_CATEGORIES
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY, "Image", NS_HTMLIMGELEMENT_CONTRACTID },
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY, "Image", "HTMLImageElement" },
   { JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY, "Option", NS_HTMLOPTIONELEMENT_CONTRACTID },
--- a/layout/reftests/bidi/718236-1-ref.html
+++ b/layout/reftests/bidi/718236-1-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
  <head>
   <meta charset="utf-8">
  </head>
  <body>
-  <div>&#x062A;<span>&#x0661;&#x0663;</span></div>
+  <div>&#x062A;<span>&#x0661;</span><span>&#x0663;</span></div>
  </body>
 </html>
--- a/layout/reftests/bidi/718236-2-ref.html
+++ b/layout/reftests/bidi/718236-2-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
  <head>
   <meta charset="utf-8">
  </head>
  <body>
-  <div><span>&#x0661;&#x0663;</span>&#x062A;</div>
+  <div><span>&#x0661;</span><span>&#x0663;</span>&#x062A;</div>
  </body>
 </html>
--- a/layout/reftests/bidi/718236-3-ref.html
+++ b/layout/reftests/bidi/718236-3-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
  <head>
   <meta charset="utf-8">
  </head>
  <body>
-  <div><span>&#x0661;&#x0663;</span></div>
+  <div><span>&#x0661;</span><span>&#x0663;</span></div>
  </body>
 </html>
--- a/layout/tools/reftest/reftest-analyzer.xhtml
+++ b/layout/tools/reftest/reftest-analyzer.xhtml
@@ -132,16 +132,17 @@ function hash_parameters() {
 function load() {
   gPhases = [ ID("entry"), ID("loading"), ID("viewer") ];
   build_mag();
   var params = hash_parameters();
   if (params.log) {
     ID("logentry").value = params.log;
     log_pasted();
   }
+  window.addEventListener('keypress', maybe_load_image, false);
 }
 
 function build_mag() {
   var mag = ID("mag");
 
   var r = document.createElementNS(SVG_NS, "rect");
   r.setAttribute("x", gMagZoom * -gMagWidth / 2);
   r.setAttribute("y", gMagZoom * -gMagHeight / 2);
@@ -369,16 +370,29 @@ function show_image(i) {
     ID("image1").style.display = "";
     ID("image2").style.display = "none";
   } else {
     ID("image1").style.display = "none";
     ID("image2").style.display = "";
   }
 }
 
+function maybe_load_image(event) {
+  switch (event.charCode) {
+  case 49: // "1" key
+    document.getElementById("radio1").checked = true;
+    show_image(1);
+    break;
+  case 50: // "2" key
+    document.getElementById("radio2").checked = true;
+    show_image(2);
+    break;
+  }
+}
+
 function show_differences(cb) {
   ID("diffrect").style.display = cb.checked ? "" : "none";
 }
 
 function flash_pixels(on) {
   var stroke = on ? "red" : "black";
   var strokeWidth = on ? "2px" : "1px";
   for (var i = 0; i < gFlashingPixels.length; i++) {
@@ -508,18 +522,18 @@ function show_pixelinfo(x, y, pix1rgb, p
       <svg xmlns="http://www.w3.org/2000/svg" width="84" height="84" shape-rendering="optimizeSpeed">
         <g id="mag"/>
       </svg>
     </div>
   </div>
   <div id="itemlist"></div>
   <div id="images" style="display:none">
     <form id="imgcontrols">
-    <label><input type="radio" name="which" value="0" onchange="show_image(1)" checked="checked" />Image 1</label>
-    <label><input type="radio" name="which" value="1" onchange="show_image(2)" />Image 2</label>
+    <label title="1"><input id="radio1" type="radio" name="which" value="0" onchange="show_image(1)" checked="checked" />Image 1</label>
+    <label title="2"><input id="radio2" type="radio" name="which" value="1" onchange="show_image(2)" />Image 2</label>
     <label><input type="checkbox" onchange="show_differences(this)" />Circle differences</label>
     </form>
     <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800px" height="1000px" viewBox="0 0 800 1000" id="svg">
       <defs>
         <!-- use sRGB to avoid loss of data -->
         <filter id="showDifferences" x="0%" y="0%" width="100%" height="100%"
                 style="color-interpolation-filters: sRGB">
           <feImage id="feimage1" result="img1" xlink:href="#image1" />
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -35,16 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.FloatSize;
 import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
 import org.mozilla.gecko.gfx.IntSize;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PlaceholderLayerClient;
 import org.mozilla.gecko.gfx.RectUtils;
 import org.mozilla.gecko.gfx.ViewportMetrics;
@@ -145,18 +146,16 @@ abstract public class GeckoApp
     private static AbsoluteLayout mPluginContainer;
 
     public String mLastTitle;
     public String mLastViewport;
     public byte[] mLastScreen;
     public int mOwnActivityDepth = 0;
     private boolean mRestoreSession = false;
 
-    private Vector<View> mPluginViews = new Vector<View>();
-
     public interface OnTabsChangedListener {
         public void onTabsChanged(Tab tab);
     }
     
     private static ArrayList<OnTabsChangedListener> mTabsChangedListeners;
 
     static class ExtraMenuItem implements MenuItem.OnMenuItemClickListener {
         String label;
@@ -593,16 +592,23 @@ abstract public class GeckoApp
         final Bitmap bitmap = isSelectedTab ?
             mSoftwareLayerClient.getBitmap() : null;
         
         if (bitmap != null) {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
             processThumbnail(tab, bitmap, bos.toByteArray());
         } else {
+            if (!tab.hasLoaded()) {
+                byte[] thumbnail = BrowserDB.getThumbnailForUrl(getContentResolver(), tab.getURL());
+                if (thumbnail != null)
+                    processThumbnail(tab, null, thumbnail);
+                return;
+            }
+
             mLastScreen = null;
             int sw = forceBigSceenshot ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
             int sh = forceBigSceenshot ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
             int dw = forceBigSceenshot ? sw : tab.getThumbnailWidth();
             int dh = forceBigSceenshot ? sh : tab.getThumbnailHeight();
             try {
                 JSONObject message = new JSONObject();
                 message.put("tabID", tab.getId());
@@ -736,16 +742,19 @@ abstract public class GeckoApp
             public void run() {
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     mBrowserToolbar.setTitle(uri);
                     mBrowserToolbar.setFavicon(null);
                     mBrowserToolbar.setSecurityMode("unknown");
                     mDoorHangerPopup.updatePopup();
                     mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
                     mLayerController.setWaitForTouchListeners(false);
+
+                    if (tab != null)
+                        hidePluginViews(tab);
                 }
             }
         });
     }
 
     void handleSecurityChange(final int tabId, final String mode) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
@@ -1284,16 +1293,17 @@ abstract public class GeckoApp
     }
 
     void handleContentLoaded(int tabId, String uri, String title) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
         tab.updateTitle(title);
+        tab.setHasLoaded(true);
 
         // Make the UI changes
         mMainHandler.post(new Runnable() {
             public void run() {
                 loadFavicon(tab);
 
                 if (Tabs.getInstance().isSelectedTab(tab))
                     mBrowserToolbar.setTitle(tab.getDisplayTitle());
@@ -1362,16 +1372,22 @@ abstract public class GeckoApp
                        final int w, final int h,
                        final String metadata) {
         mMainHandler.post(new Runnable() { 
             public void run() {
                 PluginLayoutParams lp;
                 JSONObject viewportObject;
                 ViewportMetrics pluginViewport;
 
+                Tabs tabs = Tabs.getInstance();
+                Tab tab = tabs.getSelectedTab();
+
+                if (tab == null)
+                    return;
+
                 ViewportMetrics targetViewport = mLayerController.getViewportMetrics();
                 
                 try {
                     viewportObject = new JSONObject(metadata);
                     pluginViewport = new ViewportMetrics(viewportObject);
                 } catch (JSONException e) {
                     Log.e(LOGTAG, "Bad viewport metadata: ", e);
                     return;
@@ -1384,62 +1400,93 @@ abstract public class GeckoApp
                     if (view instanceof SurfaceView) {
                         SurfaceView sview = (SurfaceView)view;
 
                         sview.setZOrderOnTop(false);
                         sview.setZOrderMediaOverlay(true);
                     }
 
                     mPluginContainer.addView(view, lp);
-                    mPluginViews.add(view);
+                    tab.addPluginView(view);
                 } else {
                     lp = (PluginLayoutParams)view.getLayoutParams();
                     lp.reset(x, y, w, h, pluginViewport);
                     lp.reposition(targetViewport);
                     try {
                         mPluginContainer.updateViewLayout(view, lp);
+                        view.setVisibility(View.VISIBLE);
                     } catch (IllegalArgumentException e) {
                         Log.i(LOGTAG, "e:" + e);
                         // it can be the case where we
                         // get an update before the view
                         // is actually attached.
                     }
                 }
             }
         });
     }
 
     void removePluginView(final View view) {
         mMainHandler.post(new Runnable() { 
             public void run() {
                 try {
                     mPluginContainer.removeView(view);
-                    mPluginViews.remove(view);
+
+                    Tabs tabs = Tabs.getInstance();
+                    Tab tab = tabs.getSelectedTab();
+                    if (tab == null)
+                        return;
+
+                    tab.removePluginView(view);
                 } catch (Exception e) {}
             }
         });
     }
 
     public void hidePluginViews() {
-        for (View view : mPluginViews) {
+        Tabs tabs = Tabs.getInstance();
+        Tab tab = tabs.getSelectedTab();
+
+        if (tab == null)
+            return;
+
+        hidePluginViews(tab);
+    }
+
+    public void hidePluginViews(Tab tab) {
+        for (View view : tab.getPluginViews()) {
             view.setVisibility(View.GONE);
         }
     }
 
     public void showPluginViews() {
         repositionPluginViews(true);
     }
 
+    public void showPluginViews(Tab tab) {
+        repositionPluginViews(tab, true);
+    }
+
     public void repositionPluginViews(boolean setVisible) {
+        Tabs tabs = Tabs.getInstance();
+        Tab tab = tabs.getSelectedTab();
+
+        if (tab == null)
+            return;
+
+        repositionPluginViews(tab, setVisible);
+    }
+
+    public void repositionPluginViews(Tab tab, boolean setVisible) {
         ViewportMetrics targetViewport = mLayerController.getViewportMetrics();
 
         if (targetViewport == null)
             return;
 
-        for (View view : mPluginViews) {
+        for (View view : tab.getPluginViews()) {
             PluginLayoutParams lp = (PluginLayoutParams)view.getLayoutParams();
             lp.reposition(targetViewport);
 
             if (setVisible) {
                 view.setVisibility(View.VISIBLE);
             }
 
             mPluginContainer.updateViewLayout(view, lp);
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -39,16 +39,17 @@ package org.mozilla.gecko;
 
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.View;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.db.BrowserDB;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -76,16 +77,18 @@ public final class Tab {
     private boolean mLoading;
     private boolean mBookmark;
     private HashMap<String, DoorHanger> mDoorHangers;
     private long mFaviconLoadId;
     private CheckBookmarkTask mCheckBookmarkTask;
     private String mDocumentURI;
     private String mContentType;
     private boolean mHasTouchListeners;
+    private ArrayList<View> mPluginViews;
+    private boolean mHasLoaded;
 
     public static final class HistoryEntry {
         public String mUri;         // must never be null
         public String mTitle;       // must never be null
 
         public HistoryEntry(String uri, String title) {
             mUri = uri;
             mTitle = title;
@@ -108,16 +111,18 @@ public final class Tab {
         mThumbnail = null;
         mHistory = new ArrayList<HistoryEntry>();
         mHistoryIndex = -1;
         mBookmark = false;
         mDoorHangers = new HashMap<String, DoorHanger>();
         mFaviconLoadId = 0;
         mDocumentURI = "";
         mContentType = "";
+        mPluginViews = new ArrayList<View>();
+        mHasLoaded = false;
     }
 
     public int getId() {
         return mId;
     }
 
     public int getParentId() {
         return mParentId;
@@ -428,16 +433,24 @@ public final class Tab {
 
         return null;
     }
 
     public HashMap<String, DoorHanger> getDoorHangers() {
         return mDoorHangers;
     }
 
+    public void setHasLoaded(boolean hasLoaded) {
+        mHasLoaded = hasLoaded;
+    }
+
+    public boolean hasLoaded() {
+        return mHasLoaded;
+    }
+
     void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException {
         if (event.equals("New")) {
             final String uri = message.getString("uri");
             mHistoryIndex++;
             while (mHistory.size() > mHistoryIndex) {
                 mHistory.remove(mHistoryIndex);
             }
             HistoryEntry he = new HistoryEntry(uri, "");
@@ -538,9 +551,21 @@ public final class Tab {
             return null;
         }
 
         @Override
         protected void onPostExecute(Void unused) {
             setBookmark(false);
         }
     }
+
+    public void addPluginView(View view) {
+        mPluginViews.add(view);
+    }
+
+    public void removePluginView(View view) {
+        mPluginViews.remove(view);
+    }
+
+    public View[] getPluginViews() {
+        return mPluginViews.toArray(new View[mPluginViews.size()]);
+    }
 }
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -106,16 +106,17 @@ public class Tabs implements GeckoEventL
             Log.i(LOGTAG, "Removed a tab with id: " + id);
         }
     }
 
     public Tab selectTab(int id) {
         if (!tabs.containsKey(id))
             return null;
 
+        final Tab oldTab = getSelectedTab();
         final Tab tab = tabs.get(id);
         // This avoids a NPE below, but callers need to be careful to
         // handle this case
         if (tab == null)
             return null;
 
         if (tab.getURL().equals("about:home"))
             GeckoApp.mAppContext.showAboutHome();
@@ -128,16 +129,19 @@ public class Tabs implements GeckoEventL
                 // Do we need to do this check?
                 if (isSelectedTab(tab)) {
                     GeckoApp.mBrowserToolbar.setTitle(tab.getDisplayTitle());
                     GeckoApp.mBrowserToolbar.setFavicon(tab.getFavicon());
                     GeckoApp.mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
                     GeckoApp.mBrowserToolbar.setProgressVisibility(tab.isLoading());
                     GeckoApp.mDoorHangerPopup.updatePopup();
                     GeckoApp.mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
+
+                    if (oldTab != null)
+                        GeckoApp.mAppContext.hidePluginViews(oldTab);
                 }
             }
         });
 
         // Pass a message to Gecko to update tab state in BrowserApp
         GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Selected", String.valueOf(tab.getId())));
         return selectedTab = tab;
     }
@@ -191,16 +195,17 @@ public class Tabs implements GeckoEventL
         tab.removeAllDoorHangers();
 
         final Tab closedTab = tab;
         GeckoApp.mAppContext.mMainHandler.post(new Runnable() { 
             public void run() {
                 GeckoApp.mAppContext.onTabsChanged(closedTab);
                 GeckoApp.mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
                 GeckoApp.mDoorHangerPopup.updatePopup();
+                GeckoApp.mAppContext.hidePluginViews(closedTab);
             }
         });
 
         // Pass a message to Gecko to update tab state in BrowserApp
         GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Closed", String.valueOf(tabId)));
     }
 
     /** Return the tab that will be selected by default after this one is closed */
@@ -267,24 +272,29 @@ public class Tabs implements GeckoEventL
                     event = event.substring("SessionHistory:".length());
                     tab.handleSessionHistoryMessage(event, message);
                 }
             } else if (event.equals("Tab:Added")) {
                 Log.i(LOGTAG, "Received message from Gecko: " + SystemClock.uptimeMillis() + " - Tab:Added");
                 Tab tab = addTab(message);
                 if (message.getBoolean("selected"))
                     selectTab(tab.getId());
+                if (message.getBoolean("delayLoad"))
+                    tab.setHasLoaded(false);
             } else if (event.equals("Tab:Close")) {
                 Tab tab = getTab(message.getInt("tabID"));
                 closeTab(tab);
             } else if (event.equals("Tab:Select")) {
                 selectTab(message.getInt("tabID"));
             } else if (event.equals("Tab:ScreenshotData")) {
                 Tab tab = getTab(message.getInt("tabID"));
-                byte[] compressed = Base64.decode(message.getString("data").substring(22), Base64.DEFAULT);
+                String data = message.getString("data");
+                if (data.length() < 22)
+                    return;
+                byte[] compressed = Base64.decode(data.substring(22), Base64.DEFAULT);
                 GeckoApp.mAppContext.processThumbnail(tab, null, compressed);
             }
         } catch (Exception e) { 
             Log.i(LOGTAG, "handleMessage throws " + e + " for message: " + event);
         }
     }
 
     public void refreshThumbnails() {
--- a/mobile/android/base/db/AndroidBrowserDB.java
+++ b/mobile/android/base/db/AndroidBrowserDB.java
@@ -364,16 +364,36 @@ public class AndroidBrowserDB implements
                                 values,
                                 Browser.BookmarkColumns.URL + " = ?",
                                 new String[] { uri });
 
         if (updated == 0)
             cr.insert(Browser.BOOKMARKS_URI, values);
     }
 
+    public byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
+        Cursor c = cr.query(Browser.BOOKMARKS_URI,
+                            new String[] { URL_COLUMN_THUMBNAIL },
+                            Browser.BookmarkColumns.URL + " = ?",
+                            new String[] { uri },
+                            null);
+
+        if (!c.moveToFirst()) {
+            c.close();
+            return null;
+        }
+
+        int thumbnailIndex = c.getColumnIndexOrThrow(URL_COLUMN_THUMBNAIL);
+
+        byte[] b = c.getBlob(thumbnailIndex);
+        c.close();
+
+        return b;
+    }
+
     private static class AndroidDBCursor extends CursorWrapper {
         public AndroidDBCursor(Cursor c) {
             super(c);
         }
 
         private String translateColumnName(String columnName) {
             if (columnName.equals(BrowserDB.URLColumns.URL)) {
                 columnName = Browser.BookmarkColumns.URL;
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -83,16 +83,18 @@ public class BrowserDB {
 
         public void removeBookmark(ContentResolver cr, String uri);
 
         public BitmapDrawable getFaviconForUrl(ContentResolver cr, String uri);
 
         public void updateFaviconForUrl(ContentResolver cr, String uri, BitmapDrawable favicon);
 
         public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
+
+        public byte[] getThumbnailForUrl(ContentResolver cr, String uri);
     }
 
     static {
         // Forcing local DB no option to switch to Android DB for now
         sDb = new LocalBrowserDB(BrowserContract.DEFAULT_PROFILE);
     }
 
     public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
@@ -154,9 +156,13 @@ public class BrowserDB {
 
     public static void updateFaviconForUrl(ContentResolver cr, String uri, BitmapDrawable favicon) {
         sDb.updateFaviconForUrl(cr, uri, favicon);
     }
 
     public static void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail) {
         sDb.updateThumbnailForUrl(cr, uri, thumbnail);
     }
+
+    public static byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
+        return sDb.getThumbnailForUrl(cr, uri);
+    }
 }
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -407,16 +407,36 @@ public class LocalBrowserDB implements B
                                 values,
                                 Images.URL + " = ?",
                                 new String[] { uri });
 
         if (updated == 0)
             cr.insert(appendProfile(Images.CONTENT_URI), values);
     }
 
+    public byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
+        Cursor c = cr.query(appendProfile(Images.CONTENT_URI),
+                            new String[] { Images.THUMBNAIL },
+                            Images.URL + " = ?",
+                            new String[] { uri },
+                            null);
+
+        if (!c.moveToFirst()) {
+            c.close();
+            return null;
+        }
+
+        int thumbnailIndex = c.getColumnIndexOrThrow(Images.THUMBNAIL);
+
+        byte[] b = c.getBlob(thumbnailIndex);
+        c.close();
+
+        return b;
+    }
+
     private static class LocalDBCursor extends CursorWrapper {
         public LocalDBCursor(Cursor c) {
             super(c);
         }
 
         private String translateColumnName(String columnName) {
             if (columnName.equals(BrowserDB.URLColumns.URL)) {
                 columnName = URLColumns.URL;
--- a/mobile/android/base/resources/layout/awesomebar_search.xml
+++ b/mobile/android/base/resources/layout/awesomebar_search.xml
@@ -15,17 +15,17 @@
           android:inputType="textUri|textNoSuggestions"
           android:imeOptions="actionSearch"
           android:singleLine="true"
           android:gravity="center_vertical|left">
               <requestFocus/>
     </view>
 
     <LinearLayout android:layout_width="4dp"
-                  android:layout_height="match_parent"
+                  android:layout_height="fill_parent"
                   android:orientation="vertical"
                   android:layout_alignParentRight="true"/>
 
     <ImageButton android:id="@+id/awesomebar_button"
                  style="@style/AddressBar.ImageButton"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_marginRight="15dip"
--- a/mobile/android/base/resources/layout/awesomebar_tabs.xml
+++ b/mobile/android/base/resources/layout/awesomebar_tabs.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <org.mozilla.gecko.AwesomeBarTabs xmlns:android="http://schemas.android.com/apk/res/android"
                                   android:id="@+id/awesomebar_tabs"
-                                  android:layout_width="match_parent"
+                                  android:layout_width="fill_parent"
                                   android:layout_height="wrap_content">
 
     <LinearLayout android:orientation="vertical"
                   android:layout_width="fill_parent"
                   android:layout_height="fill_parent">
 
         <TabWidget android:id="@android:id/tabs"
                    style="@style/TabWidget"/>
--- a/mobile/android/base/resources/layout/doorhanger.xml
+++ b/mobile/android/base/resources/layout/doorhanger.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <TextView android:id="@+id/doorhanger_title"
-              android:layout_width="match_parent"
+              android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:textAppearance="?android:attr/textAppearanceMedium"
               android:textColor="?android:attr/textColorPrimary"
               android:padding="10dp"/>
 
     <LinearLayout android:id="@+id/doorhanger_choices"
                   style="@android:style/ButtonBar"
-                  android:layout_width="match_parent"
+                  android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="horizontal"/>
 
 </merge>
--- a/mobile/android/base/resources/layout/doorhangerpopup.xml
+++ b/mobile/android/base/resources/layout/doorhangerpopup.xml
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
+                android:layout_width="fill_parent"
                 android:layout_height="wrap_content">
 
-    <ScrollView android:layout_width="match_parent"
+    <ScrollView android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="24dip"
                 android:layout_alignParentTop="true">
 
         <LinearLayout android:id="@+id/doorhanger_container"
-                      android:layout_width="match_parent"
+                      android:layout_width="fill_parent"
                       android:layout_height="wrap_content"
                       android:orientation="vertical"
                       android:background="@drawable/doorhanger_popup_bg"/>
 
     </ScrollView>
 
     <ImageView android:layout_width="43dip"
                android:layout_height="15dip"
--- a/mobile/android/base/resources/layout/launch_app_listitem.xml
+++ b/mobile/android/base/resources/layout/launch_app_listitem.xml
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
+              android:layout_width="fill_parent"
               android:layout_height="?android:attr/listPreferredItemHeight"
               android:paddingLeft="16dip"
               android:paddingRight="16dip"
               android:orientation="horizontal"
               android:gravity="left">
   
    <ImageView android:id="@+id/favicon"
               android:layout_width="48dip"
               android:layout_height="48dip"
               android:layout_marginRight="12dip"
               android:layout_gravity="center_vertical"
               android:adjustViewBounds="true"
               android:scaleType="fitCenter"/>
 
    <TextView android:id="@+id/title"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
+             android:layout_width="fill_parent"
+             android:layout_height="fill_parent"
              android:gravity="center_vertical"
              android:textAppearance="?android:attr/textAppearanceLargeInverse"
              android:ellipsize="marquee"
              android:fadingEdge="horizontal"/>
 
  </LinearLayout>
--- a/mobile/android/base/resources/layout/select_dialog_list.xml
+++ b/mobile/android/base/resources/layout/select_dialog_list.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This is used for select lists for multiple selection enabled -->
 <view xmlns:android="http://schemas.android.com/apk/res/android"
       class="android.widget.ListView"
       android:id="@+id/select_list"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"
+      android:layout_width="fill_parent"
+      android:layout_height="fill_parent"
       android:cacheColorHint="@null"
       android:scrollbars="vertical"
       android:overScrollMode="ifContentScrolls" />
--- a/mobile/android/base/resources/layout/site_setting_title.xml
+++ b/mobile/android/base/resources/layout/site_setting_title.xml
@@ -1,28 +1,28 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
+              android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:layout_weight="1"
               android:orientation="vertical"
               android:gravity="center_vertical">
 
     <TextView android:id="@+id/title"
               style="?android:attr/windowTitleStyle"
               android:textAppearance="?android:attr/textAppearanceLarge"
-              android:layout_width="match_parent" 
+              android:layout_width="fill_parent" 
               android:layout_height="wrap_content"
               android:paddingTop="6dip"
               android:paddingBottom="0dip"
               android:paddingLeft="10dip"
               android:paddingRight="10dip"/>
 
     <TextView android:id="@+id/host"
               style="?android:attr/windowTitleStyle"
               android:textAppearance="?android:attr/textAppearanceMedium"
-              android:layout_width="match_parent" 
+              android:layout_width="fill_parent" 
               android:layout_height="wrap_content"
               android:paddingTop="2dip"
               android:paddingBottom="6dip"
               android:paddingLeft="10dip"
               android:paddingRight="10dip"/>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/tabs_tray.xml
+++ b/mobile/android/base/resources/layout/tabs_tray.xml
@@ -1,31 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:id="@+id/container"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
               android:orientation="vertical">
 
      <view class="org.mozilla.gecko.TabsTray$TabsListContainer"
-           android:layout_width="match_parent"
+           android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:background="@drawable/tabs_tray_bg_repeat">
 
          <ListView android:id="@+id/list"
                    style="@style/TabsList"
                    android:divider="@drawable/tabs_tray_list_divider"/>
 
-         <LinearLayout android:layout_width="match_parent"
+         <LinearLayout android:layout_width="fill_parent"
                        android:layout_height="2dp"
                        android:background="@drawable/tabs_tray_list_divider"/>
 
          <LinearLayout android:id="@+id/add_tab"
-                       android:layout_width="match_parent"
+                       android:layout_width="fill_parent"
                        android:layout_height="50dip"
                        android:orientation="horizontal"
                        android:gravity="center|left"
                        android:background="@drawable/tabs_tray_list_selector">
 
              <ImageView android:layout_width="20dip"
                         android:layout_height="20dip"
                         android:layout_marginLeft="20dip"
--- a/mobile/android/base/resources/values-v11/styles.xml
+++ b/mobile/android/base/resources/values-v11/styles.xml
@@ -3,28 +3,28 @@
     
     <!--
         Only overriden styles for Honeycomb/Ice cream sandwich are specified here.
         Please refer to values/styles.xml for default styles.
     -->
 
     <!-- BrowserToolbar -->
     <style name="BrowserToolbar">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
+        <item name="android:layout_height">fill_parent</item>
         <item name="android:orientation">vertical</item>
     </style>
 
     <!-- Address bar -->
     <style name="AddressBar">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
+        <item name="android:layout_height">fill_parent</item>
         <item name="android:orientation">horizontal</item>
     </style>
 
     <!-- Lists in AwesomeBar -->
     <style name="AwesomeBarList" parent="android:style/Widget.Holo.ListView">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">fill_parent</item>
         <item name="android:layout_weight">1</item>
     </style>
 
 </resources>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
     <!-- Layout -->
     <style name="Layout">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
+        <item name="android:layout_height">fill_parent</item>
     </style>
 
     <!-- Horizontal Layout -->
     <style name="Layout.Horizontal">
         <item name="android:orientation">horizontal</item>
     </style>
 
     <!-- Vertical Layout -->
@@ -24,56 +24,56 @@
 
     <!-- Transparent Screen -->
     <style name="Screen.Transparent">
         <item name="android:background">#00000000</item>
     </style>
 
     <!-- BrowserToolbar -->
     <style name="BrowserToolbar">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:orientation">vertical</item>
         <item name="android:background">#000000</item>
     </style>
 
     <!-- Address bar -->
     <style name="AddressBar">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">42dip</item>
         <item name="android:orientation">horizontal</item>
     </style>
 
     <!-- Address bar - Button -->
     <style name="AddressBar.Button">
-        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_height">fill_parent</item>
         <item name="android:textSize">16sp</item>
         <item name="android:background">@android:color/transparent</item>
     </style>
 
     <!-- Address bar - Image Button -->
     <style name="AddressBar.ImageButton" parent="AddressBar.Button">
         <item name="android:scaleType">fitCenter</item>
         <item name="android:background">@android:color/transparent</item>
     </style>
 
     <!-- Lists in AwesomeBar -->
     <style name="AwesomeBarList" parent="android:style/Widget.ListView.White">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">fill_parent</item>
         <item name="android:layout_weight">1</item>
     </style>
 
     <!-- Lists in TabsTray -->
     <style name="TabsList" parent="android:style/Widget.ListView">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">fill_parent</item>
         <item name="android:layout_weight">1</item>
     </style>
 
     <!-- TabWidget --> 
     <style name="TabWidget">
-        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">48dip</item>
         <item name="android:background">@drawable/tabs_tray_bg_repeat</item>
     </style>
 
 </resources>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -376,20 +376,24 @@ var BrowserApp = {
     return this._tabs;
   },
 
   get selectedTab() {
     return this._selectedTab;
   },
 
   set selectedTab(aTab) {
+    if (this._selectedTab)
+      this._selectedTab.setActive(false);
+
     this._selectedTab = aTab;
     if (!aTab)
       return;
 
+    aTab.setActive(true);
     aTab.updateViewport(false);
     this.deck.selectedPanel = aTab.vbox;
   },
 
   get selectedBrowser() {
     if (this._selectedTab)
       return this._selectedTab.browser;
     return null;
@@ -469,17 +473,19 @@ var BrowserApp = {
   },
 
   addTab: function addTab(aURI, aParams) {
     aParams = aParams || {};
 
     let newTab = new Tab(aURI, aParams);
     this._tabs.push(newTab);
 
-    newTab.active = "selected" in aParams ? aParams.selected : true;
+    let selected = "selected" in aParams ? aParams.selected : true;
+    if (selected)
+      this.selectedTab = newTab;
 
     let evt = document.createEvent("UIEvents");
     evt.initUIEvent("TabOpen", true, false, window, null);
     newTab.browser.dispatchEvent(evt);
 
     return newTab;
   },
 
@@ -561,22 +567,21 @@ var BrowserApp = {
       }
     };
     sendMessageToJava(message);
   },
 
   // This method updates the state in BrowserApp after a tab has been selected
   // in the Java UI.
   _handleTabSelected: function _handleTabSelected(aTab) {
-      this.selectedTab = aTab;
-      aTab.active = true;
-
-      let evt = document.createEvent("UIEvents");
-      evt.initUIEvent("TabSelect", true, false, window, null);
-      aTab.browser.dispatchEvent(evt);
+    this.selectedTab = aTab;
+
+    let evt = document.createEvent("UIEvents");
+    evt.initUIEvent("TabSelect", true, false, window, null);
+    aTab.browser.dispatchEvent(evt);
 
     let message = {
       gecko: {
         type: "Tab:Selected:Done",
         tabID: aTab.id
       }
     };
     sendMessageToJava(message);
@@ -1414,17 +1419,17 @@ Tab.prototype = {
 
     aParams = aParams || {};
 
     this.vbox = document.createElement("vbox");
     this.vbox.align = "start";
     BrowserApp.deck.appendChild(this.vbox);
 
     this.browser = document.createElement("browser");
-    this.browser.setAttribute("type", "content");
+    this.browser.setAttribute("type", "content-targetable");
     this.setBrowserSize(980, 480);
     this.browser.style.MozTransformOrigin = "0 0";
     this.vbox.appendChild(this.browser);
 
     this.browser.stop();
 
     // Turn off clipping so we can buffer areas outside of the browser element.
     let frameLoader = this.browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
@@ -1435,17 +1440,18 @@ Tab.prototype = {
     let message = {
       gecko: {
         type: "Tab:Added",
         tabID: this.id,
         uri: aURL,
         parentId: ("parentId" in aParams) ? aParams.parentId : -1,
         external: ("external" in aParams) ? aParams.external : false,
         selected: ("selected" in aParams) ? aParams.selected : true,
-        title: aParams.title || ""
+        title: aParams.title || "",
+        delayLoad: aParams.delayLoad || false
       }
     };
     sendMessageToJava(message);
 
     let flags = Ci.nsIWebProgress.NOTIFY_STATE_ALL |
                 Ci.nsIWebProgress.NOTIFY_LOCATION |
                 Ci.nsIWebProgress.NOTIFY_SECURITY;
     this.browser.addProgressListener(this, flags);
@@ -1508,35 +1514,31 @@ Tab.prototype = {
     BrowserApp.deck.removeChild(this.vbox);
     BrowserApp.deck.selectedPanel = selectedPanel;
 
     this.browser = null;
     this.vbox = null;
     this.documentIdForCurrentViewport = null;
   },
 
-  set active(aActive) {
+  // This should be called to update the browser when the tab gets selected/unselected
+  setActive: function setActive(aActive) {
     if (!this.browser)
       return;
 
     if (aActive) {
       this.browser.setAttribute("type", "content-primary");
       this.browser.focus();
-      BrowserApp.selectedTab = this;
+      this.browser.docShellIsActive = true;
     } else {
-      this.browser.setAttribute("type", "content");
+      this.browser.setAttribute("type", "content-targetable");
+      this.browser.docShellIsActive = false;
     }
   },
 
-  get active() {
-    if (!this.browser)
-      return false;
-    return this.browser.getAttribute("type") == "content-primary";
-  },
-
   set viewport(aViewport) {
     // Transform coordinates based on zoom
     aViewport.x /= aViewport.zoom;
     aViewport.y /= aViewport.zoom;
 
     // Set scroll position
     let win = this.browser.contentWindow;
     win.scrollTo(aViewport.x, aViewport.y);
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -14,16 +14,17 @@
  * The Original Code is Session Store.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mark 'evil' Finkle <mfinkle@mozilla.com>
+ *   Brian Nicholson <bnicholson@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -452,17 +453,17 @@ SessionStore.prototype = {
     let browsers = aWindow.document.getElementById("browsers");
     let index = browsers.selectedIndex;
     this._windows[aWindow.__SSID].selected = parseInt(index) + 1; // 1-based
 
     // Restore the resurrected browser
     if (aBrowser.__SS_restore) {
       let data = aBrowser.__SS_data;
       if (data.entries.length > 0)
-        aBrowser.loadURI(data.entries[data.index - 1].url);
+        this._restoreHistory(data, aBrowser.sessionHistory);
 
       delete aBrowser.__SS_restore;
     }
 
     this.saveStateDelayed();
     this._updateCrashReportURL(aWindow);
   },
 
@@ -972,31 +973,32 @@ SessionStore.prototype = {
 
         let tabs = data.windows[0].tabs;
         let selected = data.windows[0].selected;
         if (selected > tabs.length) // Clamp the selected index if it's bogus
           selected = 1;
 
         for (let i=0; i<tabs.length; i++) {
           let tabData = tabs[i];
-          let isSelected = (i + 1 <= selected) && aBringToFront;
+          let isSelected = (i + 1 == selected) && aBringToFront;
           let entry = tabData.entries[tabData.index - 1];
 
           // Add a tab, but don't load the URL until we need to
-          let params = { selected: isSelected, delayLoad: !isSelected, title: entry.title };
+          let params = { selected: isSelected, delayLoad: true, title: entry.title };
           let tab = window.BrowserApp.addTab(entry.url, params);
 
-          if (!isSelected) {
+          if (isSelected) {
+            self._restoreHistory(tabData, tab.browser.sessionHistory);
+          } else {
             // Make sure the browser has its session data for the delay reload
             tab.browser.__SS_data = tabData;
             tab.browser.__SS_restore = true;
           }
 
           tab.browser.__SS_extdata = tabData.extData;
-          self._restoreHistory(tabData, tab.browser.sessionHistory);
         }
 
         notifyObservers();
       });
     } catch (ex) {
       Cu.reportError("SessionStore: Could not read from sessionstore.bak file: " + ex);
       notifyObservers("fail");
     }
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/device/GonkCaptureProvider.cpp
@@ -0,0 +1,563 @@
+/* -*- Mode: C++; tab-width: 8; 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 "base/basictypes.h"
+#include "GonkCaptureProvider.h"
+#include "nsXULAppAPI.h"
+#include "nsStreamUtils.h"
+#include "nsThreadUtils.h"
+#include "nsRawStructs.h"
+
+#define USE_GS2_LIBCAMERA
+#define CameraHardwareInterface CameraHardwareInterface_SGS2
+#define HAL_openCameraHardware HAL_openCameraHardware_SGS2
+#include "camera/CameraHardwareInterface.h"
+#undef CameraHardwareInterface
+#undef USE_GS2_LIBCAMERA
+#undef HAL_openCameraHardware
+#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+// Needed to prevent a redefinition of 'struct android::image_rect_struct'...
+#define image_rect_type image_rect_type2
+#define image_rect_struct image_rect_struct2
+
+#define USE_MAGURO_LIBCAMERA
+#define CameraHardwareInterface CameraHardwareInterface_MAGURO
+#define HAL_openCameraHardware HAL_openCameraHardware_MAGURO
+#include "camera/CameraHardwareInterface.h"
+#undef CameraHardwareInterface
+#undef USE_MAGURO_LIBCAMERA
+#undef HAL_openCameraHardware
+#undef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#undef image_rect_type
+#undef image_rect_struct
+
+#define image_rect_type image_rect_type3
+#define image_rect_struct image_rect_struct3
+#define CameraHardwareInterface CameraHardwareInterface_DEFAULT
+#include "camera/CameraHardwareInterface.h"
+#undef CameraHardwareInterface
+
+
+#include <dlfcn.h>
+#include "cutils/properties.h"
+
+using namespace android;
+using namespace mozilla;
+
+class CameraHardwareInterface {
+  public:
+    typedef enum {
+      CAMERA_SGS2,
+      CAMERA_MAGURO,
+      CAMERA_DEFAULT
+    } Type;
+
+    static Type getType() {
+      char propValue[PROPERTY_VALUE_MAX];
+      property_get("ro.product.board", propValue, NULL);
+      if (!strcmp(propValue, "GT-I9100"))
+        return CAMERA_SGS2;
+
+      if (!strcmp(propValue, "MSM7627A_SKU1"))
+        return CAMERA_MAGURO;
+
+      printf_stderr("CameraHardwareInterface : unsupported camera for device %s\n", propValue);
+      return CAMERA_DEFAULT;
+    }
+
+    static CameraHardwareInterface* openCamera(PRUint32 aCamera);
+    
+    virtual ~CameraHardwareInterface() { };
+    
+    virtual bool ok();
+    virtual void enableMsgType(int32_t msgType);
+    virtual void disableMsgType(int32_t msgType);
+    virtual bool msgTypeEnabled(int32_t msgType);
+    virtual void setCallbacks(notify_callback notify_cb,
+                              data_callback data_cb,
+                              data_callback_timestamp data_cb_timestamp,
+                              void* user);
+    virtual status_t startPreview();
+    virtual void stopPreview();
+    virtual void release();
+    virtual status_t setParameters(const CameraParameters& params);
+    virtual CameraParameters getParameters() const;
+
+  protected:
+    CameraHardwareInterface(PRUint32 aCamera = 0) { };
+};
+
+class DlopenWrapper {
+  public:
+    DlopenWrapper() : mHandle(nsnull) { };
+
+    DlopenWrapper(const char* aLibrary) : mHandle(nsnull) {
+      mHandle = dlopen(aLibrary, RTLD_LAZY);
+    };
+
+    ~DlopenWrapper() {
+      if (mHandle)
+        dlclose(mHandle);
+    };
+
+    bool opened() {
+      return mHandle != nsnull;
+    };
+    
+    void* dlsym(const char* aFunction) {
+      return ::dlsym(mHandle, aFunction);
+    };
+
+  protected:
+    void* mHandle;
+};
+
+template<class T> class CameraImpl : public CameraHardwareInterface {
+  public:
+    typedef sp<T> (*HAL_openCameraHardware_DEFAULT)(int);
+    typedef sp<T> (*HAL_openCameraHardware_SGS2)(int);
+    typedef sp<T> (*HAL_openCameraHardware_MAGURO)(int, int);
+    
+    CameraImpl(PRUint32 aCamera = 0) : mOk(false), mCamera(nsnull) {
+      DlopenWrapper wrapper("system/lib/libcamera.so");
+
+      if (!wrapper.opened())
+        return;
+
+      mOk = true;
+
+      void *hal = wrapper.dlsym("HAL_openCameraHardware");
+      HAL_openCameraHardware_DEFAULT funct0;
+      HAL_openCameraHardware_SGS2 funct1;
+      HAL_openCameraHardware_MAGURO funct2;
+      switch(getType()) {
+        case CAMERA_SGS2:
+          funct1 = reinterpret_cast<HAL_openCameraHardware_SGS2> (hal);       
+          mCamera = funct1(aCamera);
+          break;
+        case CAMERA_MAGURO:
+          funct2 = reinterpret_cast<HAL_openCameraHardware_MAGURO> (hal);  
+          mCamera = funct2(aCamera, 1);
+          break;
+        case CAMERA_DEFAULT:
+          funct0 = reinterpret_cast<HAL_openCameraHardware_DEFAULT> (hal);  
+          mCamera = funct0(aCamera);
+          break;
+      }
+    }
+
+    bool ok() {
+      return mOk;
+    };
+
+    void enableMsgType(int32_t msgType) {
+      mCamera->enableMsgType(msgType);
+    };
+
+    void disableMsgType(int32_t msgType) {
+      mCamera->disableMsgType(msgType);
+    };
+
+    bool msgTypeEnabled(int32_t msgType) {
+      return mCamera->msgTypeEnabled(msgType); 
+    };
+
+    void setCallbacks(notify_callback notify_cb,
+                              data_callback data_cb,
+                              data_callback_timestamp data_cb_timestamp,
+                              void* user) {
+      mCamera->setCallbacks(notify_cb, data_cb, data_cb_timestamp, user);                          
+    };
+
+    status_t startPreview() {
+      return mCamera->startPreview();
+    };
+
+    void stopPreview() {
+      mCamera->stopPreview();
+    };
+
+    void release() {
+      return mCamera->release();
+    };
+
+    status_t setParameters(const CameraParameters& params) {
+      return mCamera->setParameters(params);
+    }
+
+    CameraParameters getParameters() const {
+      return mCamera->getParameters();
+    };
+  protected:
+    bool mOk;
+    sp<T> mCamera;  
+};
+
+CameraHardwareInterface* CameraHardwareInterface::openCamera(PRUint32 aCamera)  {
+  nsAutoPtr<CameraHardwareInterface> instance;
+  switch(getType()) {
+    case CAMERA_SGS2:
+      instance = new CameraImpl<CameraHardwareInterface_SGS2>(aCamera);
+      break;
+    case CAMERA_MAGURO:
+      instance = new CameraImpl<CameraHardwareInterface_MAGURO>(aCamera);
+      break;
+    case CAMERA_DEFAULT:
+      instance = new CameraImpl<CameraHardwareInterface_DEFAULT>(aCamera);
+      break;
+  }
+
+  if (!instance->ok()) {
+    return nsnull;
+  }
+
+  return instance.forget();
+};
+
+
+// The maximum number of frames we keep in our queue. Don't live in the past.
+#define MAX_FRAMES_QUEUED 5
+
+NS_IMPL_THREADSAFE_ISUPPORTS2(GonkCameraInputStream, nsIInputStream, nsIAsyncInputStream)
+
+GonkCameraInputStream::GonkCameraInputStream() :
+  mAvailable(sizeof(nsRawVideoHeader)), mWidth(0), mHeight(0), mFps(30), mCamera(0), 
+  mHeaderSent(false), mClosed(true), mIs420p(false), mFrameSize(0), mMonitor("GonkCamera.Monitor")
+{
+
+}
+
+GonkCameraInputStream::~GonkCameraInputStream() {
+  // clear the frame queue
+  while (mFrameQueue.GetSize() > 0) {
+    free(mFrameQueue.PopFront());
+  }
+
+  // no need to close Close() since the stream is opened here :
+  // http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#239
+  // and this leads to http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsBaseChannel.cpp#259
+  // that creates and input pump with closeWhenDone == true
+  // the pump cleans up properly at http://mxr.mozilla.org/mozilla-central/source/netwerk/base/src/nsInputStreamPump.cpp#565
+}
+
+void
+GonkCameraInputStream::DataCallback(int32_t aMsgType, const sp<IMemory>& aDataPtr, void *aUser) {
+  GonkCameraInputStream* stream = (GonkCameraInputStream*)(aUser);
+  stream->ReceiveFrame((char*)aDataPtr->pointer(), aDataPtr->size());
+}
+
+NS_IMETHODIMP
+GonkCameraInputStream::Init(nsACString& aContentType, nsCaptureParams* aParams)
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default)
+    return NS_ERROR_NOT_IMPLEMENTED;
+
+  mContentType = aContentType;
+  mWidth = aParams->width;
+  mHeight = aParams->height;
+  mCamera = aParams->camera;
+ 
+  PRUint32 maxCameras = HAL_getNumberOfCameras();
+
+  if (mCamera >= maxCameras)
+    mCamera = maxCameras - 1;
+
+  mHardware = CameraHardwareInterface::openCamera(mCamera);
+
+  if (!mHardware)
+    return NS_ERROR_FAILURE;
+
+  mHardware->setCallbacks(NULL, GonkCameraInputStream::DataCallback, NULL, this);
+  mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+
+  CameraParameters params = mHardware->getParameters();
+
+  printf_stderr("Preview format : %s\n", params.get(params.KEY_SUPPORTED_PREVIEW_FORMATS));
+
+  Vector<Size> previewSizes;
+  params.getSupportedPreviewSizes(previewSizes);
+
+  // find the available preview size closest to the requested size.
+  PRUint32 minSizeDelta = PR_UINT32_MAX;
+  PRUint32 bestWidth = mWidth;
+  PRUint32 bestHeight = mHeight;
+  for (PRUint32 i = 0; i < previewSizes.size(); i++) {
+    Size size = previewSizes[i];
+    PRUint32 delta = abs(size.width * size.height - mWidth * mHeight); 
+    if (delta < minSizeDelta) {
+      minSizeDelta = delta;
+      bestWidth = size.width;
+      bestHeight = size.height;
+    }
+  }
+  mWidth = bestWidth;
+  mHeight = bestHeight;
+  params.setPreviewSize(mWidth, mHeight);
+
+  // try to set preferred image format
+  params.setPreviewFormat("yuv420p");
+
+  params.setPreviewFrameRate(mFps);
+  mHardware->setParameters(params);
+  params = mHardware->getParameters();
+  mFps = params.getPreviewFrameRate();
+
+  mIs420p = !strcmp(params.getPreviewFormat(), "yuv420p");
+
+  mHardware->startPreview();
+
+  mClosed = false;
+  return NS_OK;
+}
+
+
+void 
+GonkCameraInputStream::ReceiveFrame(char* frame, PRUint32 length) {
+  {
+    ReentrantMonitorAutoEnter enter(mMonitor);
+    if (mFrameQueue.GetSize() > MAX_FRAMES_QUEUED) {
+      free(mFrameQueue.PopFront());
+      mAvailable -= mFrameSize;
+    }
+  }
+
+  mFrameSize = sizeof(nsRawPacketHeader) + length;
+
+  char* fullFrame = (char*)moz_malloc(mFrameSize);
+
+  if (!fullFrame)
+    return;
+
+  nsRawPacketHeader* header = reinterpret_cast<nsRawPacketHeader*> (fullFrame);
+  header->packetID = 0xFF;
+  header->codecID = RAW_ID;
+
+  if (mIs420p) {
+    memcpy(fullFrame + sizeof(nsRawPacketHeader), frame, length);
+  } else {
+    // we copy the Y plane, and de-interlace the CrCb
+    PRUint32 yFrameSize = mWidth * mHeight;
+    PRUint32 uvFrameSize = yFrameSize / 4;
+    memcpy(fullFrame + sizeof(nsRawPacketHeader), frame, yFrameSize);
+
+    char* uFrame = fullFrame + sizeof(nsRawPacketHeader) + yFrameSize;
+    char* vFrame = fullFrame + sizeof(nsRawPacketHeader) + yFrameSize + uvFrameSize;
+    const char* yFrame = frame + yFrameSize;
+    for (PRUint32 i = 0; i < uvFrameSize; i++) {
+      uFrame[i] = yFrame[2 * i + 1];
+      vFrame[i] = yFrame[2 * i];
+    }
+  }
+  
+
+  {
+    ReentrantMonitorAutoEnter enter(mMonitor);
+    mAvailable += mFrameSize;
+    mFrameQueue.Push((void*)fullFrame);
+  }
+
+  NotifyListeners();
+}
+
+NS_IMETHODIMP
+GonkCameraInputStream::Available(PRUint32 *aAvailable)
+{
+  ReentrantMonitorAutoEnter enter(mMonitor);
+
+  *aAvailable = mAvailable;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP GonkCameraInputStream::IsNonBlocking(bool *aNonBlock) {
+  *aNonBlock = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP GonkCameraInputStream::Read(char *aBuffer, PRUint32 aCount, PRUint32 *aRead NS_OUTPARAM) {
+  return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aRead);
+}
+
+NS_IMETHODIMP GonkCameraInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, PRUint32 aCount, PRUint32 *aRead NS_OUTPARAM) {
+  *aRead = 0;
+  
+  nsresult rv;
+
+  if (mAvailable == 0)
+    return NS_BASE_STREAM_WOULD_BLOCK;
+  
+  if (aCount > mAvailable)
+    aCount = mAvailable;
+
+  if (!mHeaderSent) {
+    nsRawVideoHeader header;
+    header.headerPacketID = 0;
+    header.codecID = RAW_ID;
+    header.majorVersion = 0;
+    header.minorVersion = 1;
+    header.options = 1 | 1 << 1; // color, 4:2:0
+
+    header.alphaChannelBpp = 0;
+    header.lumaChannelBpp = 8;
+    header.chromaChannelBpp = 4;
+    header.colorspace = 1;
+
+    header.frameWidth = mWidth;
+    header.frameHeight = mHeight;
+    header.aspectNumerator = 1;
+    header.aspectDenominator = 1;
+
+    header.framerateNumerator = mFps;
+    header.framerateDenominator = 1;
+
+    rv = aWriter(this, aClosure, (const char*)&header, 0, sizeof(nsRawVideoHeader), aRead);
+   
+    if (NS_FAILED(rv))
+      return NS_OK;
+    
+    mHeaderSent = true;
+    aCount -= sizeof(nsRawVideoHeader);
+    mAvailable -= sizeof(nsRawVideoHeader);
+  }
+  
+  {
+    ReentrantMonitorAutoEnter enter(mMonitor);
+    while ((mAvailable > 0) && (aCount >= mFrameSize)) {
+      PRUint32 readThisTime = 0;
+
+      char* frame = (char*)mFrameQueue.PopFront();
+      rv = aWriter(this, aClosure, (const char*)frame, *aRead, mFrameSize, &readThisTime);
+
+      if (readThisTime != mFrameSize) {
+        mFrameQueue.PushFront((void*)frame);
+        return NS_OK;
+      }
+
+      // nsRawReader does a copy when calling VideoData::Create()
+      free(frame);
+
+      if (NS_FAILED(rv))
+        return NS_OK;
+
+      aCount -= readThisTime;
+      mAvailable -= readThisTime;
+      *aRead += readThisTime;
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP GonkCameraInputStream::Close() {
+  return CloseWithStatus(NS_OK);
+}
+
+void GonkCameraInputStream::doClose() {
+  ReentrantMonitorAutoEnter enter(mMonitor);
+
+  if (mClosed)
+    return;
+
+  mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
+  mHardware->stopPreview();
+  mHardware->release();
+  delete mHardware;
+
+  mClosed = true;
+}
+
+
+void GonkCameraInputStream::NotifyListeners() {
+  ReentrantMonitorAutoEnter enter(mMonitor);
+  
+  if (mCallback && (mAvailable > sizeof(nsRawVideoHeader))) {
+    nsCOMPtr<nsIInputStreamCallback> callback;
+    if (mCallbackTarget) {
+      NS_NewInputStreamReadyEvent(getter_AddRefs(callback), mCallback, mCallbackTarget);
+    } else {
+      callback = mCallback;
+    }
+
+    NS_ASSERTION(callback, "Shouldn't fail to make the callback!");
+
+    // Null the callback first because OnInputStreamReady may reenter AsyncWait
+    mCallback = nsnull;
+    mCallbackTarget = nsnull;
+
+    callback->OnInputStreamReady(this);
+  }
+}
+
+NS_IMETHODIMP GonkCameraInputStream::AsyncWait(nsIInputStreamCallback *aCallback, PRUint32 aFlags, PRUint32 aRequestedCount, nsIEventTarget *aTarget)
+{
+  if (aFlags != 0)
+    return NS_ERROR_NOT_IMPLEMENTED;
+
+  if (mCallback || mCallbackTarget)
+    return NS_ERROR_UNEXPECTED;
+
+  mCallbackTarget = aTarget;
+  mCallback = aCallback;
+
+  // What we are being asked for may be present already
+  NotifyListeners();
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP GonkCameraInputStream::CloseWithStatus(PRUint32 status)
+{
+  GonkCameraInputStream::doClose();
+  return NS_OK;
+}
+
+/**
+ * GonkCaptureProvider implementation
+ */
+NS_IMPL_ISUPPORTS0(GonkCaptureProvider)
+
+GonkCaptureProvider* GonkCaptureProvider::sInstance = NULL;
+
+GonkCaptureProvider::GonkCaptureProvider() {
+}
+
+GonkCaptureProvider::~GonkCaptureProvider() {
+  GonkCaptureProvider::sInstance = NULL;
+}
+
+nsresult GonkCaptureProvider::Init(nsACString& aContentType,
+                        nsCaptureParams* aParams,
+                        nsIInputStream** aStream) {
+
+  NS_ENSURE_ARG_POINTER(aParams);
+
+  NS_ASSERTION(aParams->frameLimit == 0 || aParams->timeLimit == 0,
+    "Cannot set both a frame limit and a time limit!");
+
+  nsRefPtr<GonkCameraInputStream> stream;
+
+  if (aContentType.EqualsLiteral("video/x-raw-yuv")) {
+    stream = new GonkCameraInputStream();
+    if (stream) {
+      nsresult rv = stream->Init(aContentType, aParams);
+      if (NS_FAILED(rv))
+        return rv;
+    }
+    else {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+  } else {
+    NS_NOTREACHED("Should not have asked Gonk for this type!");
+  }
+  return CallQueryInterface(stream, aStream);
+}
+
+already_AddRefed<GonkCaptureProvider> GetGonkCaptureProvider() {
+  if (!GonkCaptureProvider::sInstance) {
+    GonkCaptureProvider::sInstance = new GonkCaptureProvider();
+  }
+  GonkCaptureProvider::sInstance->AddRef();
+  return GonkCaptureProvider::sInstance;
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/device/GonkCaptureProvider.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
+
+#ifndef GonkDeviceCaptureProvider_h_
+#define GonkDeviceCaptureProvider_h_
+
+#include "nsDeviceCaptureProvider.h"
+#include "nsIAsyncInputStream.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsString.h"
+#include "nsIEventTarget.h"
+#include "nsDeque.h"
+#include "mozilla/ReentrantMonitor.h"
+
+#include "binder/IMemory.h"
+
+using namespace android;
+
+class CameraHardwareInterface;
+
+class GonkCaptureProvider : public nsDeviceCaptureProvider {
+  public:
+    GonkCaptureProvider();
+    ~GonkCaptureProvider();
+
+    NS_DECL_ISUPPORTS
+
+    nsresult Init(nsACString& aContentType, nsCaptureParams* aParams, nsIInputStream** aStream);
+    static GonkCaptureProvider* sInstance;
+};
+
+class GonkCameraInputStream : public nsIAsyncInputStream {
+  public:
+    GonkCameraInputStream();
+    ~GonkCameraInputStream();
+
+    NS_IMETHODIMP Init(nsACString& aContentType, nsCaptureParams* aParams);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIINPUTSTREAM
+    NS_DECL_NSIASYNCINPUTSTREAM
+
+    void ReceiveFrame(char* frame, PRUint32 length);
+
+    static void  DataCallback(int32_t aMsgType, const sp<IMemory>& aDataPtr, void *aUser);
+
+  protected:
+    void NotifyListeners();
+    void doClose();
+
+  private:
+    PRUint32 mAvailable;
+    nsCString mContentType;
+    PRUint32 mWidth;
+    PRUint32 mHeight;
+    PRUint32 mFps;
+    PRUint32 mCamera;
+    bool mHeaderSent;
+    bool mClosed;
+    bool mIs420p;
+    nsDeque mFrameQueue;
+    PRUint32 mFrameSize;
+    mozilla::ReentrantMonitor mMonitor;
+    nsCOMPtr<nsIInputStreamCallback> mCallback;
+    nsCOMPtr<nsIEventTarget> mCallbackTarget;
+    CameraHardwareInterface* mHardware;
+};
+
+already_AddRefed<GonkCaptureProvider> GetGonkCaptureProvider();
+
+#endif
--- a/netwerk/protocol/device/Makefile.in
+++ b/netwerk/protocol/device/Makefile.in
@@ -59,16 +59,21 @@ CPPSRCS += AndroidCaptureProvider.cpp \
 EXPORTS_NAMESPACES = mozilla/net
 
 EXPORTS_mozilla/net += \
   CameraStreamImpl.h  \
   $(NULL)
 
 endif
 
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += GonkCaptureProvider.cpp \
+           $(NULL)
+endif
+
 LOCAL_INCLUDES = -I$(srcdir)/../../base/src/ \
                  $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
--- a/netwerk/protocol/device/nsDeviceChannel.cpp
+++ b/netwerk/protocol/device/nsDeviceChannel.cpp
@@ -40,16 +40,22 @@
 #include "nsDeviceChannel.h"
 #include "nsDeviceCaptureProvider.h"
 #include "mozilla/Preferences.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidCaptureProvider.h"
 #endif
 
+#ifdef MOZ_WIDGET_GONK
+#include "GonkCaptureProvider.h"
+#endif
+
+using namespace mozilla;
+
 // Copied from image/decoders/icon/nsIconURI.cpp
 // takes a string like ?size=32&contentType=text/html and returns a new string
 // containing just the attribute values. i.e you could pass in this string with
 // an attribute name of "size=", this will return 32
 // Assumption: attribute pairs are separated by &
 void extractAttributeValue(const char* searchString, const char* attributeName, nsCString& result)
 {
   result.Truncate();
@@ -134,20 +140,25 @@ nsDeviceChannel::OpenContentStream(bool 
     nsresult err;
     captureParams.width = buffer.ToInteger(&err);
     if (!captureParams.width)
       captureParams.width = 640;
     extractAttributeValue(spec.get(), "height=", buffer);
     captureParams.height = buffer.ToInteger(&err);
     if (!captureParams.height)
       captureParams.height = 480;
+    extractAttributeValue(spec.get(), "camera=", buffer);
+    captureParams.camera = buffer.ToInteger(&err);
     captureParams.bpp = 32;
 #ifdef MOZ_WIDGET_ANDROID
     capture = GetAndroidCaptureProvider();
 #endif
+#ifdef MOZ_WIDGET_GONK
+    capture = GetGonkCaptureProvider();
+#endif
   } else if (kNotFound != spec.Find(NS_LITERAL_CSTRING("type=video/x-raw-yuv"),
                                     true,
                                     0,
                                     -1)) {
     type.AssignLiteral("video/x-raw-yuv");
     SetContentType(type);
     captureParams.captureAudio = false;
     captureParams.captureVideo = true;
@@ -156,24 +167,30 @@ nsDeviceChannel::OpenContentStream(bool 
     nsresult err;
     captureParams.width = buffer.ToInteger(&err);
     if (!captureParams.width)
       captureParams.width = 640;
     extractAttributeValue(spec.get(), "height=", buffer);
     captureParams.height = buffer.ToInteger(&err);
     if (!captureParams.height)
       captureParams.height = 480;
+    extractAttributeValue(spec.get(), "camera=", buffer);
+    captureParams.camera = buffer.ToInteger(&err);
     captureParams.bpp = 32;
     captureParams.timeLimit = 0;
     captureParams.frameLimit = 60000;
 #ifdef MOZ_WIDGET_ANDROID
     // only enable if "device.camera.enabled" is true.
-    if (mozilla::Preferences::GetBool("device.camera.enabled", false) == true)
+    if (Preferences::GetBool("device.camera.enabled", false) == true)
       capture = GetAndroidCaptureProvider();
 #endif
+#ifdef MOZ_WIDGET_GONK
+    if (Preferences::GetBool("device.camera.enabled", false) == true)
+      capture = GetGonkCaptureProvider();
+#endif
   } else {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   if (!capture)
     return NS_ERROR_FAILURE;
 
   return capture->Init(type, &captureParams, aStream);
--- a/security/manager/ssl/src/PSMRunnable.cpp
+++ b/security/manager/ssl/src/PSMRunnable.cpp
@@ -41,24 +41,28 @@ namespace mozilla { namespace psm {
 SyncRunnableBase::SyncRunnableBase()
   : monitor("SyncRunnableBase::monitor")
 {
 }
 
 nsresult
 SyncRunnableBase::DispatchToMainThreadAndWait()
 {
-  NS_ASSERTION(!NS_IsMainThread(),
-               "DispatchToMainThreadAndWait called on the main thread.");
+  nsresult rv;
+  if (NS_IsMainThread()) {
+    RunOnTargetThread();
+    rv = NS_OK;
+  } else {
+    mozilla::MonitorAutoLock lock(monitor);
+    rv = NS_DispatchToMainThread(this);
+    if (NS_SUCCEEDED(rv)) {
+      lock.Wait();
+    }
+  }
 
-  mozilla::MonitorAutoLock lock(monitor);
-  nsresult rv = NS_DispatchToMainThread(this);
-  if (NS_SUCCEEDED(rv)) {
-    lock.Wait();
-  }
   return rv;
 }
 
 NS_IMETHODIMP
 SyncRunnableBase::Run()
 {
   RunOnTargetThread();
   mozilla::MonitorAutoLock(monitor).Notify();
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -37,54 +37,60 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* 
- * All I/O is done on the socket transport thread, including all calls into
- * libssl. That is, all SSL_* functions must be called on the socket transport
- * thread. This also means that all SSL callback functions will be called on
- * the socket transport thread, including in particular the auth certificate
- * hook.
+ * For connections that are not processed on the socket transport thread, we do
+ * NOT use the async logic described below. Instead, we authenticate the
+ * certificate on the thread that the connection's I/O happens on,
+ * synchronously. This allows us to do certificate verification for blocking
+ * (not non-blocking) sockets and sockets that have their I/O processed on a
+ * thread other than the socket transport service thread. Also, we DO NOT
+ * support blocking sockets on the socket transport service thread at all.
  *
  * During certificate authentication, we call CERT_PKIXVerifyCert or
  * CERT_VerifyCert. These functions may make zero or more HTTP requests
- * for OCSP responses, CRLs, intermediate certificates, etc.
+ * for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
+ * for these requests processes them on the socket transport service thread.
  *
- * If our cert auth hook were to call the CERT_*Verify* functions directly,
+ * If the connection for which we are verifying the certificate is happening
+ * on the socket transport thread (the usually case, at least for HTTP), then
+ * if our cert auth hook were to call the CERT_*Verify* functions directly,
  * there would be a deadlock: The CERT_*Verify* function would cause an event
  * to be asynchronously posted to the socket transport thread, and then it
  * would block the socket transport thread waiting to be notified of the HTTP
  * response. However, the HTTP request would never actually be processed
  * because the socket transport thread would be blocked and so it wouldn't be
  * able process HTTP requests. (i.e. Deadlock.)
  *
- * Consequently, we must always call the CERT_*Verify* cert functions off the
- * socket transport thread. To accomplish this, our auth cert hook dispatches a
- * SSLServerCertVerificationJob to a pool of background threads, and then
- * immediatley return SECWouldBlock to libssl. These jobs are where the
- * CERT_*Verify* functions are actually called. 
+ * Consequently, when we are asked to verify a certificate on the socket
+ * transport service thread, we must always call the CERT_*Verify* cert
+ * functions on another thread. To accomplish this, our auth cert hook
+ * dispatches a SSLServerCertVerificationJob to a pool of background threads,
+ * and then immediatley return SECWouldBlock to libssl. These jobs are where
+ * the CERT_*Verify* functions are actually called. 
  *
  * When our auth cert hook returns SECWouldBlock, libssl will carry on the
  * handshake while we validate the certificate. This will free up the socket
  * transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
  * requests needed for cert verification as mentioned above--can be processed.
  *
  * Once the CERT_*Verify* function returns, the cert verification job
  * dispatches a SSLServerCertVerificationResult to the socket transport thread;
  * the SSLServerCertVerificationResult will notify libssl that the certificate
  * authentication is complete. Once libssl is notified that the authentication
  * is complete, it will continue the SSL handshake (if it hasn't already
  * finished) and it will begin allowing us to send/receive data on the
  * connection.
  *
- * Timeline of events:
+ * Timeline of events (for connections managed by the socket transport service):
  *
  *    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
  *      transport thread.
  *    * SSLServerCertVerificationJob::Dispatch queues a job
  *      (instance of SSLServerCertVerificationJob) to its background thread
  *      pool and returns.
  *    * One of the background threads calls CERT_*Verify*, which may enqueue
  *      some HTTP request(s) onto the socket transport thread, and then
@@ -120,36 +126,49 @@
  * thread because we must only call SSL_* functions on the socket transport
  * thread since they may do I/O, because many parts of nsNSSSocketInfo and
  * the PSM NSS I/O layer are not thread-safe, and because we need the event to
  * interrupt the PR_Poll that may waiting for I/O on the socket for which we
  * are validating the cert.
  */
 
 #include "SSLServerCertVerification.h"
+#include "nsIBadCertListener2.h"
+#include "nsICertOverrideService.h"
+#include "nsIStrictTransportSecurityService.h"
 #include "nsNSSComponent.h"
-#include "nsNSSCertificate.h"
+#include "nsNSSCleaner.h"
+#include "nsRecentBadCerts.h"
 #include "nsNSSIOLayer.h"
 
+#include "mozilla/Assertions.h"
 #include "nsIThreadPool.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
+#include "PSMRunnable.h"
 
 #include "ssl.h"
 #include "secerr.h"
+#include "secport.h"
 #include "sslerr.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
 
 namespace mozilla { namespace psm {
 
 namespace {
+
+NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
+NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
+NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, false)
+
 // do not use a nsCOMPtr to avoid static initializer/destructor
 nsIThreadPool * gCertVerificationThreadPool = nsnull;
 } // unnamed namespace
 
 // Called when the socket transport thread starts, to initialize the SSL cert
 // verification thread pool. By tying the thread pool startup/shutdown directly
 // to the STS thread's lifetime, we ensure that they are *always* available for
 // SSL connections and that there are no races during startup and especially
@@ -192,35 +211,405 @@ void StopSSLServerCertVerificationThread
   if (gCertVerificationThreadPool) {
     gCertVerificationThreadPool->Shutdown();
     NS_RELEASE(gCertVerificationThreadPool);
   }
 }
 
 namespace {
 
+// Dispatched to the STS thread to notify the socketInfo of the verification
+// result.
+//
+// This will cause the PR_Poll in the STS thread to return, so things work
+// correctly even if the STS thread is blocked polling (only) on the file
+// descriptor that is waiting for this result.
+class SSLServerCertVerificationResult : public nsRunnable
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
+                                  PRErrorCode errorCode,
+                                  SSLErrorMessageType errorMessageType = 
+                                      PlainErrorMessage);
+
+  void Dispatch();
+private:
+  const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
+public:
+  const PRErrorCode mErrorCode;
+  const SSLErrorMessageType mErrorMessageType;
+};
+
+class CertErrorRunnable : public SyncRunnableBase
+{
+ public:
+  CertErrorRunnable(const void * fdForLogging,
+                    nsIX509Cert * cert,
+                    nsNSSSocketInfo * infoObject,
+                    PRErrorCode defaultErrorCodeToReport,
+                    PRUint32 collectedErrors,
+                    PRErrorCode errorCodeTrust,
+                    PRErrorCode errorCodeMismatch,
+                    PRErrorCode errorCodeExpired)
+    : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
+      mDefaultErrorCodeToReport(defaultErrorCodeToReport),
+      mCollectedErrors(collectedErrors),
+      mErrorCodeTrust(errorCodeTrust),
+      mErrorCodeMismatch(errorCodeMismatch),
+      mErrorCodeExpired(errorCodeExpired)
+  {
+  }
+
+  virtual void RunOnTargetThread();
+  nsRefPtr<SSLServerCertVerificationResult> mResult; // out
+private:
+  SSLServerCertVerificationResult* CheckCertOverrides();
+  
+  const void * const mFdForLogging; // may become an invalid pointer; do not dereference
+  const nsCOMPtr<nsIX509Cert> mCert;
+  const nsRefPtr<nsNSSSocketInfo> mInfoObject;
+  const PRErrorCode mDefaultErrorCodeToReport;
+  const PRUint32 mCollectedErrors;
+  const PRErrorCode mErrorCodeTrust;
+  const PRErrorCode mErrorCodeMismatch;
+  const PRErrorCode mErrorCodeExpired;
+};
+
+SSLServerCertVerificationResult *
+CertErrorRunnable::CheckCertOverrides()
+{
+  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
+                                    mFdForLogging, this));
+
+  if (!NS_IsMainThread()) {
+    NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
+    return new SSLServerCertVerificationResult(*mInfoObject,
+                                               mDefaultErrorCodeToReport);
+  }
+
+  PRInt32 port;
+  mInfoObject->GetPort(&port);
+
+  nsCString hostWithPortString;
+  hostWithPortString.AppendASCII(mInfoObject->GetHostName());
+  hostWithPortString.AppendLiteral(":");
+  hostWithPortString.AppendInt(port);
+
+  PRUint32 remaining_display_errors = mCollectedErrors;
+
+  nsresult nsrv;
+
+  // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
+  // connections must be dropped when there are any certificate errors
+  // (STS Spec section 7.3).
+  bool strictTransportSecurityEnabled = false;
+  nsCOMPtr<nsIStrictTransportSecurityService> stss
+    = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
+  if (NS_SUCCEEDED(nsrv)) {
+    nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
+                           &strictTransportSecurityEnabled);
+  }
+  if (NS_FAILED(nsrv)) {
+    return new SSLServerCertVerificationResult(*mInfoObject,
+                                               mDefaultErrorCodeToReport);
+  }
+
+  if (!strictTransportSecurityEnabled) {
+    nsCOMPtr<nsICertOverrideService> overrideService =
+      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
+    // it is fine to continue without the nsICertOverrideService
+
+    PRUint32 overrideBits = 0;
+
+    if (overrideService)
+    {
+      bool haveOverride;
+      bool isTemporaryOverride; // we don't care
+      nsCString hostString(mInfoObject->GetHostName());
+      nsrv = overrideService->HasMatchingOverride(hostString, port,
+                                                  mCert,
+                                                  &overrideBits,
+                                                  &isTemporaryOverride, 
+                                                  &haveOverride);
+      if (NS_SUCCEEDED(nsrv) && haveOverride) 
+      {
+       // remove the errors that are already overriden
+        remaining_display_errors -= overrideBits;
+      }
+    }
+
+    if (!remaining_display_errors) {
+      // all errors are covered by override rules, so let's accept the cert
+      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+             ("[%p][%p] All errors covered by override rules\n",
+             mFdForLogging, this));
+      return new SSLServerCertVerificationResult(*mInfoObject, 0);
+    }
+  } else {
+    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+           ("[%p][%p] Strict-Transport-Security is violated: untrusted "
+            "transport layer\n", mFdForLogging, this));
+  }
+
+  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+         ("[%p][%p] Certificate error was not overridden\n",
+         mFdForLogging, this));
+
+  // Ok, this is a full stop.
+  // First, deliver the technical details of the broken SSL status.
+
+  // Try to get a nsIBadCertListener2 implementation from the socket consumer.
+  nsCOMPtr<nsIInterfaceRequestor> cb;
+  mInfoObject->GetNotificationCallbacks(getter_AddRefs(cb));
+  if (cb) {
+    nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
+    if (bcl) {
+      nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(mInfoObject);
+      bool suppressMessage = false; // obsolete, ignored
+      nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
+                                    hostWithPortString, &suppressMessage);
+    }
+  }
+
+  nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService = 
+    do_GetService(NS_RECENTBADCERTS_CONTRACTID);
+ 
+  if (recentBadCertsService) {
+    NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
+    recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
+                                      mInfoObject->SSLStatus());
+  }
+
+  // pick the error code to report by priority
+  PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
+                                : mErrorCodeMismatch ? mErrorCodeMismatch
+                                : mErrorCodeExpired  ? mErrorCodeExpired
+                                : mDefaultErrorCodeToReport;
+
+  return new SSLServerCertVerificationResult(*mInfoObject, errorCodeToReport,
+                                             OverridableCertErrorMessage);
+}
+
+void 
+CertErrorRunnable::RunOnTargetThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mResult = CheckCertOverrides();
+  
+  MOZ_ASSERT(mResult);
+}
+
+// Returns null with the error code (PR_GetError()) set if it does not create
+// the CertErrorRunnable.
+CertErrorRunnable *
+CreateCertErrorRunnable(PRErrorCode defaultErrorCodeToReport,
+                        nsNSSSocketInfo * socketInfo,
+                        CERTCertificate * cert,
+                        const void * fdForLogging)
+{
+  MOZ_ASSERT(socketInfo);
+  MOZ_ASSERT(cert);
+  
+  // cert was revoked, don't do anything else
+  if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
+    PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
+    return nsnull;
+  }
+
+  if (defaultErrorCodeToReport == 0) {
+    NS_ERROR("No error code set during certificate validation failure.");
+    PR_SetError(PR_INVALID_STATE_ERROR, 0);
+    return nsnull;
+  }
+
+  nsRefPtr<nsNSSCertificate> nssCert;
+  nssCert = nsNSSCertificate::Create(cert);
+  if (!nssCert) {
+    NS_ERROR("nsNSSCertificate::Create failed");
+    PR_SetError(SEC_ERROR_NO_MEMORY, 0);
+    return nsnull;
+  }
+
+  SECStatus srv;
+  nsresult nsrv;
+
+  nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
+  if (!inss) {
+    NS_ERROR("do_GetService(kNSSComponentCID) failed");
+    PR_SetError(defaultErrorCodeToReport, 0);
+    return nsnull;
+  }
+
+  nsRefPtr<nsCERTValInParamWrapper> survivingParams;
+  nsrv = inss->GetDefaultCERTValInParam(survivingParams);
+  if (NS_FAILED(nsrv)) {
+    NS_ERROR("GetDefaultCERTValInParam failed");
+    PR_SetError(defaultErrorCodeToReport, 0);
+    return nsnull;
+  }
+  
+  PRArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+  PRArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
+  if (!log_arena) {
+    NS_ERROR("PORT_NewArena failed");
+    return nsnull; // PORT_NewArena set error code
+  }
+
+  CERTVerifyLog *verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
+  if (!verify_log) {
+    NS_ERROR("PORT_ArenaZNew failed");
+    return nsnull; // PORT_ArenaZNew set error code
+  }
+  CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
+  verify_log->arena = log_arena;
+
+  if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
+    srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert,
+                                true, certificateUsageSSLServer,
+                                PR_Now(), static_cast<void*>(socketInfo),
+                                verify_log, NULL);
+  }
+  else {
+    CERTValOutParam cvout[2];
+    cvout[0].type = cert_po_errorLog;
+    cvout[0].value.pointer.log = verify_log;
+    cvout[1].type = cert_po_end;
+
+    srv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
+                              survivingParams->GetRawPointerForNSS(),
+                              cvout, static_cast<void*>(socketInfo));
+  }
+
+  // We ignore the result code of the cert verification.
+  // Either it is a failure, which is expected, and we'll process the
+  //                         verify log below.
+  // Or it is a success, then a domain mismatch is the only 
+  //                     possible failure. 
+
+  PRErrorCode errorCodeMismatch = 0;
+  PRErrorCode errorCodeTrust = 0;
+  PRErrorCode errorCodeExpired = 0;
+
+  PRUint32 collected_errors = 0;
+
+  if (socketInfo->IsCertIssuerBlacklisted()) {
+    collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
+    errorCodeTrust = defaultErrorCodeToReport;
+  }
+
+  // Check the name field against the desired hostname.
+  if (CERT_VerifyCertName(cert, socketInfo->GetHostName()) != SECSuccess) {
+    collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
+    errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
+  }
+
+  CERTVerifyLogNode *i_node;
+  for (i_node = verify_log->head; i_node; i_node = i_node->next)
+  {
+    switch (i_node->error)
+    {
+      case SEC_ERROR_UNKNOWN_ISSUER:
+      case SEC_ERROR_CA_CERT_INVALID:
+      case SEC_ERROR_UNTRUSTED_ISSUER:
+      case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+      case SEC_ERROR_UNTRUSTED_CERT:
+      case SEC_ERROR_INADEQUATE_KEY_USAGE:
+        // We group all these errors as "cert not trusted"
+        collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
+        if (errorCodeTrust == SECSuccess) {
+          errorCodeTrust = i_node->error;
+        }
+        break;
+      case SSL_ERROR_BAD_CERT_DOMAIN:
+        collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
+        if (errorCodeMismatch == SECSuccess) {
+          errorCodeMismatch = i_node->error;
+        }
+        break;
+      case SEC_ERROR_EXPIRED_CERTIFICATE:
+        collected_errors |= nsICertOverrideService::ERROR_TIME;
+        if (errorCodeExpired == SECSuccess) {
+          errorCodeExpired = i_node->error;
+        }
+        break;
+      default:
+        PR_SetError(i_node->error, 0);
+        return nsnull;
+    }
+  }
+
+  if (!collected_errors)
+  {
+    // This will happen when CERT_*Verify* only returned error(s) that are
+    // not on our whitelist of overridable certificate errors.
+    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
+           fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
+    PR_SetError(defaultErrorCodeToReport, 0);
+    return nsnull;
+  }
+
+  socketInfo->SetStatusErrorBits(*nssCert, collected_errors);
+
+  return new CertErrorRunnable(fdForLogging, 
+                               static_cast<nsIX509Cert*>(nssCert.get()),
+                               socketInfo, defaultErrorCodeToReport, 
+                               collected_errors, errorCodeTrust, 
+                               errorCodeMismatch, errorCodeExpired);
+}
+
+// When doing async cert processing, we dispatch one of these runnables to the
+// socket transport service thread, which blocks the socket transport
+// service thread while it waits for the inner CertErrorRunnable to execute
+// CheckCertOverrides on the main thread. CheckCertOverrides must block events
+// on both of these threads because it calls nsNSSSocketInfo::GetInterface(), 
+// which may call nsHttpConnection::GetInterface() through
+// nsNSSSocketInfo::mCallbacks. nsHttpConnection::GetInterface must always
+// execute on the main thread, with the socket transport service thread
+// blocked.
+class CertErrorRunnableRunnable : public nsRunnable
+{
+public:
+  CertErrorRunnableRunnable(CertErrorRunnable * certErrorRunnable)
+    : mCertErrorRunnable(certErrorRunnable)
+  {
+  }
+private:
+  NS_IMETHOD Run()
+  {
+    nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
+    // The result must run on the socket transport thread, which we are already
+    // on, so we can just run it directly, instead of dispatching it.
+    if (NS_SUCCEEDED(rv)) {
+      rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
+                                       : NS_ERROR_UNEXPECTED;
+    }
+    return rv;
+  }
+  nsRefPtr<CertErrorRunnable> mCertErrorRunnable;
+};
+
 class SSLServerCertVerificationJob : public nsRunnable
 {
 public:
   // Must be called only on the socket transport thread
   static SECStatus Dispatch(const void * fdForLogging,
                             nsNSSSocketInfo * infoObject,
                             CERTCertificate * serverCert);
 private:
   NS_DECL_NSIRUNNABLE
 
   // Must be called only on the socket transport thread
   SSLServerCertVerificationJob(const void * fdForLogging,
                                nsNSSSocketInfo & socketInfo, 
                                CERTCertificate & cert);
   ~SSLServerCertVerificationJob();
 
-  // Runs on one of the background threads
-  SECStatus AuthCertificate(const nsNSSShutDownPreventionLock & proofOfLock);
-
   const void * const mFdForLogging;
   const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
   CERTCertificate * const mCert;
 };
 
 SSLServerCertVerificationJob::SSLServerCertVerificationJob(
     const void * fdForLogging, nsNSSSocketInfo & socketInfo,
     CERTCertificate & cert)
@@ -230,22 +619,19 @@ SSLServerCertVerificationJob::SSLServerC
 {
 }
 
 SSLServerCertVerificationJob::~SSLServerCertVerificationJob()
 {
   CERT_DestroyCertificate(mCert);
 }
 
-static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
-
 SECStatus
 PSM_SSL_PKIX_AuthCertificate(CERTCertificate *peerCert, void * pinarg,
-                             const char * hostname,
-                             const nsNSSShutDownPreventionLock & /*proofOfLock*/)
+                             const char * hostname)
 {
     SECStatus          rv;
     
     if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
         rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, true,
                                 certUsageSSLServer, pinarg);
     }
     else {
@@ -429,29 +815,28 @@ BlockServerCertChangeForSpdy(nsNSSSocket
   // Report an error - changed cert is confirmed
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
          ("SPDY Refused to allow new cert during renegotiation\n"));
   PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
   return SECFailure;
 }
 
 SECStatus
-SSLServerCertVerificationJob::AuthCertificate(
-  nsNSSShutDownPreventionLock const & nssShutdownPreventionLock)
+AuthCertificate(nsNSSSocketInfo * socketInfo, CERTCertificate * cert)
 {
-  if (BlockServerCertChangeForSpdy(mSocketInfo, mCert) != SECSuccess)
+  if (BlockServerCertChangeForSpdy(socketInfo, cert) != SECSuccess)
     return SECFailure;
 
-  if (mCert->serialNumber.data &&
-      mCert->issuerName &&
-      !strcmp(mCert->issuerName, 
+  if (cert->serialNumber.data &&
+      cert->issuerName &&
+      !strcmp(cert->issuerName, 
         "CN=UTN-USERFirst-Hardware,OU=http://www.usertrust.com,O=The USERTRUST Network,L=Salt Lake City,ST=UT,C=US")) {
 
-    unsigned char *server_cert_comparison_start = mCert->serialNumber.data;
-    unsigned int server_cert_comparison_len = mCert->serialNumber.len;
+    unsigned char *server_cert_comparison_start = cert->serialNumber.data;
+    unsigned int server_cert_comparison_len = cert->serialNumber.len;
 
     while (server_cert_comparison_len) {
       if (*server_cert_comparison_start != 0)
         break;
 
       ++server_cert_comparison_start;
       --server_cert_comparison_len;
     }
@@ -473,51 +858,50 @@ SSLServerCertVerificationJob::AuthCertif
       if (server_cert_comparison_len == locked_cert_comparison_len &&
           !memcmp(server_cert_comparison_start, locked_cert_comparison_start, locked_cert_comparison_len)) {
         PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
         return SECFailure;
       }
     }
   }
 
-  SECStatus rv = PSM_SSL_PKIX_AuthCertificate(mCert, mSocketInfo,
-                                              mSocketInfo->GetHostName(),
-                                              nssShutdownPreventionLock);
+  SECStatus rv = PSM_SSL_PKIX_AuthCertificate(cert, socketInfo,
+                                              socketInfo->GetHostName());
 
   // We want to remember the CA certs in the temp db, so that the application can find the
   // complete chain at any time it might need it.
   // But we keep only those CA certs in the temp db, that we didn't already know.
 
-  nsRefPtr<nsSSLStatus> status = mSocketInfo->SSLStatus();
+  nsRefPtr<nsSSLStatus> status = socketInfo->SSLStatus();
   nsRefPtr<nsNSSCertificate> nsc;
 
   if (!status || !status->mServerCert) {
-    nsc = nsNSSCertificate::Create(mCert);
+    nsc = nsNSSCertificate::Create(cert);
   }
 
   CERTCertList *certList = nsnull;
-  certList = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLCA);
+  certList = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageSSLCA);
   if (!certList) {
     rv = SECFailure;
   } else {
     PRErrorCode blacklistErrorCode;
     if (rv == SECSuccess) { // PSM_SSL_PKIX_AuthCertificate said "valid cert"
-      blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(mCert, certList);
+      blacklistErrorCode = PSM_SSL_BlacklistDigiNotar(cert, certList);
     } else { // PSM_SSL_PKIX_AuthCertificate said "invalid cert"
       PRErrorCode savedErrorCode = PORT_GetError();
       // Check if we want to worsen the error code to "revoked".
-      blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(mCert, certList);
+      blacklistErrorCode = PSM_SSL_DigiNotarTreatAsRevoked(cert, certList);
       if (blacklistErrorCode == 0) {
         // we don't worsen the code, let's keep the original error code from NSS
         PORT_SetError(savedErrorCode);
       }
     }
       
     if (blacklistErrorCode != 0) {
-      mSocketInfo->SetCertIssuerBlacklisted();
+      socketInfo->SetCertIssuerBlacklisted();
       PORT_SetError(blacklistErrorCode);
       rv = SECFailure;
     }
   }
 
   if (rv == SECSuccess) {
     if (nsc) {
       bool dummyIsEV;
@@ -535,17 +919,17 @@ SSLServerCertVerificationJob::AuthCertif
         continue;
       }
 
       if (node->cert->isperm) {
         // We don't need to remember certs already stored in perm db.
         continue;
       }
         
-      if (node->cert == mCert) {
+      if (node->cert == cert) {
         // We don't want to remember the server cert, 
         // the code that cares for displaying page info does this already.
         continue;
       }
 
       // We have found a signer cert that we want to remember.
       char* nickname = nsNSSCertificate::defaultServerNickname(node->cert);
       if (nickname && *nickname) {
@@ -563,29 +947,29 @@ SSLServerCertVerificationJob::AuthCertif
       CERT_DestroyCertList(certList);
     }
 
     // The connection may get terminated, for example, if the server requires
     // a client cert. Let's provide a minimal SSLStatus
     // to the caller that contains at least the cert and its status.
     if (!status) {
       status = new nsSSLStatus();
-      mSocketInfo->SetSSLStatus(status);
+      socketInfo->SetSSLStatus(status);
     }
 
     if (rv == SECSuccess) {
       // Certificate verification succeeded delete any potential record
       // of certificate error bits.
       nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
-        mSocketInfo, nsnull, rv);
+        socketInfo, nsnull, rv);
     }
     else {
       // Certificate verification failed, update the status' bits.
       nsSSLIOLayerHelpers::mHostsWithCertErrors->LookupCertErrorBits(
-        mSocketInfo, status);
+        socketInfo, status);
     }
 
     if (status && !status->mServerCert) {
       status->mServerCert = nsc;
       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
              ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
     }
   }
@@ -594,40 +978,43 @@ SSLServerCertVerificationJob::AuthCertif
 }
 
 /*static*/ SECStatus
 SSLServerCertVerificationJob::Dispatch(const void * fdForLogging,
                                        nsNSSSocketInfo * socketInfo,
                                        CERTCertificate * serverCert)
 {
   // Runs on the socket transport thread
-
   if (!socketInfo || !serverCert) {
     NS_ERROR("Invalid parameters for SSL server cert validation");
-    socketInfo->SetCertVerificationResult(PR_INVALID_STATE_ERROR,
-                                          PlainErrorMessage);
-    PR_SetError(PR_INVALID_STATE_ERROR, 0);
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     return SECFailure;
   }
   
   nsRefPtr<SSLServerCertVerificationJob> job
     = new SSLServerCertVerificationJob(fdForLogging, *socketInfo, *serverCert);
 
   socketInfo->SetCertVerificationWaiting();
   nsresult nrv;
   if (!gCertVerificationThreadPool) {
     nrv = NS_ERROR_NOT_INITIALIZED;
   } else {
     nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
   }
   if (NS_FAILED(nrv)) {
+    // We can't call SetCertVerificationResult here to change
+    // mCertVerificationState because SetCertVerificationResult will call
+    // libssl functions that acquire SSL locks that are already being held at
+    // this point. socketInfo->mCertVerificationState will be stuck at
+    // waiting_for_cert_verification here, but that is OK because we already
+    // have to be able to handle cases where we encounter non-cert errors while
+    // in that state.
     PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
                       ? SEC_ERROR_NO_MEMORY
                       : PR_INVALID_STATE_ERROR;
-    socketInfo->SetCertVerificationResult(error, PlainErrorMessage);
     PORT_SetError(error);
     return SECFailure;
   }
 
   PORT_SetError(PR_WOULD_BLOCK_ERROR);
   return SECWouldBlock;    
 }
 
@@ -643,37 +1030,55 @@ SSLServerCertVerificationJob::Run()
 
   nsNSSShutDownPreventionLock nssShutdownPrevention;
   if (mSocketInfo->isAlreadyShutDown()) {
     error = SEC_ERROR_USER_CANCELLED;
   } else {
     // Reset the error code here so we can detect if AuthCertificate fails to
     // set the error code if/when it fails.
     PR_SetError(0, 0); 
-    SECStatus rv = AuthCertificate(nssShutdownPrevention);
+    SECStatus rv = AuthCertificate(mSocketInfo, mCert);
     if (rv == SECSuccess) {
       nsRefPtr<SSLServerCertVerificationResult> restart 
         = new SSLServerCertVerificationResult(*mSocketInfo, 0);
       restart->Dispatch();
       return NS_OK;
     }
 
     error = PR_GetError();
     if (error != 0) {
-      rv = HandleBadCertificate(error, mSocketInfo, *mCert, mFdForLogging,
-                                nssShutdownPrevention);
-      if (rv == SECSuccess) {
-        // The CertErrorRunnable will run on the main thread and it will dispatch
-        // the cert verification result to the socket transport thread, so we
-        // don't have to. This way, this verification thread doesn't need to
-        // wait for the CertErrorRunnable to complete.
-        return NS_OK; 
+      nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
+              error, mSocketInfo, mCert, mFdForLogging);
+      if (!runnable) {
+        // CreateCertErrorRunnable set a new error code
+        error = PR_GetError(); 
+      } else {
+        // We must block the the socket transport service thread while the
+        // main thread executes the CertErrorRunnable. The CertErrorRunnable
+        // will dispatch the result asynchronously, so we don't have to block
+        // this thread waiting for it.
+
+        PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+                ("[%p][%p] Before dispatching CertErrorRunnable\n",
+                mFdForLogging, runnable.get()));
+
+        nsresult nrv;
+        nsCOMPtr<nsIEventTarget> stsTarget
+          = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
+        if (NS_SUCCEEDED(nrv)) {
+          nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
+                                    NS_DISPATCH_NORMAL);
+        }
+        if (NS_SUCCEEDED(nrv)) {
+          return NS_OK;
+        }
+
+        NS_ERROR("Failed to dispatch CertErrorRunnable");
+        error = PR_INVALID_STATE_ERROR;
       }
-      // DispatchCertErrorRunnable set a new error code.
-      error = PR_GetError(); 
     }
   }
 
   if (error == 0) {
     NS_NOTREACHED("no error set during certificate validation failure");
     error = PR_INVALID_STATE_ERROR;
   }
 
@@ -705,24 +1110,101 @@ AuthCertificateHook(void *arg, PRFileDes
   NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
 
   if (!checkSig || isServer) {
       PR_SetError(PR_INVALID_STATE_ERROR, 0);
       return SECFailure;
   }
       
   CERTCertificate *serverCert = SSL_PeerCertificate(fd);
+  CERTCertificateCleaner serverCertCleaner(serverCert);
 
   nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);
-  SECStatus rv = SSLServerCertVerificationJob::Dispatch(
+
+  bool onSTSThread;
+  nsresult nrv;
+  nsCOMPtr<nsIEventTarget> sts
+    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
+  if (NS_SUCCEEDED(nrv)) {
+    nrv = sts->IsOnCurrentThread(&onSTSThread);
+  }
+
+  if (NS_FAILED(nrv)) {
+    NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
+    PR_SetError(PR_UNKNOWN_ERROR, 0);
+    return SECFailure;
+  }
+  
+  if (onSTSThread) {
+    // We *must* do certificate verification on a background thread because
+    // we need the socket transport thread to be free for our OCSP requests,
+    // and we *want* to do certificate verification on a background thread
+    // because of the performance benefits of doing so.
+    SECStatus rv = SSLServerCertVerificationJob::Dispatch(
                         static_cast<const void *>(fd), socketInfo, serverCert);
+    return rv;
+  }
+  
+  // We can't do certificate verification on a background thread, because the
+  // thread doing the network I/O may not interrupt its network I/O on receipt
+  // of our SSLServerCertVerificationResult event, and/or it might not even be
+  // a non-blocking socket.
+  SECStatus rv = AuthCertificate(socketInfo, serverCert);
+  if (rv == SECSuccess) {
+    return SECSuccess;
+  }
 
-  CERT_DestroyCertificate(serverCert);
+  PRErrorCode error = PR_GetError();
+  if (error != 0) {
+    nsRefPtr<CertErrorRunnable> runnable = CreateCertErrorRunnable(
+                    error, socketInfo, serverCert,
+                    static_cast<const void *>(fd));
+    if (!runnable) {
+      // CreateCertErrorRunnable sets a new error code when it fails
+      error = PR_GetError();
+    } else {
+      // We have to return SECSuccess or SECFailure based on the result of the
+      // override processing, so we must block this thread waiting for it. The
+      // CertErrorRunnable will NOT dispatch the result at all, since we passed
+      // false for CreateCertErrorRunnable's async parameter
+      nrv = runnable->DispatchToMainThreadAndWait();
+      if (NS_FAILED(nrv)) {
+        NS_ERROR("Failed to dispatch CertErrorRunnable");
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        return SECFailure;
+      }
 
-  return rv;
+      if (!runnable->mResult) {
+        NS_ERROR("CertErrorRunnable did not set result");
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        return SECFailure;
+      }
+
+      if (runnable->mResult->mErrorCode == 0) {
+        return SECSuccess; // cert error override occurred.
+      }
+
+      // We must call SetCanceled here to set the error message type
+      // in case it isn't PlainErrorMessage, which is what we would
+      // default to if we just called
+      // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
+      // SECFailure without doing this.
+      socketInfo->SetCanceled(runnable->mResult->mErrorCode,
+                              runnable->mResult->mErrorMessageType);
+      error = runnable->mResult->mErrorCode;
+    }
+  }
+
+  if (error == 0) {
+    NS_ERROR("error code not set");
+    error = PR_UNKNOWN_ERROR;
+  }
+
+  PR_SetError(error, 0);
+  return SECFailure;
 }
 
 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
         nsNSSSocketInfo & socketInfo, PRErrorCode errorCode,
         SSLErrorMessageType errorMessageType)
   : mSocketInfo(&socketInfo)
   , mErrorCode(errorCode)
   , mErrorMessageType(errorMessageType)
--- a/security/manager/ssl/src/SSLServerCertVerification.h
+++ b/security/manager/ssl/src/SSLServerCertVerification.h
@@ -34,56 +34,23 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef _SSLSERVERCERTVERIFICATION_H
 #define _SSLSERVERCERTVERIFICATION_H
 
 #include "seccomon.h"
-#include "nsAutoPtr.h"
-#include "nsThreadUtils.h"
-#include "nsIRunnable.h"
-#include "prerror.h"
-#include "nsNSSIOLayer.h"
+#include "prio.h"
 
 typedef struct PRFileDesc PRFileDesc;
 typedef struct CERTCertificateStr CERTCertificate;
 class nsNSSSocketInfo;
 class nsNSSShutDownPreventionLock;
 
 namespace mozilla { namespace psm {
 
 SECStatus AuthCertificateHook(void *arg, PRFileDesc *fd, 
                               PRBool checkSig, PRBool isServer);
 
-SECStatus HandleBadCertificate(PRErrorCode defaultErrorCodeToReport,
-                               nsNSSSocketInfo * socketInfo,
-                               CERTCertificate & cert,
-                               const void * fdForLogging,
-                               const nsNSSShutDownPreventionLock &);
-
-// Dispatched from a cert verification thread to the STS thread to notify the
-// socketInfo of the verification result.
-//
-// This will cause the PR_Poll in the STS thread to return, so things work
-// correctly even if the STS thread is blocked polling (only) on the file
-// descriptor that is waiting for this result.
-class SSLServerCertVerificationResult : public nsRunnable
-{
-public:
-  NS_DECL_NSIRUNNABLE
-
-  SSLServerCertVerificationResult(nsNSSSocketInfo & socketInfo,
-                                  PRErrorCode errorCode,
-                                  SSLErrorMessageType errorMessageType = 
-                                      PlainErrorMessage);
-
-  void Dispatch();
-private:
-  const nsRefPtr<nsNSSSocketInfo> mSocketInfo;
-  const PRErrorCode mErrorCode;
-  const SSLErrorMessageType mErrorMessageType;
-};
-
 } } // namespace mozilla::psm
 
 #endif
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -810,38 +810,34 @@ void PK11PasswordPromptRunnable::RunOnTa
 }
 
 char* PR_CALLBACK
 PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
 {
   nsRefPtr<PK11PasswordPromptRunnable> runnable = 
     new PK11PasswordPromptRunnable(slot,
                                    static_cast<nsIInterfaceRequestor*>(arg));
-  if (NS_IsMainThread()) {
-    runnable->RunOnTargetThread();
-  } else {
-    runnable->DispatchToMainThreadAndWait();
-  }
+  runnable->DispatchToMainThreadAndWait();
   return runnable->mResult;
 }
 
 void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
   nsNSSShutDownPreventionLock locker;
   PRInt32 sslStatus;
   char* signer = nsnull;
   char* cipherName = nsnull;
   PRInt32 keyLength;
   nsresult rv;
   PRInt32 encryptBits;
 
   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
 
   // If the handshake completed, then we know the site is TLS tolerant (if this
   // was a TLS connection).
-  nsSSLIOLayerHelpers::rememberTolerantSite(fd, infoObject);
+  nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);
 
   if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
                                        &encryptBits, &signer, nsnull)) {
     return;
   }
 
   PRInt32 secStatus;
   if (sslStatus == SSL_SECURITY_STATUS_OFF)
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -52,35 +52,31 @@
 #include "nsIChannel.h"
 #include "nsNSSCertificate.h"
 #include "nsIX509CertValidity.h"
 #include "nsIDateTimeFormat.h"
 #include "nsDateTimeFormatCID.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsClientAuthRemember.h"
 #include "nsICertOverrideService.h"
-#include "nsIBadCertListener2.h"
 #include "nsISSLErrorListener.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
-#include "nsRecentBadCerts.h"
-#include "nsIStrictTransportSecurityService.h"
 
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsHashSets.h"
 #include "nsCRT.h"
 #include "nsAutoPtr.h"
 #include "nsPrintfCString.h"
 #include "SSLServerCertVerification.h"
 #include "nsNSSShutDown.h"
 #include "nsSSLStatus.h"
 #include "nsNSSCertHelper.h"
 #include "nsNSSCleaner.h"
-#include "nsThreadUtils.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIArray.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "PSMRunnable.h"
@@ -88,17 +84,16 @@
 #include "ssl.h"
 #include "secerr.h"
 #include "sslerr.h"
 #include "secder.h"
 #include "secasn1.h"
 #include "certdb.h"
 #include "cert.h"
 #include "keyhi.h"
-#include "secport.h"
 
 #include "mozilla/Util.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal 
                             //reports when doing SSL read/write
@@ -108,17 +103,16 @@ using namespace mozilla::psm;
                        //read/write buffer to a log.
                        //Uses PR_LOG except on Mac where
                        //we always write out to our own
                        //file.
 
 
 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
 NSSCleanupAutoPtrClass(void, PR_FREEIF)
-NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, false)
 
 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 
 /* SSM_UserCertChoice: enum for cert choice info */
 typedef enum {ASK, AUTO} SSM_UserCertChoice;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
@@ -159,16 +153,18 @@ nsNSSSocketInfo::nsNSSSocketInfo()
     mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
     mSubRequestsHighSecurity(0),
     mSubRequestsLowSecurity(0),
     mSubRequestsBrokenSecurity(0),
     mSubRequestsNoSecurity(0),
     mErrorCode(0),
     mErrorMessageType(PlainErrorMessage),
     mForSTARTTLS(false),
+    mSSL3Enabled(false),
+    mTLSEnabled(false),
     mHandshakePending(true),
     mHasCleartextPhase(false),
     mHandshakeInProgress(false),
     mAllowTLSIntoleranceTimeout(true),
     mRememberClientAuthCertificate(false),
     mHandshakeStartTime(0),
     mPort(0),
     mIsCertIssuerBlacklisted(false),
@@ -937,21 +933,16 @@ private:
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
 };
 
 void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
 {
   NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
   *_result = nsnull;
 
-  if (NS_IsMainThread()) {
-    NS_ERROR("nsNSSSocketInfo::GetPreviousCert called on the main thread");
-    return;
-  }
-
   nsRefPtr<PreviousCertRunnable> runnable = new PreviousCertRunnable(mCallbacks);
   nsresult rv = runnable->DispatchToMainThreadAndWait();
   NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
   runnable->mPreviousCert.forget(_result);
 }
 
 void
 nsNSSSocketInfo::SetCertVerificationWaiting()
@@ -960,16 +951,20 @@ nsNSSSocketInfo::SetCertVerificationWait
   // handshake on the connection, or after_cert_verification for subsequent
   // renegotiation handshakes.
   NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
                "Invalid state transition to waiting_for_cert_verification");
   mCertVerificationState = waiting_for_cert_verification;
   mCertVerificationStarted = PR_IntervalNow();
 }
 
+// Be careful that SetCertVerificationResult does NOT get called while we are
+// processing a SSL callback function, because SSL_AuthCertificateComplete will
+// attempt to acquire locks that are already held by libssl when it calls
+// callbacks.
 void
 nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
                                            SSLErrorMessageType errorMessageType)
 {
   NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
                "Invalid state transition to cert_verification_finished");
 
   mCertVerificationEnded = PR_IntervalNow();
@@ -1754,54 +1749,43 @@ nsSSLIOLayerHelpers::getSiteKey(nsNSSSoc
   socketInfo->GetHostName(getter_Copies(host));
 
   key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
 }
 
 // Call this function to report a site that is possibly TLS intolerant.
 // This function will return true, if the given socket is currently using TLS.
 bool
-nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo)
+nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
 {
-  PRBool currentlyUsesTLS = false;
-
   nsCAutoString key;
   getSiteKey(socketInfo, key);
 
-  SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
-  if (!currentlyUsesTLS) {
-    // We were not using TLS but failed with an intolerant error using
+  if (!socketInfo->IsTLSEnabled()) {
+    // We did not offer TLS but failed with an intolerant error using
     // a different protocol. To give TLS a try on next connection attempt again
     // drop this site from the list of intolerant sites. TLS failure might be 
     // caused only by a traffic congestion while the server is TLS tolerant.
     removeIntolerantSite(key);
     return false;
   }
 
-  PRBool enableSSL3 = false;
-  SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_SSL3, &enableSSL3);
-  if (enableSSL3) {
+  if (socketInfo->IsSSL3Enabled()) {
     // Add this site to the list of TLS intolerant sites.
     addIntolerantSite(key);
   }
   
-  return currentlyUsesTLS;
+  return socketInfo->IsTLSEnabled();
 }
 
 void
-nsSSLIOLayerHelpers::rememberTolerantSite(PRFileDesc* ssl_layer_fd, 
-                                          nsNSSSocketInfo *socketInfo)
+nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
 {
-  PRBool usingSecurity = false;
-  PRBool currentlyUsesTLS = false;
-  SSL_OptionGet(ssl_layer_fd, SSL_SECURITY, &usingSecurity);
-  SSL_OptionGet(ssl_layer_fd, SSL_ENABLE_TLS, &currentlyUsesTLS);
-  if (!usingSecurity || !currentlyUsesTLS) {
+  if (!socketInfo->IsTLSEnabled())
     return;
-  }
 
   nsCAutoString key;
   getSiteKey(socketInfo, key);
 
   MutexAutoLock lock(*mutex);
   nsSSLIOLayerHelpers::mTLSTolerantSites->Put(key);
 }
 
@@ -2019,17 +2003,17 @@ PRInt32 checkHandshake(PRInt32 bytesTran
       if (PR_WOULD_BLOCK_ERROR == err) {
         socketInfo->SetHandshakeInProgress(true);
         return bytesTransfered;
       }
 
       if (!wantRetry // no decision yet
           && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
       {
-        wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
+        wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
       }
     }
     
     // This is the common place where we trigger non-cert-errors on a SSL
     // socket. This might be reached at any time of the connection.
     //
     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
     // do the synchronous dispatch to the main thread unnecessarily after we've
@@ -2047,17 +2031,17 @@ PRInt32 checkHandshake(PRInt32 bytesTran
   else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
   {
     if (handleHandshakeResultNow)
     {
       if (!wantRetry // no decision yet
           && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
       {
         wantRetry = 
-          nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(ssl_layer_fd, socketInfo);
+          nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
       }
     }
   }
 
   if (wantRetry) {
     // We want to cause the network layer to retry the connection.
     PR_SetError(PR_CONNECT_RESET_ERROR, 0);
     if (wasReading)
@@ -3439,235 +3423,16 @@ done:
   *mPRetCert = cert;
   *mPRetKey = privKey;
 
   if (mRV == SECFailure) {
     mErrorCodeToReport = error;
   }
 }
 
-class CertErrorRunnable : public SyncRunnableBase
-{
- public:
-  CertErrorRunnable(const void * fdForLogging,
-                    nsIX509Cert * cert,
-                    nsNSSSocketInfo * infoObject,
-                    PRErrorCode defaultErrorCodeToReport,
-                    PRUint32 collectedErrors,
-                    PRErrorCode errorCodeTrust,
-                    PRErrorCode errorCodeMismatch,
-                    PRErrorCode errorCodeExpired)
-    : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
-      mDefaultErrorCodeToReport(defaultErrorCodeToReport),
-      mCollectedErrors(collectedErrors),
-      mErrorCodeTrust(errorCodeTrust),
-      mErrorCodeMismatch(errorCodeMismatch),
-      mErrorCodeExpired(errorCodeExpired)
-  {
-  }
-
-  NS_DECL_NSIRUNNABLE
-  virtual void RunOnTargetThread();
-  nsCOMPtr<nsIRunnable> mResult; // out
-private:
-  SSLServerCertVerificationResult* CheckCertOverrides();
-  
-  const void * const mFdForLogging; // may become an invalid pointer; do not dereference
-  const nsCOMPtr<nsIX509Cert> mCert;
-  const nsRefPtr<nsNSSSocketInfo> mInfoObject;
-  const PRErrorCode mDefaultErrorCodeToReport;
-  const PRUint32 mCollectedErrors;
-  const PRErrorCode mErrorCodeTrust;
-  const PRErrorCode mErrorCodeMismatch;
-  const PRErrorCode mErrorCodeExpired;
-};
-
-namespace mozilla { namespace psm {
-
-// Returns SECSuccess if it dispatched the CertErrorRunnable. In that case,
-// the caller should NOT dispatch its own SSLServerCertVerificationResult;
-// the CertErrorRunnable will do it instead.
-//
-// Returns SECFailure with the error code set if it does not dispatch the
-// CertErrorRunnable. In that case, the caller should dispatch its own 
-// SSLServerCertVerificationResult with the error code from PR_GetError().
-SECStatus
-HandleBadCertificate(PRErrorCode defaultErrorCodeToReport,
-                    nsNSSSocketInfo * socketInfo, CERTCertificate & cert,
-                    const void * fdForLogging,
-                    const nsNSSShutDownPreventionLock & /*proofOfLock*/)
-{
-  // cert was revoked, don't do anything else
-  if (defaultErrorCodeToReport == SEC_ERROR_REVOKED_CERTIFICATE) {
-    PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
-    return SECFailure;
-  }
-
-  if (defaultErrorCodeToReport == 0) {
-    NS_ERROR("No error code set during certificate validation failure.");
-    PR_SetError(PR_INVALID_STATE_ERROR, 0);
-    return SECFailure;
-  }
-
-  nsRefPtr<nsNSSCertificate> nssCert;
-  nssCert = nsNSSCertificate::Create(&cert);
-  if (!nssCert) {
-    NS_ERROR("nsNSSCertificate::Create failed in DispatchCertErrorRunnable");
-    PR_SetError(SEC_ERROR_NO_MEMORY, 0);
-    return SECFailure;
-  }
-
-  SECStatus srv;
-  nsresult nsrv;
-
-  nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
-  if (!inss) {
-    NS_ERROR("do_GetService(kNSSComponentCID) failed in DispatchCertErrorRunnable");
-    PR_SetError(defaultErrorCodeToReport, 0);
-    return SECFailure;
-  }
-
-  nsRefPtr<nsCERTValInParamWrapper> survivingParams;
-  nsrv = inss->GetDefaultCERTValInParam(survivingParams);
-  if (NS_FAILED(nsrv)) {
-    NS_ERROR("GetDefaultCERTValInParam failed in DispatchCertErrorRunnable");
-    PR_SetError(defaultErrorCodeToReport, 0);
-    return SECFailure;
-  }
-  
-  PRArenaPool *log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-  PRArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
-  if (!log_arena) {
-    NS_ERROR("PORT_NewArena failed in DispatchCertErrorRunnable");
-    return SECFailure; // PORT_NewArena set error code
-  }
-
-  CERTVerifyLog *verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
-  if (!verify_log) {
-    NS_ERROR("PORT_ArenaZNew failed in DispatchCertErrorRunnable");
-    return SECFailure; // PORT_ArenaZNew set error code
-  }
-  CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
-  verify_log->arena = log_arena;
-
-  if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
-    srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), &cert,
-                                true, certificateUsageSSLServer,
-                                PR_Now(), static_cast<void*>(socketInfo),
-                                verify_log, NULL);
-  }
-  else {
-    CERTValOutParam cvout[2];
-    cvout[0].type = cert_po_errorLog;
-    cvout[0].value.pointer.log = verify_log;
-    cvout[1].type = cert_po_end;
-
-    srv = CERT_PKIXVerifyCert(&cert, certificateUsageSSLServer,
-                              survivingParams->GetRawPointerForNSS(),
-                              cvout, static_cast<void*>(socketInfo));
-  }
-
-  // We ignore the result code of the cert verification.
-  // Either it is a failure, which is expected, and we'll process the
-  //                         verify log below.
-  // Or it is a success, then a domain mismatch is the only 
-  //                     possible failure. 
-
-  PRErrorCode errorCodeMismatch = 0;
-  PRErrorCode errorCodeTrust = 0;
-  PRErrorCode errorCodeExpired = 0;
-
-  PRUint32 collected_errors = 0;
-
-  if (socketInfo->IsCertIssuerBlacklisted()) {
-    collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
-    errorCodeTrust = defaultErrorCodeToReport;
-  }
-
-  // Check the name field against the desired hostname.
-  if (CERT_VerifyCertName(&cert, socketInfo->GetHostName()) != SECSuccess) {
-    collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
-    errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
-  }
-
-  CERTVerifyLogNode *i_node;
-  for (i_node = verify_log->head; i_node; i_node = i_node->next)
-  {
-    switch (i_node->error)
-    {
-      case SEC_ERROR_UNKNOWN_ISSUER:
-      case SEC_ERROR_CA_CERT_INVALID:
-      case SEC_ERROR_UNTRUSTED_ISSUER:
-      case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
-      case SEC_ERROR_UNTRUSTED_CERT:
-      case SEC_ERROR_INADEQUATE_KEY_USAGE:
-        // We group all these errors as "cert not trusted"
-        collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
-        if (errorCodeTrust == SECSuccess) {
-          errorCodeTrust = i_node->error;
-        }
-        break;
-      case SSL_ERROR_BAD_CERT_DOMAIN:
-        collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
-        if (errorCodeMismatch == SECSuccess) {
-          errorCodeMismatch = i_node->error;
-        }
-        break;
-      case SEC_ERROR_EXPIRED_CERTIFICATE:
-        collected_errors |= nsICertOverrideService::ERROR_TIME;
-        if (errorCodeExpired == SECSuccess) {
-          errorCodeExpired = i_node->error;
-        }
-        break;
-      default:
-        PR_SetError(i_node->error, 0);
-        return SECFailure;
-    }
-  }
-
-  if (!collected_errors)
-  {
-    // This will happen when CERT_*Verify* only returned error(s) that are
-    // not on our whitelist of overridable certificate errors.
-    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
-           fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
-    PR_SetError(defaultErrorCodeToReport, 0);
-    return SECFailure;
-  }
-
-  socketInfo->SetStatusErrorBits(*nssCert, collected_errors);
-
-  nsRefPtr<CertErrorRunnable> runnable =
-    new CertErrorRunnable(fdForLogging, 
-                          static_cast<nsIX509Cert*>(nssCert.get()),
-                          socketInfo, defaultErrorCodeToReport, 
-                          collected_errors, errorCodeTrust, 
-                          errorCodeMismatch, errorCodeExpired);
-
-  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
-          ("[%p][%p] Before dispatching CertErrorRunnable\n",
-          fdForLogging, runnable.get()));
-
-  nsresult nrv;
-  nsCOMPtr<nsIEventTarget> stsTarget
-    = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
-  if (NS_SUCCEEDED(nrv)) {
-    nrv = stsTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
-  }
-  if (NS_FAILED(nrv)) {
-    NS_ERROR("Failed to dispatch CertErrorRunnable");
-    PR_SetError(defaultErrorCodeToReport, 0);
-    return SECFailure;
-  }
-
-  return SECSuccess;
-}
-
-} } // namespace mozilla::psm
-
 void
 nsNSSSocketInfo::SetStatusErrorBits(nsIX509Cert & cert,
                                     PRUint32 collected_errors)
 {
   MutexAutoLock lock(mMutex);
 
   if (!mSSLStatus)
     mSSLStatus = new nsSSLStatus();
@@ -3681,172 +3446,16 @@ nsNSSSocketInfo::SetStatusErrorBits(nsIX
     collected_errors & nsICertOverrideService::ERROR_TIME;
   mSSLStatus->mIsUntrusted = 
     collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
 
   nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
     this, mSSLStatus, SECFailure);
 }
 
-SSLServerCertVerificationResult *
-CertErrorRunnable::CheckCertOverrides()
-{
-  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CertErrorRunnable::Run\n",
-                                    mFdForLogging, this));
-
-  if (!NS_IsMainThread()) {
-    NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
-    return new SSLServerCertVerificationResult(*mInfoObject,
-                                               mDefaultErrorCodeToReport);
-  }
-
-  PRInt32 port;
-  mInfoObject->GetPort(&port);
-
-  nsCString hostWithPortString;
-  hostWithPortString.AppendASCII(mInfoObject->GetHostName());
-  hostWithPortString.AppendLiteral(":");
-  hostWithPortString.AppendInt(port);
-
-  PRUint32 remaining_display_errors = mCollectedErrors;
-
-  nsresult nsrv;
-
-  // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
-  // connections must be dropped when there are any certificate errors
-  // (STS Spec section 7.3).
-  bool strictTransportSecurityEnabled = false;
-  nsCOMPtr<nsIStrictTransportSecurityService> stss
-    = do_GetService(NS_STSSERVICE_CONTRACTID, &nsrv);
-  if (NS_SUCCEEDED(nsrv)) {
-    nsrv = stss->IsStsHost(mInfoObject->GetHostName(),
-                           &strictTransportSecurityEnabled);
-  }
-  if (NS_FAILED(nsrv)) {
-    return new SSLServerCertVerificationResult(*mInfoObject,
-                                               mDefaultErrorCodeToReport);
-  }
-
-  if (!strictTransportSecurityEnabled) {
-    nsCOMPtr<nsICertOverrideService> overrideService =
-      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
-    // it is fine to continue without the nsICertOverrideService
-
-    PRUint32 overrideBits = 0;
-
-    if (overrideService)
-    {
-      bool haveOverride;
-      bool isTemporaryOverride; // we don't care
-      nsCString hostString(mInfoObject->GetHostName());
-      nsrv = overrideService->HasMatchingOverride(hostString, port,
-                                                  mCert,
-                                                  &overrideBits,
-                                                  &isTemporaryOverride, 
-                                                  &haveOverride);
-      if (NS_SUCCEEDED(nsrv) && haveOverride) 
-      {
-       // remove the errors that are already overriden
-        remaining_display_errors -= overrideBits;
-      }
-    }
-
-    if (!remaining_display_errors) {
-      // all errors are covered by override rules, so let's accept the cert
-      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
-             ("[%p][%p] All errors covered by override rules\n",
-             mFdForLogging, this));
-      return new SSLServerCertVerificationResult(*mInfoObject, 0);
-    }
-  } else {
-    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
-           ("[%p][%p] Strict-Transport-Security is violated: untrusted "
-            "transport layer\n", mFdForLogging, this));
-  }
-
-  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
-         ("[%p][%p] Certificate error was not overridden\n",
-         mFdForLogging, this));
-
-  // Ok, this is a full stop.
-  // First, deliver the technical details of the broken SSL status.
-
-  // Try to get a nsIBadCertListener2 implementation from the socket consumer.
-  nsCOMPtr<nsIInterfaceRequestor> cb;
-  mInfoObject->GetNotificationCallbacks(getter_AddRefs(cb));
-  if (cb) {
-    nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
-    if (bcl) {
-      nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(mInfoObject);
-      bool suppressMessage = false; // obsolete, ignored
-      nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
-                                    hostWithPortString, &suppressMessage);
-    }
-  }
-
-  nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService = 
-    do_GetService(NS_RECENTBADCERTS_CONTRACTID);
- 
-  if (recentBadCertsService) {
-    NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
-    recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
-                                      mInfoObject->SSLStatus());
-  }
-
-  // pick the error code to report by priority
-  PRErrorCode errorCodeToReport = mErrorCodeTrust    ? mErrorCodeTrust
-                                : mErrorCodeMismatch ? mErrorCodeMismatch
-                                : mErrorCodeExpired  ? mErrorCodeExpired
-                                : mDefaultErrorCodeToReport;
-
-  return new SSLServerCertVerificationResult(*mInfoObject, errorCodeToReport,
-                                             OverridableCertErrorMessage);
-}
-
-NS_IMETHODIMP
-CertErrorRunnable::Run()
-{
-  // This code is confusing: First, Run() is called on the socket transport
-  // thread. Then we re-dispatch it to the main thread synchronously (step 1).
-  // On the main thread, we call CheckCertOverrides (step 2). Then we return
-  // from the main thread and are back on the socket transport thread. There,
-  // we run the result runnable directly (step 3).
-  if (!NS_IsMainThread()) {
-    // We are running on the socket transport thread. We need to re-dispatch
-    // ourselves synchronously to the main thread.
-    DispatchToMainThreadAndWait(); // step 1
-
-    // step 3
-    if (!mResult) {
-      // Either the dispatch failed or CheckCertOverrides wrongly returned null
-      NS_ERROR("Did not create a SSLServerCertVerificationResult");
-      mResult = new SSLServerCertVerificationResult(*mInfoObject,
-                                                    PR_INVALID_STATE_ERROR);
-    }
-    return mResult->Run(); 
-  } else {
-    // block this thread (the socket transport thread) until RunOnTargetThread
-    // is complete.
-    return SyncRunnableBase::Run(); // step 2
-  }
-}
-
-void 
-CertErrorRunnable::RunOnTargetThread()
-{
-  // Now we are running on the main thread, blocking the socket tranposrt
-  // thread. This is exactly the state we need to be in to call
-  // CheckCertOverrides; CheckCertOverrides must block events on both of
-  // these threads because it calls nsNSSSocketInfo::GetInterface(),
-  // which calls nsHttpConnection::GetInterface() through
-  // nsNSSSocketInfo::mCallbacks. nsHttpConnection::GetInterface must always
-  // execute on the main thread, with the socket transport thread blocked.
-  mResult = CheckCertOverrides(); 
-}
- 
 static PRFileDesc*
 nsSSLIOLayerImportFD(PRFileDesc *fd,
                      nsNSSSocketInfo *infoObject,
                      const char *host,
                      bool anonymousLoad)
 {
   nsNSSShutDownPreventionLock locker;
   PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
@@ -3910,16 +3519,26 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, b
     // We assume that protocols that use the STARTTLS mechanism should support
     // modern hellos. For other protocols, if we suspect a site 
     // does not support TLS, let's also use V2 hellos.
     // One advantage of this approach, if a site only supports the older
     // hellos, it is more likely that we will get a reasonable error code
     // on our single retry attempt.
   }
 
+  PRBool enabled;
+  if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
+    return NS_ERROR_FAILURE;
+  }
+  infoObject->SetSSL3Enabled(enabled);
+  if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
+    return NS_ERROR_FAILURE;
+  }
+  infoObject->SetTLSEnabled(enabled);
+
   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
     return NS_ERROR_FAILURE;
   }
   
   if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
     if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
       return NS_ERROR_FAILURE;
     }
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -172,17 +172,20 @@ public:
               ::mozilla::psm::SSLErrorMessageType errorMessageType);
   
   // for logging only
   PRBool IsWaitingForCertVerification() const
   {
     return mCertVerificationState == waiting_for_cert_verification;
   }
   
-
+  bool IsSSL3Enabled() const { return mSSL3Enabled; }
+  void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; }
+  bool IsTLSEnabled() const { return mTLSEnabled; }
+  void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; }
 protected:
   mutable ::mozilla::Mutex mMutex;
 
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   PRFileDesc* mFd;
   CertVerificationState mCertVerificationState;
   PRIntervalTime mCertVerificationStarted;
   PRIntervalTime mCertVerificationEnded;
@@ -196,16 +199,18 @@ protected:
   PRErrorCode mErrorCode;
   ::mozilla::psm::SSLErrorMessageType mErrorMessageType;
   nsString mErrorMessageCached;
   nsresult formatErrorMessage(::mozilla::MutexAutoLock const & proofOfLock);
 
   bool mDocShellDependentStuffKnown;
   bool mExternalErrorReporting; // DocShellDependent
   bool mForSTARTTLS;
+  bool mSSL3Enabled;
+  bool mTLSEnabled;
   bool mHandshakePending;
   bool mHasCleartextPhase;
   bool mHandshakeInProgress;
   bool mAllowTLSIntoleranceTimeout;
   bool mRememberClientAuthCertificate;
   PRIntervalTime mHandshakeStartTime;
   PRInt32 mPort;
   nsXPIDLCString mHostName;
@@ -275,18 +280,18 @@ public:
 
   static void setTreatUnsafeNegotiationAsBroken(bool broken);
   static bool treatUnsafeNegotiationAsBroken();
 
   static void setWarnLevelMissingRFC5746(PRInt32 level);
   static PRInt32 getWarnLevelMissingRFC5746();
 
   static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
-  static bool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
-  static void rememberTolerantSite(PRFileDesc* ssl_layer_fd, nsNSSSocketInfo *socketInfo);
+  static bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
+  static void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
 
   static void addIntolerantSite(const nsCString &str);
   static void removeIntolerantSite(const nsCString &str);
   static bool isKnownAsIntolerantSite(const nsCString &str);
 
   static void setRenegoUnrestrictedSites(const nsCString &str);
   static bool isRenegoUnrestrictedSite(const nsCString &str);
 };
--- a/toolkit/components/satchel/test/test_bug_511615.html
+++ b/toolkit/components/satchel/test/test_bug_511615.html
@@ -7,17 +7,17 @@
   <script type="text/javascript" src="satchel_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Form History test: form field autocomplete
 <p id="display"></p>
 
 <!-- we presumably can't hide the content for this test. -->
-<div id="content" style="direction: rtl;">
+<div id="content">
   <!-- unused -->
   <form id="unused" onsubmit="return false;">
     <input  type="text" name="field1" value="unused">
   </form>
 
   <!-- normal, basic form -->
   <form id="form1" onsubmit="return false;">
     <input  type="text" name="field1">
@@ -27,17 +27,16 @@ Form History test: form field autocomple
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Form History autocomplete **/
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
 var autocompletePopup = getAutocompletePopup();
-autocompletePopup.style.direction = "ltr";
 
 var input = $_(1, "field1");
 
 // Get the form history service
 var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
          getService(Components.interfaces.nsIFormHistory2);
 ok(fh != null, "got form history service");
 
@@ -362,17 +361,16 @@ function runTest(testNum) {
     case 210:
         // Need to use doKey(), even though this test is not privileged.
         doKey("escape");
         nextTestPrivledged = true;
         break;
     case 211:
         checkPopupOpen(false);
         checkForm("");
-        is(autocompletePopup.style.direction, "rtl", "direction should have been changed from ltr to rtl");
 
         SimpleTest.finish();
         return;
 
     default:
         ok(false, "Unexpected invocation of test #" + testNum);
         SimpleTest.finish();
         return;
--- a/toolkit/content/tests/chrome/Makefile.in
+++ b/toolkit/content/tests/chrome/Makefile.in
@@ -67,16 +67,17 @@ include $(topsrcdir)/config/rules.mk
 		bug451286_window.xul \
 		test_bug451286.xul \
 		bug451540_window.xul \
 		test_bug451540.xul \
 		test_bug471776.xul \
 		test_bug570192.xul \
 		test_bug624329.xul \
 		bug624329_window.xul \
+		test_bug649840.xul \
 		test_popup_preventdefault_chrome.xul \
 		window_popup_preventdefault_chrome.xul \
 		test_largemenu.xul \
 		window_largemenu.xul \
 		test_popup_anchor.xul \
 		window_popup_anchor.xul \
 		frame_popup_anchor.xul \
 		test_preferences.xul \
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_bug649840.xul
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=649840
+-->
+<window title="Mozilla Bug 649840" 
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <textbox id="textLTR" type="autocomplete" autocompletesearch="simple"/>
+  <textbox id="textRTL" type="autocomplete" autocompletesearch="simple"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=649840"
+     target="_blank">Mozilla Bug 649840</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+/** Test for Bug 649840 **/
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+function runTest()
+{
+  var textLTR = $("textLTR");
+  var textRTL = $("textRTL");
+
+  textLTR.style.direction = "ltr";
+  textRTL.style.direction = "rtl";
+
+  textLTR.value="abcd";
+  textRTL.value="ابجد";
+
+  // open and close the popups to update the popupdir attribute value
+  textLTR.openPopup();
+  textLTR.closePopup();
+  textRTL.openPopup();
+  textRTL.closePopup();
+  
+  is(textLTR.popup.style.direction, textLTR.style.direction, "LTR textbox test fails");
+  is(textRTL.popup.style.direction, textRTL.style.direction, "RTL textbox test fails");
+
+  // switch directions of the two textboxes
+  textLTR.style.direction = "rtl";
+  textRTL.style.direction = "ltr";
+
+  // open and close the popups to update the popupdir attribute value
+  textLTR.openPopup();
+  textLTR.closePopup();
+  textRTL.openPopup();
+  textRTL.closePopup();
+
+  is(textLTR.popup.style.direction, textLTR.style.direction, "RTL-switched textbox test fails");
+  is(textRTL.popup.style.direction, textRTL.style.direction, "LTR-switched textbox test fails");
+
+  SimpleTest.finish();
+}
+
+  ]]>
+  </script>
+</window>
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -421,16 +421,20 @@ endif
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += \
   -lui \
   -lmedia \
   -lhardware_legacy \
   -lhardware \
   -lutils \
+  -lcutils \
+  -lcamera \
+  -lcamera_client \
+  -lbinder \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)
 
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -757,17 +757,17 @@ var AddonManagerInternal = {
 
       pendingUpdates++;
       this.getAllAddons(function getAddonsCallback(aAddons) {
         // If there is a known hotfix then exclude it from the list of add-ons to update.
         var ids = [a.id for each (a in aAddons) if (a.id != hotfixID)];
 
         // Repopulate repository cache first, to ensure compatibility overrides
         // are up to date before checking for addon updates.
-        scope.AddonRepository.repopulateCache(ids, function BUC_repopulateCacheCallback() {
+        scope.AddonRepository.backgroundUpdateCheck(ids, function BUC_backgroundUpdateCheckCallback() {
           AddonManagerInternal.updateAddonRepositoryData(function BUC_updateAddonCallback() {
 
             pendingUpdates += aAddons.length;
             aAddons.forEach(function BUC_forEachCallback(aAddon) {
               if (aAddon.id == hotfixID) {
                 notifyComplete();
                 return;
               }
--- a/toolkit/mozapps/extensions/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/AddonRepository.jsm
@@ -52,16 +52,17 @@ Components.utils.import("resource://gre/
 
 var EXPORTED_SYMBOLS = [ "AddonRepository" ];
 
 const PREF_GETADDONS_CACHE_ENABLED       = "extensions.getAddons.cache.enabled";
 const PREF_GETADDONS_CACHE_TYPES         = "extensions.getAddons.cache.types";
 const PREF_GETADDONS_CACHE_ID_ENABLED    = "extensions.%ID%.getAddons.cache.enabled"
 const PREF_GETADDONS_BROWSEADDONS        = "extensions.getAddons.browseAddons";
 const PREF_GETADDONS_BYIDS               = "extensions.getAddons.get.url";
+const PREF_GETADDONS_BYIDS_PERFORMANCE   = "extensions.getAddons.getWithPerformance.url";
 const PREF_GETADDONS_BROWSERECOMMENDED   = "extensions.getAddons.recommended.browseURL";
 const PREF_GETADDONS_GETRECOMMENDED      = "extensions.getAddons.recommended.url";
 const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
 const PREF_GETADDONS_GETSEARCHRESULTS    = "extensions.getAddons.search.url";
 
 const PREF_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility";
 
 const BRANCH_REGEXP                   = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
@@ -605,16 +606,20 @@ var AddonRepository = {
    * the cache is completely removed.
    *
    * @param  aIds
    *         The array of add-on ids to repopulate the cache with
    * @param  aCallback
    *         The optional callback to call once complete
    */
   repopulateCache: function(aIds, aCallback) {
+    this._repopulateCache(aIds, aCallback, false);
+  },
+
+  _repopulateCache: function(aIds, aCallback, aSendPerformance) {
     // Completely remove cache if caching is not enabled
     if (!this.cacheEnabled) {
       this._addons = null;
       this._pendingCallbacks = null;
       AddonDatabase.delete(aCallback);
       return;
     }
 
@@ -623,28 +628,28 @@ var AddonRepository = {
       // Completely remove cache if there are no add-ons to cache
       if (aAddons.length == 0) {
         self._addons = null;
         self._pendingCallbacks = null;
         AddonDatabase.delete(aCallback);
         return;
       }
 
-      self.getAddonsByIDs(aAddons, {
+      self._beginGetAddons(aAddons, {
         searchSucceeded: function(aAddons) {
           self._addons = {};
           aAddons.forEach(function(aAddon) { self._addons[aAddon.id] = aAddon; });
           AddonDatabase.repopulate(aAddons, aCallback);
         },
         searchFailed: function() {
           WARN("Search failed when repopulating cache");
           if (aCallback)
             aCallback();
         }
-      });
+      }, aSendPerformance);
     });
   },
 
   /**
    * Asynchronously add add-ons to the cache corresponding to the specified
    * ids. If caching is disabled, the cache is unchanged and the callback is
    * immediatly called if it is defined.
    *
@@ -742,24 +747,66 @@ var AddonRepository = {
    * passed to the given callback.
    *
    * @param  aIDs
    *         The array of ids to search for
    * @param  aCallback
    *         The callback to pass results to
    */
   getAddonsByIDs: function(aIDs, aCallback) {
+    return this._beginGetAddons(aIDs, aCallback, false);
+  },
+
+  /**
+   * Begins a search of add-ons, potentially sending performance data.
+   *
+   * @param  aIDs
+   *         Array of ids to search for.
+   * @param  aCallback
+   *         Function to pass results to.
+   * @param  aSendPerformance
+   *         Boolean indicating whether to send performance data with the
+   *         request.
+   */
+  _beginGetAddons: function(aIDs, aCallback, aSendPerformance) {
     let ids = aIDs.slice(0);
 
     let params = {
       API_VERSION : API_VERSION,
       IDS : ids.map(encodeURIComponent).join(',')
     };
 
-    let url = this._formatURLPref(PREF_GETADDONS_BYIDS, params);
+    let pref = PREF_GETADDONS_BYIDS;
+
+    if (aSendPerformance) {
+      let type = Services.prefs.getPrefType(PREF_GETADDONS_BYIDS_PERFORMANCE);
+      if (type == Services.prefs.PREF_STRING) {
+        pref = PREF_GETADDONS_BYIDS_PERFORMANCE;
+
+        let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].
+                          getService(Ci.nsIAppStartup).
+                          getStartupInfo();
+
+        if (startupInfo.process) {
+          if (startupInfo.main) {
+            params.TIME_MAIN = startupInfo.main - startupInfo.process;
+          }
+          if (startupInfo.firstPaint) {
+            params.TIME_FIRST_PAINT = startupInfo.firstPaint -
+                                      startupInfo.process;
+          }
+          if (startupInfo.sessionRestored) {
+            params.TIME_SESSION_RESTORED = startupInfo.sessionRestored -
+                                           startupInfo.process;
+          }
+        }
+      }
+    }
+
+    let url = this._formatURLPref(pref, params);
 
     let self = this;
     function handleResults(aElements, aTotalResults, aCompatData) {
       // Don't use this._parseAddons() so that, for example,
       // incompatible add-ons are not filtered out
       let results = [];
       for (let i = 0; i < aElements.length && results.length < self._maxResults; i++) {
         let result = self._parseAddon(aElements[i], null, aCompatData);
@@ -797,16 +844,33 @@ var AddonRepository = {
       // aTotalResults irrelevant
       self._reportSuccess(results, -1);
     }
 
     this._beginSearch(url, ids.length, aCallback, handleResults);
   },
 
   /**
+   * Performs the daily background update check.
+   *
+   * This API both searches for the add-on IDs specified and sends performance
+   * data. It is meant to be called as part of the daily update ping. It should
+   * not be used for any other purpose. Use repopulateCache instead.
+   *
+   * @param  aIDs
+   *         Array of add-on IDs to repopulate the cache with.
+   * @param  aCallback
+   *         Function to call when data is received. Function must be an object
+   *         with the keys searchSucceeded and searchFailed.
+   */
+  backgroundUpdateCheck: function(aIDs, aCallback) {
+    this._repopulateCache(aIDs, aCallback, true);
+  },
+
+  /**
    * Begins a search for recommended add-ons in this repository. Results will
    * be passed to the given callback.
    *
    * @param  aMaxResults
    *         The maximum number of results to return
    * @param  aCallback
    *         The callback to pass results to
    */
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -197,16 +197,34 @@ var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{
     Components.utils.import("resource://gre/modules/AddonLogging.jsm");
 
     LogManager.getLogger("addons.xpi", this);
     return this[aName];
   })
 }, this);
 
 /**
+ * Sets permissions on a file
+ *
+ * @param  aFile
+ *         The file or directory to operate on.
+ * @param  aPermissions
+ *         The permisions to set
+ */
+function setFilePermissions(aFile, aPermissions) {
+  try {
+    aFile.permissions = aPermissions;
+  }
+  catch (e) {
+    WARN("Failed to set permissions " + aPermissions.toString(8) + " on " +
+         aFile.path, e);
+  }
+}
+
+/**
  * A safe way to install a file or the contents of a directory to a new
  * directory. The file or directory is moved or copied recursively and if
  * anything fails an attempt is made to rollback the entire operation. The
  * operation may also be rolled back to its original state after it has
  * completed by calling the rollback method.
  *
  * Operations can be chained. Calling move or copy multiple times will remember
  * the whole set and if one fails all of the operations will be rolled back.
@@ -274,17 +292,17 @@ SafeInstallOperation.prototype = {
 
     // If this is only a copy operation then there is nothing else to do
     if (aCopy)
       return;
 
     // The directory should be empty by this point. If it isn't this will throw
     // and all of the operations will be rolled back
     try {
-      aDirectory.permissions = FileUtils.PERMS_DIRECTORY;
+      setFilePermissions(aDirectory, FileUtils.PERMS_DIRECTORY);
       aDirectory.remove(false);
     }
     catch (e) {
       ERROR("Failed to remove directory " + aDirectory.path, e);
       throw e;
     }
 
     // Note we put the directory move in after all the file moves so the
@@ -1080,17 +1098,23 @@ function extractFiles(aZipFile, aDir) {
     entries = zipReader.findEntries(null);
     while (entries.hasMore()) {
       let entryName = entries.getNext();
       let target = getTargetFile(aDir, entryName);
       if (target.exists())
         continue;
 
       zipReader.extract(entryName, target);
-      target.permissions |= FileUtils.PERMS_FILE;
+      try {
+        target.permissions |= FileUtils.PERMS_FILE;
+      }
+      catch (e) {
+        WARN("Failed to set permissions " + aPermissions.toString(8) + " on " +
+             target.path, e);
+      }
     }
   }
   finally {
     zipReader.close();
   }
 }
 
 /**
@@ -1247,34 +1271,34 @@ function cleanStagingDir(aDir, aLeafName
     if (dirEntries.nextFile)
       return;
   }
   finally {
     dirEntries.close();
   }
 
   try {
-    aDir.permissions = FileUtils.PERMS_DIRECTORY;
+    setFilePermissions(aDir, FileUtils.PERMS_DIRECTORY);
     aDir.remove(false);
   }
   catch (e) {
     WARN("Failed to remove staging dir", e);
     // Failing to remove the staging directory is ignorable
   }
 }
 
 /**
  * Recursively removes a directory or file fixing permissions when necessary.
  *
  * @param  aFile
  *         The nsIFile to remove
  */
 function recursiveRemove(aFile) {
-  aFile.permissions = aFile.isDirectory() ? FileUtils.PERMS_DIRECTORY
-                                          : FileUtils.PERMS_FILE;
+  setFilePermissions(aFile, aFile.isDirectory() ? FileUtils.PERMS_DIRECTORY
+                                                : FileUtils.PERMS_FILE);
 
   try {
     aFile.remove(true);
     return;
   }
   catch (e) {
     if (!aFile.isDirectory()) {
       ERROR("Failed to remove file " + aFile.path, e);
@@ -8071,17 +8095,21 @@ DirectoryInstallLocation.prototype = {
       }
       catch (e) {
         WARN("Failed to remove trash directory when installing " + aId, e);
       }
     }
 
     let newFile = this._directory.clone().QueryInterface(Ci.nsILocalFile);
     newFile.append(aSource.leafName);
-    newFile.lastModifiedTime = Date.now();
+    try {
+      newFile.lastModifiedTime = Date.now();
+    } catch (e)  {
+      WARN("failed to set lastModifiedTime on " + newFile.path, e);
+    }
     this._FileToIDMap[newFile.path] = aId;
     this._IDToFileMap[aId] = newFile;
 
     if (aExistingAddonID && aExistingAddonID != aId &&
         aExistingAddonID in this._IDToFileMap) {
       delete this._FileToIDMap[this._IDToFileMap[aExistingAddonID]];
       delete this._IDToFileMap[aExistingAddonID];
     }
--- a/toolkit/mozapps/extensions/test/browser/Makefile.in
+++ b/toolkit/mozapps/extensions/test/browser/Makefile.in
@@ -91,16 +91,17 @@ include $(DEPTH)/config/autoconf.mk
   browser_openDialog.js \
   browser_types.js \
   browser_inlinesettings.js \
   browser_tabsettings.js \
   $(NULL)
 
 _TEST_FILES = \
   head.js \
+  browser_addonrepository_performance.js \
   browser_bug557956.js \
   browser_bug616841.js \
   browser_hotfix.js \
   browser_updatessl.js \
   browser_installssl.js \
   browser_newaddon.js \
   browser_select_selection.js \
   browser_select_compatoverrides.js \
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_addonrepository_performance.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the metadata request includes startup time measurements
+
+Components.utils.import("resource://gre/modules/AddonRepository.jsm");
+
+var gManagerWindow;
+var gProvider;
+
+function parseParams(aQuery) {
+  let params = {};
+
+  aQuery.split("&").forEach(function(aParam) {
+    let [key, value] = aParam.split("=");
+    params[key] = value;
+  });
+
+  return params;
+}
+
+function test() {
+  waitForExplicitFinish();
+
+  var gSeenRequest = false;
+
+  gProvider = new MockProvider();
+  gProvider.createAddons([{
+    id: "test1@tests.mozilla.org",
+    name: "Test add-on"
+  }]);
+
+  function observe(aSubject, aTopic, aData) {
+    aSubject.QueryInterface(Ci.nsIChannel);
+    let url = aSubject.URI.QueryInterface(Ci.nsIURL);
+    if (url.filePath != "/extensions-dummy/metadata") {
+      return;
+    }
+    info(url.query);
+
+    let params = parseParams(url.query);
+
+    is(params.appOS, Services.appinfo.OS, "OS should be correct");
+    is(params.appVersion, Services.appinfo.version, "Version should be correct");
+    ok(params.tMain >= 0, "Should be a sensible tMain");
+    ok(params.tFirstPaint >= 0, "Should be a sensible tFirstPaint");
+    ok(params.tSessionRestored >= 0, "Should be a sensible tSessionRestored");
+
+    gSeenRequest = true;
+  }
+
+  const PREF = "extensions.getAddons.getWithPerformance.url";
+
+  // Watch HTTP requests
+  Services.obs.addObserver(observe, "http-on-modify-request", false);
+  Services.prefs.setCharPref(PREF,
+    "http://127.0.0.1:8888/extensions-dummy/metadata?appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
+
+  registerCleanupFunction(function() {
+    Services.obs.removeObserver(observe, "http-on-modify-request");
+  });
+
+  AddonRepository._beginGetAddons(["test1@tests.mozilla.org"], {
+    searchFailed: function() {
+      ok(gSeenRequest, "Should have seen metadata request");
+      finish();
+    }
+  }, true);
+}
+
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -50,16 +50,17 @@ var gTestsRun = 0;
 var gTestStart = null;
 
 var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window);
 
 var gRestorePrefs = [{name: PREF_LOGGING_ENABLED},
                      {name: "extensions.webservice.discoverURL"},
                      {name: "extensions.update.url"},
                      {name: "extensions.getAddons.get.url"},
+                     {name: "extensions.getAddons.getWithPerformance.url"},
                      {name: "extensions.getAddons.search.browseURL"},
                      {name: "extensions.getAddons.search.url"},
                      {name: "extensions.getAddons.cache.enabled"},
                      {name: PREF_SEARCH_MAXRESULTS},
                      {name: PREF_STRICT_COMPAT},
                      {name: PREF_CHECK_COMPATIBILITY}];
 
 gRestorePrefs.forEach(function(aPref) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
@@ -10,16 +10,17 @@ do_load_httpd_js();
 let gServer;
 
 const PORT      = 4444;
 const BASE_URL  = "http://localhost:" + PORT;
 
 const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
 const PREF_GETADDONS_CACHE_TYPES   = "extensions.getAddons.cache.types";
 const PREF_GETADDONS_BYIDS         = "extensions.getAddons.get.url";
+const PREF_GETADDONS_BYIDS_PERF    = "extensions.getAddons.getWithPerformance.url";
 const GETADDONS_RESULTS            = BASE_URL + "/data/test_AddonRepository_cache.xml";
 const GETADDONS_EMPTY              = BASE_URL + "/data/test_AddonRepository_empty.xml";
 const GETADDONS_FAILED             = BASE_URL + "/data/test_AddonRepository_failed.xml";
 
 const FILE_DATABASE = "addons.sqlite";
 const ADDON_NAMES = ["test_AddonRepository_1",
                      "test_AddonRepository_2",
                      "test_AddonRepository_3"];
@@ -699,17 +700,17 @@ function run_test_14() {
       run_test_15();
     });
   });
 }
 
 // Tests that the XPI add-ons correctly use the repository properties when
 // caching is enabled and the repository information is available
 function run_test_15() {
-  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);
+  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS_PERF, GETADDONS_RESULTS);
 
   trigger_background_update(function() {
     AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
       check_results(aAddons, WITH_CACHE);
       run_test_16();
     });
   });
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_compatoverrides.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_compatoverrides.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests compatibility overrides, for when strict compatibility checking is
 // disabled. See bug 693906.
 
 
 const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
-const PREF_GETADDONS_BYIDS         = "extensions.getAddons.get.url";
+const PREF_GETADDONS_BYIDS         = "extensions.getAddons.getWithPerformance.url";
 
 const PORT            = 4444;
 const BASE_URL        = "http://localhost:" + PORT;
 const DEFAULT_URL     = "about:blank";
 const REQ_URL         = "/data.xml";
 
 Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
 Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_update.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_update.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This verifies that add-on update checks work
 
 const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
 const PREF_SELECTED_LOCALE = "general.useragent.locale";
-const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
+const PREF_GETADDONS_BYIDS = "extensions.getAddons.getWithPerformance.url";
 const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
 
 // The test extension uses an insecure update url.
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
 // This test requires lightweight themes update to be enabled even if the app
 // doesn't support lightweight themes.
 Services.prefs.setBoolPref("lightweightThemes.update.enabled", true);
--- a/toolkit/xre/glxtest.cpp
+++ b/toolkit/xre/glxtest.cpp
@@ -226,34 +226,28 @@ static void glxtest()
                         "VENDOR\n%s\nRENDERER\n%s\nVERSION\n%s\nTFP\n%s\n",
                         vendorString,
                         rendererString,
                         versionString,
                         glXBindTexImageEXT ? "TRUE" : "FALSE");
   if (length >= bufsize)
     fatal_error("GL strings length too large for buffer size");
 
-  ///// Check that no X error happened /////
-  // In case of X errors, our X error handler will exit() now.
-  // We really want to make sure that the system is able to create a GL context without generating X errors,
-  // as these would crash the application.
-  XSync(dpy, False);
-  
-  ///// Finally write data to the pipe /////
-  write(write_end_of_the_pipe, buf, length);
-
   ///// Clean up. Indeed, the parent process might fail to kill us (e.g. if it doesn't need to check GL info)
   ///// so we might be staying alive for longer than expected, so it's important to consume as little memory as
   ///// possible. Also we want to check that we're able to do that too without generating X errors.
   glXMakeCurrent(dpy, None, NULL); // must release the GL context before destroying it
   glXDestroyContext(dpy, context);
   glXDestroyPixmap(dpy, glxpixmap);
   XFreePixmap(dpy, pixmap);
   XCloseDisplay(dpy);
   dlclose(libgl);
+
+  ///// Finally write data to the pipe
+  write(write_end_of_the_pipe, buf, length);
 }
 
 /** \returns true in the child glxtest process, false in the parent process */
 bool fire_glxtest_process()
 {
   int pfd[2];
   if (pipe(pfd) == -1) {
       perror("pipe");
--- a/tools/profiler/sps/TableTicker.cpp
+++ b/tools/profiler/sps/TableTicker.cpp
@@ -420,17 +420,17 @@ void TableTicker::HandleSaveRequest()
 }
 
 #ifdef USE_BACKTRACE
 void TableTicker::doBacktrace(Profile &aProfile)
 {
   void *array[100];
   int count = backtrace (array, 100);
 
-  aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
+  aProfile.addTag(ProfileEntry('s', "(root)", 0));
 
   for (int i = 0; i < count; i++) {
     if( (intptr_t)array[i] == -1 ) break;
     aProfile.addTag(ProfileEntry('l', (const char*)array[i]));
   }
 }
 #endif
 
@@ -459,17 +459,17 @@ void TableTicker::doBacktrace(Profile &a
   void* pc_array[1000];
   PCArray array = {
     pc_array,
     mozilla::ArrayLength(pc_array),
     0
   };
   nsresult rv = NS_StackWalk(StackWalkCallback, 0, &array, thread);
   if (NS_SUCCEEDED(rv)) {
-    aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
+    aProfile.addTag(ProfileEntry('s', "(root)", 0));
 
     for (size_t i = array.count; i > 0; --i) {
       aProfile.addTag(ProfileEntry('l', (const char*)array.array[i - 1]));
     }
   }
 }
 #endif
 
--- a/widget/xpwidgets/GfxInfoX11.cpp
+++ b/widget/xpwidgets/GfxInfoX11.cpp
@@ -88,17 +88,18 @@ GfxInfo::GetData()
     enum { buf_size = 1024 };
     char buf[buf_size];
     ssize_t bytesread = read(glxtest_pipe,
                              &buf,
                              buf_size-1); // -1 because we'll append a zero
     close(glxtest_pipe);
     glxtest_pipe = 0;
 
-    // bytesread < 0 would mean that the above read() call failed. This should never happen.
+    // bytesread < 0 would mean that the above read() call failed.
+    // This should never happen. If it did, the outcome would be to blacklist anyway.
     if (bytesread < 0)
         bytesread = 0;
 
     // let buf be a zero-terminated string
     buf[bytesread] = 0;
 
     // Wait for the glxtest process to finish. This serves 2 purposes:
     // * avoid having a zombie glxtest process laying around
@@ -106,20 +107,25 @@ GfxInfo::GetData()
     int glxtest_status = 0;
     bool wait_for_glxtest_process = true;
     bool waiting_for_glxtest_process_failed = false;
     int waitpid_errno = 0;
     while(wait_for_glxtest_process) {
         wait_for_glxtest_process = false;
         if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) {
             waitpid_errno = errno;
-            if (waitpid_errno == EINTR)
+            if (waitpid_errno == EINTR) {
                 wait_for_glxtest_process = true;
-            else
-                waiting_for_glxtest_process_failed = true;
+            } else {
+                // Bug 718629
+                // ECHILD happens when the glxtest process got reaped got reaped after a PR_CreateProcess
+                // as per bug 227246. This shouldn't matter, as we still seem to get the data
+                // from the pipe, and if we didn't, the outcome would be to blacklist anyway.
+                waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
+            }
         }
     }
 
     bool exited_with_error_code = !waiting_for_glxtest_process_failed &&
                                   WIFEXITED(glxtest_status) && 
                                   WEXITSTATUS(glxtest_status) != EXIT_SUCCESS;
     bool received_signal = !waiting_for_glxtest_process_failed &&
                            WIFSIGNALED(glxtest_status);
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -152,16 +152,17 @@
 #include "nsTArray.h"
 #include "mozilla/Services.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIXPConnect.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIMemoryReporter.h"
 #include "xpcpublic.h"
 #include "nsXPCOMPrivate.h"
+#include "sampler.h"
 #include <stdio.h>
 #include <string.h>
 #ifdef WIN32
 #include <io.h>
 #include <process.h>
 #endif
 
 #ifdef XP_WIN
@@ -3834,24 +3835,26 @@ nsCycleCollector_setForgetSkippableCallb
         sCollector->mForgetSkippableCB = aCB;
     }
 }
 
 void
 nsCycleCollector_forgetSkippable()
 {
     if (sCollector) {
+        SAMPLE_LABEL("CC", "nsCycleCollector_forgetSkippable");
         sCollector->ForgetSkippable();
     }
 }
 
 PRUint32
 nsCycleCollector_collect(nsICycleCollectorListener *aListener)
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    SAMPLE_LABEL("CC", "nsCycleCollector_collect");
     nsCOMPtr<nsICycleCollectorListener> listener(aListener);
     if (!aListener && sCollector && sCollector->mParams.mLogGraphs) {
         listener = new nsCycleCollectorLogger();
     }
 
     if (sCollectorRunner)
         return sCollectorRunner->Collect(listener);
     return sCollector ? sCollector->Collect(1, listener) : 0;
@@ -3877,13 +3880,14 @@ nsCycleCollector_shutdownThreads()
 void
 nsCycleCollector_shutdown()
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     NS_ASSERTION(!sCollectorRunner, "Should have finished before!");
     NS_ASSERTION(!sCollectorThread, "Should have finished before!");
 
     if (sCollector) {
+        SAMPLE_LABEL("CC", "nsCycleCollector_shutdown");
         sCollector->Shutdown();
         delete sCollector;
         sCollector = nsnull;
     }
 }
--- a/xpcom/base/nsICycleCollectorListener.idl
+++ b/xpcom/base/nsICycleCollectorListener.idl
@@ -44,17 +44,17 @@
  * beginResults(); then a mixture of describeRoot() for ref counted
  * nodes the CC has identified as roots and describeGarbage() for
  * nodes the CC has identified as garbage.  Ref counted nodes that are
  * not identified as either roots or garbage are neither, and have a
  * known edges count equal to their ref count.  Finally, there will be
  * a call to end().  If begin() returns an error none of the other
  * functions will be called.
  */
-[scriptable, uuid(35a3a9b0-a120-4bf7-9739-46027fe96212)]
+[scriptable, builtinclass, uuid(e7e9a010-d02f-4137-94c8-6d73605fe623)]
 interface nsICycleCollectorListener : nsISupports
 {
     nsICycleCollectorListener allTraces();
     // false if allTraces() has not been called.
     readonly attribute boolean wantAllTraces;
 
     void begin();
     void noteRefCountedObject (in unsigned long long aAddress,