Merge mozilla-central into holly
authorMike Conley <mconley@mozilla.com>
Thu, 05 Dec 2013 13:56:35 -0500
changeset 224563 52c84e6c3056f64492cbc83ec78c39d3cf8df693
parent 224562 7be54d06d846aa5ef581efbec0244b78b0cddd49 (current diff)
parent 158909 118234ab24ed153d6aa2ee0fc03493a9509b8d7d (diff)
child 224564 bd9075540b416542f86bd97d1180959fb0f5996a
push id6
push userryanvm@gmail.com
push dateMon, 12 Jan 2015 22:04:06 +0000
treeherdermozilla-b2g37_v2_2@895c8fc7b734 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
Merge mozilla-central into holly
CLOBBER
dom/tests/mochitest/localstorage/test_cookieSession-phase1.html
dom/tests/mochitest/localstorage/test_cookieSession-phase2.html
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 915533 - Remove unused files under dom/bluetooth.
+Bug 933136 - Windows webidl changes.
--- a/b2g/app/macbuild/Contents/Info.plist.in
+++ b/b2g/app/macbuild/Contents/Info.plist.in
@@ -23,10 +23,14 @@
 	<key>CFBundleSignature</key>
 	<string>MOZB</string>
 	<key>CFBundleVersion</key>
 	<string>%APP_VERSION%</string>
 	<key>NSAppleScriptEnabled</key>
 	<true/>
 	<key>CGDisableCoalescedUpdates</key>
 	<true/>
+	<key>NSHighResolutionCapable</key>
+	<true/>
+	<key>NSPrincipalClass</key>
+	<string>GeckoNSApplication</string>
 </dict>
 </plist>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "adb7896ababd1ccb828e11b05909c0e9ca22594e", 
+    "revision": "1ab9ef0530a59b513469e362eeb060d7b008e6d9", 
     "repo_path": "/integration/gaia-central"
 }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8506,21 +8506,27 @@ static void
 FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
                          bool aFireEvents)
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm)
     return;
 
   for (uint32_t i = 0; i < aDocuments.Length(); ++i) {
+    // NB: Don't bother trying to fire delayed events on documents that were
+    // closed before this event ran.
     if (!aDocuments[i]->EventHandlingSuppressed()) {
       fm->FireDelayedEvents(aDocuments[i]);
       nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell();
       if (shell) {
-        shell->FireOrClearDelayedEvents(aFireEvents);
+        // Only fire events for active documents.
+        bool fire = aFireEvents &&
+                    aDocuments[i]->GetInnerWindow() &&
+                    aDocuments[i]->GetInnerWindow()->IsCurrentInnerWindow();
+        shell->FireOrClearDelayedEvents(fire);
       }
     }
   }
 }
 
 void
 nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr)
 {
--- a/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
+++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
@@ -41,16 +41,17 @@ MediaResourceManagerService::~MediaResou
   mLooper->unregisterHandler(mReflector->id());
   // Stop ALooper thread.
   mLooper->stop();
 }
 
 void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
 {
   if (who != NULL) {
+    Mutex::Autolock autoLock(mLock);
     sp<IBinder> binder = who.promote();
     if (binder != NULL) {
       cancelClientLocked(binder);
     }
   }
 }
 
 void MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -987,26 +987,33 @@ nsFocusManager::WindowHidden(nsIDOMWindo
 }
 
 NS_IMETHODIMP
 nsFocusManager::FireDelayedEvents(nsIDocument* aDocument)
 {
   NS_ENSURE_ARG(aDocument);
 
   // fire any delayed focus and blur events in the same order that they were added
-  for (uint32_t i = 0; i < mDelayedBlurFocusEvents.Length(); i++)
-  {
-    if (mDelayedBlurFocusEvents[i].mDocument == aDocument &&
-        !aDocument->EventHandlingSuppressed()) {
-      uint32_t type = mDelayedBlurFocusEvents[i].mType;
-      nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
-      nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
-      mDelayedBlurFocusEvents.RemoveElementAt(i);
-      SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
-      --i;
+  for (uint32_t i = 0; i < mDelayedBlurFocusEvents.Length(); i++) {
+    if (mDelayedBlurFocusEvents[i].mDocument == aDocument) {
+      if (!aDocument->GetInnerWindow() ||
+          !aDocument->GetInnerWindow()->IsCurrentInnerWindow()) {
+        // If the document was navigated away from or is defunct, don't bother
+        // firing events on it. Note the symmetry between this condition and
+        // the similar one in nsDocument.cpp:FireOrClearDelayedEvents.
+        mDelayedBlurFocusEvents.RemoveElementAt(i);
+        --i;
+      } else if (!aDocument->EventHandlingSuppressed()) {
+        uint32_t type = mDelayedBlurFocusEvents[i].mType;
+        nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
+        nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
+        mDelayedBlurFocusEvents.RemoveElementAt(i);
+        SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
+        --i;
+      }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFocusManager::FocusPlugin(nsIContent* aContent)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8184,20 +8184,18 @@ nsGlobalWindow::EnterModalState()
       }
     }
   }
 
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     mSuspendedDoc = topWin->GetExtantDoc();
-    if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
+    if (mSuspendedDoc) {
       mSuspendedDoc->SuppressEventHandling();
-    } else {
-      mSuspendedDoc = nullptr;
     }
   }
   topWin->mModalStateDepth++;
 }
 
 // static
 void
 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -134,29 +134,37 @@ BluetoothProfileController::SetupProfile
 
   /**
    * For a connect request, put multiple profiles into array and connect to
    * all of them sequencely.
    */
   bool hasAudio = HAS_AUDIO(mTarget.cod);
   bool hasRendering = HAS_RENDERING(mTarget.cod);
   bool isPeripheral = IS_PERIPHERAL(mTarget.cod);
+  bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
+  bool isKeyboard = IS_KEYBOARD(mTarget.cod);
+  bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
 
   NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);
 
-  /**
-   * Connect to HFP/HSP first. Then, connect A2DP if Rendering bit is set.
-   */
+  // Audio bit should be set if remote device supports HFP/HSP.
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
   }
-  if (hasRendering) {
+
+  // Rendering bit should be set if remote device supports A2DP.
+  // A device which supports AVRCP should claim that it's a peripheral and it's
+  // a remote control.
+  if (hasRendering || (isPeripheral && isRemoteControl)) {
     AddProfile(BluetoothA2dpManager::Get());
   }
-  if (isPeripheral) {
+
+  // A device which supports HID should claim that it's a peripheral and it's
+  // either a keyboard, a pointing device, or both.
+  if (isPeripheral && (isKeyboard || isPointingDevice)) {
     AddProfile(BluetoothHidManager::Get());
   }
 }
 
 void
 BluetoothProfileController::Start()
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -29,25 +29,34 @@ BEGIN_BLUETOOTH_NAMESPACE
 #define GET_MAJOR_SERVICE_CLASS(cod) ((cod & 0xffe000) >> 13)
 
 // Bit 12 ~ Bit 8: Major device class
 #define GET_MAJOR_DEVICE_CLASS(cod)  ((cod & 0x1f00) >> 8)
 
 // Bit 7 ~ Bit 2: Minor device class
 #define GET_MINOR_DEVICE_CLASS(cod)  ((cod & 0xfc) >> 2)
 
-// Bit 21: Major service class = 0x100, Audio
+// Audio: Major service class = 0x100 (Bit 21 is set)
 #define HAS_AUDIO(cod)               (cod & 0x200000)
 
-// Bit 18: Major service class = 0x20, Rendering
+// Rendering: Major service class = 0x20 (Bit 18 is set)
 #define HAS_RENDERING(cod)           (cod & 0x40000)
 
-// Major device class = 0x5, Peripheral
+// Peripheral: Major device class = 0x5
 #define IS_PERIPHERAL(cod)           (GET_MAJOR_DEVICE_CLASS(cod) == 0x5)
 
+// Remote Control: sub-field of minor device class, Bit 5 ~ Bit 2 = 0x3
+#define IS_REMOTE_CONTROL(cod)       ((GET_MINOR_DEVICE_CLASS(cod) & 0xf) == 0x3)
+
+// Keyboard: sub-field of minor device class (Bit 6)
+#define IS_KEYBOARD(cod)             ((GET_MINOR_DEVICE_CLASS(cod) & 0x10) >> 4)
+
+// Pointing device: sub-field of minor device class (Bit 7)
+#define IS_POINTING_DEVICE(cod)      ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
+
 class BluetoothProfileManagerBase;
 class BluetoothReplyRunnable;
 typedef void (*BluetoothProfileControllerCallback)();
 
 class BluetoothProfileController : public RefCounted<BluetoothProfileController>
 {
 public:
   /**
--- a/dom/bluetooth/bluedroid/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothHfpManager.cpp
@@ -334,17 +334,17 @@ bool
 Call::IsActive()
 {
   return (mState == nsITelephonyProvider::CALL_STATE_CONNECTED);
 }
 
 /**
  *  BluetoothHfpManager
  */
-BluetoothHfpManager::BluetoothHfpManager()
+BluetoothHfpManager::BluetoothHfpManager() : mPhoneType(PhoneType::NONE)
 {
   Reset();
 }
 
 void
 BluetoothHfpManager::ResetCallArray()
 {
   mCurrentCallArray.Clear();
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -336,17 +336,18 @@ Call::IsActive()
 {
   return (mState == nsITelephonyProvider::CALL_STATE_CONNECTED);
 }
 #endif // MOZ_B2G_RIL
 
 /**
  *  BluetoothHfpManager
  */
-BluetoothHfpManager::BluetoothHfpManager() : mController(nullptr)
+BluetoothHfpManager::BluetoothHfpManager() : mPhoneType(PhoneType::NONE)
+                                           , mController(nullptr)
 {
   Reset();
 }
 
 #ifdef MOZ_B2G_RIL
 void
 BluetoothHfpManager::ResetCallArray()
 {
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -14,24 +14,32 @@ function debug(s) {
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
+const NFC_PEER_EVENT_READY = 0x01;
+const NFC_PEER_EVENT_LOST  = 0x02;
+
 /**
  * NFCTag
  */
 function MozNFCTag() {
   debug("In MozNFCTag Constructor");
   this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
                              .getService(Ci.nsINfcContentHelper);
   this.session = null;
+
   // Map WebIDL declared enum map names to integer
   this._techTypesMap = [];
   this._techTypesMap['NFC_A'] = 0;
   this._techTypesMap['NFC_B'] = 1;
   this._techTypesMap['NFC_ISO_DEP'] = 2;
   this._techTypesMap['NFC_F'] = 3;
   this._techTypesMap['NFC_V'] = 4;
   this._techTypesMap['NDEF'] = 5;
@@ -97,82 +105,172 @@ function MozNFCPeer() {
   this.session = null;
 }
 MozNFCPeer.prototype = {
   _nfcContentHelper: null,
   _window: null,
 
   initialize: function(aWindow, aSessionToken) {
     this._window = aWindow;
-    this.setSessionToken(aSessionToken);
+    this.session = aSessionToken;
   },
 
   // ChromeOnly interface
   setSessionToken: function setSessionToken(aSessionToken) {
     debug("Setting session token.");
     this.session = aSessionToken;
     // report to NFC worker:
     return this._nfcContentHelper.setSessionToken(aSessionToken);
   },
 
   // NFCPeer interface:
   sendNDEF: function sendNDEF(records) {
     // Just forward sendNDEF to writeNDEF
-    return this._nfcContentHelper.writeNDEF(this._window, records);
+    return this._nfcContentHelper.writeNDEF(this._window, records, this.session);
   },
 
   classID: Components.ID("{c1b2bcf0-35eb-11e3-aa6e-0800200c9a66}"),
   contractID: "@mozilla.org/nfc/NFCPeer;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 };
 
 /**
  * Navigator NFC object
  */
 function mozNfc() {
   debug("In mozNfc Constructor");
+  this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
+                             .getService(Ci.nsINfcContentHelper);
 }
 mozNfc.prototype = {
   _nfcContentHelper: null,
   _window: null,
   _wrap: function _wrap(obj) {
     return ObjectWrapper.wrap(obj, this._window);
   },
 
   init: function init(aWindow) {
     debug("mozNfc init called");
     this._window = aWindow;
+    let origin = this._window.document.nodePrincipal.origin;
+    // Only System Process should listen on 'nfc-p2p-user-accept' event
+    if (origin !== 'app://system.gaiamobile.org') {
+      return;
+    }
+    let self = this;
+    this._window.addEventListener("nfc-p2p-user-accept", function (event) {
+      let appID = appsService.getAppLocalIdByManifestURL(event.detail.manifestUrl);
+      // Notify Chrome process of User's acknowledgement
+      self._nfcContentHelper.notifyUserAcceptedP2P(self._window, appID);
+    });
+  },
+
+  checkP2PRegistration: function checkP2PRegistration(manifestUrl) {
+    // Get the AppID and pass it to ContentHelper
+    let appID = appsService.getAppLocalIdByManifestURL(manifestUrl);
+    return this._nfcContentHelper.checkP2PRegistration(this._window, appID);
   },
 
   getNFCTag: function getNFCTag(sessionToken) {
     let obj = new MozNFCTag();
     let nfcTag = this._window.MozNFCTag._create(this._window, obj);
     if (nfcTag) {
       obj.initialize(this._window, sessionToken);
       return nfcTag;
     } else {
       debug("Error: Unable to create NFCTag");
       return null;
     }
   },
 
   getNFCPeer: function getNFCPeer(sessionToken) {
     let obj = new MozNFCPeer();
-    let nfcPeer = this._window.MozNFCTag._create(this._window, obj);
+    let nfcPeer = this._window.MozNFCPeer._create(this._window, obj);
     if (nfcPeer) {
       obj.initialize(this._window, sessionToken);
       return nfcPeer;
     } else {
       debug("Error: Unable to create NFCPeer");
       return null;
     }
   },
 
-  // get/set onpeerfound/lost onforegrounddispatch
+  // get/set onpeerready
+  get onpeerready() {
+    return this.__DOM_IMPL__.getEventHandler("onpeerready");
+  },
+
+  set onpeerready(handler) {
+    this.__DOM_IMPL__.setEventHandler("onpeerready", handler);
+  },
+
+  // get/set onpeerlost
+  get onpeerlost() {
+    return this.__DOM_IMPL__.getEventHandler("onpeerlost");
+  },
+
+  set onpeerlost(handler) {
+    this.__DOM_IMPL__.setEventHandler("onpeerlost", handler);
+  },
+
+  eventListenerWasAdded: function(evt) {
+    let eventType = this.getEventType(evt);
+    if (eventType == -1)
+      return;
+    this.registerTarget(eventType);
+  },
+
+  eventListenerWasRemoved: function(evt) {
+    let eventType = this.getEventType(evt);
+    if (eventType == -1)
+      return;
+    this.unregisterTarget(eventType);
+  },
+
+  registerTarget: function registerTarget(event) {
+    let self = this;
+    let appId = this._window.document.nodePrincipal.appId;
+    this._nfcContentHelper.registerTargetForPeerEvent(this._window, appId,
+      event, function(evt, sessionToken) {
+        self.session = sessionToken;
+        self.firePeerEvent(evt, sessionToken);
+    });
+  },
+
+  unregisterTarget: function unregisterTarget(event) {
+    let appId = this._window.document.nodePrincipal.appId;
+    this._nfcContentHelper.unregisterTargetForPeerEvent(this._window,
+                                                        appId, event);
+  },
+
+  getEventType: function getEventType(evt) {
+    let eventType = -1;
+    switch (evt) {
+      case 'peerready':
+        eventType = NFC_PEER_EVENT_READY;
+        break;
+      case 'peerlost':
+        eventType = NFC_PEER_EVENT_LOST;
+        break;
+      default:
+        break;
+    }
+    return eventType;
+  },
+
+  firePeerEvent: function firePeerEvent(evt, sessionToken) {
+    let peerEvent = (NFC_PEER_EVENT_READY === evt) ? "peerready" : "peerlost";
+    let detail = {
+      "detail":sessionToken
+    };
+    let event = new this._window.CustomEvent(peerEvent,
+      ObjectWrapper.wrap(detail, this._window));
+    this.__DOM_IMPL__.dispatchEvent(event);
+  },
 
   classID: Components.ID("{6ff2b290-2573-11e3-8224-0800200c9a66}"),
   contractID: "@mozilla.org/navigatorNfc;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozNFCTag, MozNFCPeer, mozNfc]);
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -15,17 +15,19 @@
 
 #include <android/log.h>
 #include <cutils/properties.h>
 
 #include "AudioChannelService.h"
 #include "AudioManager.h"
 
 #include "nsIObserverService.h"
+#ifdef MOZ_B2G_RIL
 #include "nsIRadioInterfaceLayer.h"
+#endif
 #include "nsISettingsService.h"
 #include "nsPrintfCString.h"
 
 #include "mozilla/Hal.h"
 #include "mozilla/Services.h"
 #include "base/message_loop.h"
 
 #include "BluetoothCommon.h"
@@ -365,19 +367,22 @@ public:
       sSwitchDone = false;
     } else if (aEvent.status() != SWITCH_STATE_OFF) {
       InternalSetAudioRoutes(aEvent.status());
       sSwitchDone = true;
     }
   }
 };
 
-AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT),
-                 mObserver(new HeadphoneSwitchObserver()),
-                 mMuteCallToRIL(false)
+AudioManager::AudioManager()
+  : mPhoneState(PHONE_STATE_CURRENT)
+  , mObserver(new HeadphoneSwitchObserver())
+#ifdef MOZ_B2G_RIL
+  , mMuteCallToRIL(false)
+#endif
 {
   RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
 
   InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
   NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
 
   for (int loop = 0; loop < AUDIO_STREAM_CNT; loop++) {
     AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0,
@@ -418,21 +423,23 @@ AudioManager::AudioManager() : mPhoneSta
   }
   if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID, false))) {
     NS_WARNING("Failed to add bluetooth hfp status changed observer!");
   }
   if (NS_FAILED(obs->AddObserver(this, MOZ_SETTINGS_CHANGE_ID, false))) {
     NS_WARNING("Failed to add mozsettings-changed observer!");
   }
 
+#ifdef MOZ_B2G_RIL
   char value[PROPERTY_VALUE_MAX];
   property_get("ro.moz.mute.call.to_ril", value, "false");
   if (!strcmp(value, "true")) {
     mMuteCallToRIL = true;
   }
+#endif
 }
 
 AudioManager::~AudioManager() {
   UnregisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
   if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID))) {
@@ -447,39 +454,43 @@ AudioManager::~AudioManager() {
   if (NS_FAILED(obs->RemoveObserver(this, MOZ_SETTINGS_CHANGE_ID))) {
     NS_WARNING("Failed to remove mozsettings-changed observer!");
   }
 }
 
 NS_IMETHODIMP
 AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted)
 {
+#ifdef MOZ_B2G_RIL
   if (mMuteCallToRIL) {
     // Simply return cached mIsMicMuted if mute call go via RIL.
     *aMicrophoneMuted = mIsMicMuted;
     return NS_OK;
   }
+#endif
 
   if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AudioManager::SetMicrophoneMuted(bool aMicrophoneMuted)
 {
   if (!AudioSystem::muteMicrophone(aMicrophoneMuted)) {
+#ifdef MOZ_B2G_RIL
     if (mMuteCallToRIL) {
       // Extra mute request to RIL for specific platform.
       nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
       NS_ENSURE_TRUE(ril, NS_ERROR_FAILURE);
       ril->SetMicrophoneMuted(aMicrophoneMuted);
       mIsMicMuted = aMicrophoneMuted;
     }
+#endif
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 AudioManager::GetPhoneState(int32_t* aState)
 {
--- a/dom/system/gonk/AudioManager.h
+++ b/dom/system/gonk/AudioManager.h
@@ -61,19 +61,21 @@ protected:
   int mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT];
 
   nsresult SetStreamVolumeIndex(int32_t aStream, int32_t aIndex);
   nsresult GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex);
 
 private:
   nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
   nsCOMPtr<AudioChannelAgent>             mPhoneAudioAgent;
+#ifdef MOZ_B2G_RIL
   bool                                    mMuteCallToRIL;
   // mIsMicMuted is only used for toggling mute call to RIL.
   bool                                    mIsMicMuted;
+#endif
 
   void HandleBluetoothStatusChanged(nsISupports* aSubject,
                                     const char* aTopic,
                                     const nsCString aAddress);
 };
 
 } /* namespace gonk */
 } /* namespace dom */
--- a/dom/system/gonk/Nfc.js
+++ b/dom/system/gonk/Nfc.js
@@ -46,16 +46,23 @@ const NFC_IPC_MSG_NAMES = [
   "NFC:ReadNDEF",
   "NFC:WriteNDEF",
   "NFC:GetDetailsNDEF",
   "NFC:MakeReadOnlyNDEF",
   "NFC:Connect",
   "NFC:Close"
 ];
 
+const NFC_IPC_PEER_MSG_NAMES = [
+  "NFC:RegisterPeerTarget",
+  "NFC:UnregisterPeerTarget",
+  "NFC:CheckP2PRegistration",
+  "NFC:NotifyUserAcceptedP2P"
+];
+
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
                                    "@mozilla.org/telephony/system-worker-manager;1",
@@ -73,16 +80,20 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
     nfc: null,
 
     // Manage message targets in terms of sessionToken. Only the authorized and
     // registered contents can receive related messages.
     targetsBySessionTokens: {},
     sessionTokens: [],
 
+    // Manage registered Peer Targets
+    peerTargetsMap: {},
+    currentPeerAppId: null,
+
     init: function init(nfc) {
       this.nfc = nfc;
 
       Services.obs.addObserver(this, "xpcom-shutdown", false);
       this._registerMessageListeners();
     },
 
     _shutdown: function _shutdown() {
@@ -92,23 +103,31 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       this._unregisterMessageListeners();
     },
 
     _registerMessageListeners: function _registerMessageListeners() {
       ppmm.addMessageListener("child-process-shutdown", this);
       for (let msgname of NFC_IPC_MSG_NAMES) {
         ppmm.addMessageListener(msgname, this);
       }
+
+      for (let msgname of NFC_IPC_PEER_MSG_NAMES) {
+        ppmm.addMessageListener(msgname, this);
+      }
     },
 
     _unregisterMessageListeners: function _unregisterMessageListeners() {
       ppmm.removeMessageListener("child-process-shutdown", this);
       for (let msgname of NFC_IPC_MSG_NAMES) {
         ppmm.removeMessageListener(msgname, this);
       }
+
+      for (let msgname of NFC_IPC_PEER_MSG_NAMES) {
+        ppmm.removeMessageListener(msgname, this);
+      }
       ppmm = null;
     },
 
     _registerMessageTarget: function _registerMessageTarget(sessionToken, target) {
       let targets = this.targetsBySessionTokens[sessionToken];
       if (!targets) {
         targets = this.targetsBySessionTokens[sessionToken] = [];
         let list = this.sessionTokens;
@@ -166,16 +185,92 @@ XPCOMUtils.defineLazyGetter(this, "gMess
         return;
       }
 
       for (let target of targets) {
         target.sendAsyncMessage(message, options);
       }
     },
 
+    registerPeerTarget: function registerPeerTarget(msg) {
+      let appInfo = msg.json;
+      // Sanity check on PeerEvent
+      if (!this.isValidPeerEvent(appInfo.event)) {
+        return;
+      }
+      let targets = this.peerTargetsMap;
+      let targetInfo = targets[appInfo.appId];
+      // If the application Id is already registered
+      if (targetInfo) {
+        // If the event is not registered
+        if (targetInfo.event !== appInfo.event) {
+          // Update the event field ONLY
+          targetInfo.event |= appInfo.event;
+        }
+        // Otherwise event is already registered, return!
+        return;
+      }
+      // Target not registered yet! Add to the target map
+
+      // Registered targetInfo target consists of 2 fields (values)
+      // target : Target to notify the right content for peer notifications
+      // event  : NFC_PEER_EVENT_READY (0x01) Or NFC_PEER_EVENT_LOST (0x02)
+      let newTargetInfo = { target : msg.target,
+                            event  : appInfo.event };
+      targets[appInfo.appId] = newTargetInfo;
+    },
+
+    unregisterPeerTarget: function unregisterPeerTarget(msg) {
+      let appInfo = msg.json;
+      // Sanity check on PeerEvent
+      if (!this.isValidPeerEvent(appInfo.event)) {
+        return;
+      }
+      let targets = this.peerTargetsMap;
+      let targetInfo = targets[appInfo.appId];
+      if (targetInfo) {
+        // Application Id registered and the event exactly matches.
+        if (targetInfo.event === appInfo.event) {
+          // Remove the target from the list of registered targets
+          delete targets[appInfo.appId]
+        }
+        else {
+          // Otherwise, update the event field ONLY, by removing the event flag
+          targetInfo.event &= ~appInfo.event;
+        }
+      }
+    },
+
+    isRegisteredP2PTarget: function isRegisteredP2PTarget(appId, event) {
+      let targetInfo = this.peerTargetsMap[appId];
+      // Check if it is a registered target for the 'event'
+      return ((targetInfo != null) && (targetInfo.event & event !== 0));
+    },
+
+    notifyPeerEvent: function notifyPeerEvent(appId, event) {
+      let targetInfo = this.peerTargetsMap[appId];
+      // Check if the application id is a registeredP2PTarget
+      if (this.isRegisteredP2PTarget(appId, event)) {
+        targetInfo.target.sendAsyncMessage("NFC:PeerEvent", {
+          event: event,
+          sessionToken: this.nfc.sessionTokenMap[this.nfc._currentSessionId]
+        });
+        return;
+      }
+      debug("Application ID : " + appId + " is not a registered target" +
+                             "for the event " + event + " notification");
+    },
+
+    isValidPeerEvent: function isValidPeerEvent(event) {
+      // Valid values : 0x01, 0x02 Or 0x03
+      return ((event === NFC.NFC_PEER_EVENT_READY) ||
+              (event === NFC.NFC_PEER_EVENT_LOST)  ||
+              (event === (NFC.NFC_PEER_EVENT_READY | NFC.NFC_PEER_EVENT_LOST)));
+    },
+
     /**
      * nsIMessageListener interface methods.
      */
 
     receiveMessage: function receiveMessage(msg) {
       debug("Received '" + msg.name + "' message from content process");
       if (msg.name == "child-process-shutdown") {
         // By the time we receive child-process-shutdown, the child process has
@@ -186,29 +281,71 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       }
 
       if (NFC_IPC_MSG_NAMES.indexOf(msg.name) != -1) {
         if (!msg.target.assertPermission("nfc-read")) {
           debug("Nfc message " + msg.name +
                 " from a content process with no 'nfc-read' privileges.");
           return null;
         }
+      } else if (NFC_IPC_PEER_MSG_NAMES.indexOf(msg.name) != -1) {
+        if (!msg.target.assertPermission("nfc-write")) {
+          debug("Nfc Peer message  " + msg.name +
+                " from a content process with no 'nfc-write' privileges.");
+          return null;
+        }
+
+        // Add extra permission check for two IPC Peer events:
+        // 'NFC:CheckP2PRegistration' , 'NFC:NotifyUserAcceptedP2P'
+        if ((msg.name == "NFC:CheckP2PRegistration") ||
+            (msg.name == "NFC:NotifyUserAcceptedP2P")) {
+          // ONLY privileged Content can send these two events
+          if (!msg.target.assertPermission("nfc-manager")) {
+            debug("NFC message " + message.name +
+                  " from a content process with no 'nfc-manager' privileges.");
+            return null;
+          }
+        }
       } else {
         debug("Ignoring unknown message type: " + msg.name);
         return null;
       }
 
       switch (msg.name) {
         case "NFC:SetSessionToken":
           this._registerMessageTarget(this.nfc.sessionTokenMap[this.nfc._currentSessionId], msg.target);
           debug("Registering target for this SessionToken : " +
                 this.nfc.sessionTokenMap[this.nfc._currentSessionId]);
-          return null;
+          break;
+        case "NFC:RegisterPeerTarget":
+          this.registerPeerTarget(msg);
+          break;
+        case "NFC:UnregisterPeerTarget":
+          this.unregisterPeerTarget(msg);
+          break;
+        case "NFC:CheckP2PRegistration":
+          // Check if the application id is a valid registered target.
+          // (It should have registered for NFC_PEER_EVENT_READY).
+          let isRegistered = this.isRegisteredP2PTarget(msg.json.appId,
+                                                        NFC.NFC_PEER_EVENT_READY);
+          // Remember the current AppId if registered.
+          this.currentPeerAppId = (isRegistered) ? msg.json.appId : null;
+          let status = (isRegistered) ? NFC.GECKO_NFC_ERROR_SUCCESS :
+                                        NFC.GECKO_NFC_ERROR_GENERIC_FAILURE;
+          // Notify the content process immediately of the status
+          msg.target.sendAsyncMessage(msg.name + "Response", {
+            status: status,
+            requestId: msg.json.requestId
+          });
+          break;
+        case "NFC:NotifyUserAcceptedP2P":
+          // Notify the 'NFC_PEER_EVENT_READY' since user has acknowledged
+          this.notifyPeerEvent(msg.json.appId, NFC.NFC_PEER_EVENT_READY);
+          break;
       }
-
       return null;
     },
 
     /**
      * nsIObserver interface methods.
      */
 
     observe: function observe(subject, topic, data) {
@@ -306,36 +443,43 @@ Nfc.prototype = {
    */
   onmessage: function onmessage(event) {
     let message = event.data;
     debug("Received message from NFC worker: " + JSON.stringify(message));
 
     switch (message.type) {
       case "techDiscovered":
         this._currentSessionId = message.sessionId;
+
         // Check if the session token already exists. If exists, continue to use the same one.
         // If not, generate a new token.
         if (!this.sessionTokenMap[this._currentSessionId]) {
           this.sessionTokenMap[this._currentSessionId] = UUIDGenerator.generateUUID().toString();
         }
         // Update the upper layers with a session token (alias)
         message.sessionToken = this.sessionTokenMap[this._currentSessionId];
         // Do not expose the actual session to the content
         delete message.sessionId;
+
         gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", message);
         break;
       case "techLost":
         gMessageManager._unregisterMessageTarget(this.sessionTokenMap[this._currentSessionId], null);
+
         // Update the upper layers with a session token (alias)
         message.sessionToken = this.sessionTokenMap[this._currentSessionId];
         // Do not expose the actual session to the content
         delete message.sessionId;
+
         gSystemMessenger.broadcastMessage("nfc-manager-tech-lost", message);
+        // Notify 'PeerLost' to appropriate registered target, if any
+        gMessageManager.notifyPeerEvent(this.currentPeerAppId, NFC.NFC_PEER_EVENT_LOST);
         delete this.sessionTokenMap[this._currentSessionId];
         this._currentSessionId = null;
+        this.currentPeerAppId = null;
         break;
      case "ConfigResponse":
         gSystemMessenger.broadcastMessage("nfc-powerlevel-change", message);
         break;
       case "ConnectResponse": // Fall through.
       case "CloseResponse":
       case "GetDetailsNDEFResponse":
       case "ReadNDEFResponse":
--- a/dom/system/gonk/NfcContentHelper.js
+++ b/dom/system/gonk/NfcContentHelper.js
@@ -42,44 +42,51 @@ const NFCCONTENTHELPER_CID =
   Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}");
 
 const NFC_IPC_MSG_NAMES = [
   "NFC:ReadNDEFResponse",
   "NFC:WriteNDEFResponse",
   "NFC:GetDetailsNDEFResponse",
   "NFC:MakeReadOnlyNDEFResponse",
   "NFC:ConnectResponse",
-  "NFC:CloseResponse"
+  "NFC:CloseResponse",
+  "NFC:CheckP2PRegistrationResponse",
+  "NFC:PeerEvent"
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsISyncMessageSender");
 
 function NfcContentHelper() {
   this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES);
   Services.obs.addObserver(this, "xpcom-shutdown", false);
 
   this._requestMap = [];
+
+  // Maintains an array of PeerEvent related callbacks, mainly
+  // one for 'peerReady' and another for 'peerLost'.
+  this.peerEventsCallbackMap = {};
 }
 
 NfcContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsINfcContentHelper,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsIObserver]),
   classID:   NFCCONTENTHELPER_CID,
   classInfo: XPCOMUtils.generateCI({
     classID:          NFCCONTENTHELPER_CID,
     classDescription: "NfcContentHelper",
     interfaces:       [Ci.nsINfcContentHelper]
   }),
 
   _requestMap: null,
+  peerEventsCallbackMap: null,
 
   /* TODO: Bug 815526: This is a limitation when a DOMString is used in sequences of Moz DOM Objects.
    *       Strings such as 'type', 'id' 'payload' will not be acccessible to NfcWorker.
    *       Therefore this function exists till the bug is addressed.
    */
   encodeNdefRecords: function encodeNdefRecords(records) {
     let encodedRecords = [];
     for (let i = 0; i < records.length; i++) {
@@ -140,23 +147,21 @@ NfcContentHelper.prototype = {
     return request;
   },
 
   writeNDEF: function writeNDEF(window, records, sessionToken) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
-
     let request = Services.DOMRequest.createRequest(window);
     let requestId = btoa(this.getRequestId(request));
     this._requestMap[requestId] = window;
 
     let encodedRecords = this.encodeNdefRecords(records);
-
     cpmm.sendAsyncMessage("NFC:WriteNDEF", {
       requestId: requestId,
       sessionToken: sessionToken,
       records: encodedRecords
     });
     return request;
   },
 
@@ -205,16 +210,73 @@ NfcContentHelper.prototype = {
 
     cpmm.sendAsyncMessage("NFC:Close", {
       requestId: requestId,
       sessionToken: sessionToken
     });
     return request;
   },
 
+  registerTargetForPeerEvent: function registerTargetForPeerEvent(window,
+                                                  appId, event, callback) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    this.peerEventsCallbackMap[event] = callback;
+    cpmm.sendAsyncMessage("NFC:RegisterPeerTarget", {
+      appId: appId,
+      event: event
+    });
+  },
+
+  unregisterTargetForPeerEvent: function unregisterTargetForPeerEvent(window,
+                                                                appId, event) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let callback = this.peerEventsCallbackMap[event];
+    if (callback != null) {
+      delete this.peerEventsCallbackMap[event];
+    }
+
+    cpmm.sendAsyncMessage("NFC:UnregisterPeerTarget", {
+      appId: appId,
+      event: event
+    });
+  },
+
+  checkP2PRegistration: function checkP2PRegistration(window, appId) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:CheckP2PRegistration", {
+      appId: appId,
+      requestId: requestId
+    });
+    return request;
+  },
+
+  notifyUserAcceptedP2P: function notifyUserAcceptedP2P(window, appId) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+
+    cpmm.sendAsyncMessage("NFC:NotifyUserAcceptedP2P", {
+      appId: appId
+    });
+  },
+
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
     if (topic == "xpcom-shutdown") {
       this.removeMessageListener();
       Services.obs.removeObserver(this, "xpcom-shutdown");
       cpmm = null;
     }
@@ -254,18 +316,29 @@ NfcContentHelper.prototype = {
       case "NFC:ReadNDEFResponse":
         this.handleReadNDEFResponse(message.json);
         break;
       case "NFC:ConnectResponse": // Fall through.
       case "NFC:CloseResponse":
       case "NFC:WriteNDEFResponse":
       case "NFC:MakeReadOnlyNDEFResponse":
       case "NFC:GetDetailsNDEFResponse":
+      case "NFC:CheckP2PRegistrationResponse":
         this.handleResponse(message.json);
         break;
+      case "NFC:PeerEvent":
+        let callback = this.peerEventsCallbackMap[message.json.event];
+        if (callback) {
+          callback.peerNotification(message.json.event,
+                                    message.json.sessionToken);
+        } else {
+          debug("PeerEvent: No valid callback registered for the event " +
+                message.json.event);
+        }
+        break;
     }
   },
 
   handleReadNDEFResponse: function handleReadNDEFResponse(message) {
     debug("ReadNDEFResponse(" + JSON.stringify(message) + ")");
     let requester = this._requestMap[message.requestId];
     if (!requester) {
        debug("ReadNDEFResponse Invalid requester=" + requester +
--- a/dom/system/gonk/OpenFileFinder.cpp
+++ b/dom/system/gonk/OpenFileFinder.cpp
@@ -14,19 +14,20 @@ namespace mozilla {
 namespace system {
 
 OpenFileFinder::OpenFileFinder(const nsACString& aPath,
                                bool aCheckIsB2gOrDescendant /* = true */)
   : mPath(aPath),
     mProcDir(nullptr),
     mFdDir(nullptr),
     mPid(0),
-    mMyPid(-1),
     mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant)
 {
+  // We assume that we're running in the parent process
+  mMyPid = getpid();
 }
 
 OpenFileFinder::~OpenFileFinder()
 {
   Close();
 }
 
 bool
@@ -157,20 +158,16 @@ OpenFileFinder::FillInfo(OpenFileFinder:
   }
   nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1);
   aInfo->mComm = comm;
   // There is a single character field after the comm and then
   // the parent pid (the field we're interested in).
   // ) X ppid
   // 01234
   int ppid = atoi(&closeParen[4]);
-  // We assume that we're running in the parent process
-  if (mMyPid == -1) {
-    mMyPid = getpid();
-  }
 
   if (mPid == mMyPid) {
     // This is chrome process
     aInfo->mIsB2gOrDescendant = true;
     DBG("Chrome process has open file(s)");
     return;
   }
   // For the rest (non-chrome process), we recursively check the ppid to know
--- a/dom/system/gonk/nfc_consts.js
+++ b/dom/system/gonk/nfc_consts.js
@@ -62,10 +62,13 @@ this.NFC_POWER_LEVEL_DISABLED       = 0;
 this.NFC_POWER_LEVEL_LOW            = 1;
 this.NFC_POWER_LEVEL_ENABLED        = 2;
 
 this.TOPIC_MOZSETTINGS_CHANGED      = "mozsettings-changed";
 this.TOPIC_XPCOM_SHUTDOWN           = "xpcom-shutdown";
 this.SETTING_NFC_ENABLED            = "nfc.enabled";
 this.SETTING_NFC_POWER_LEVEL        = "nfc.powerlevel";
 
+this.NFC_PEER_EVENT_READY = 0x01;
+this.NFC_PEER_EVENT_LOST  = 0x02;
+
 // Allow this file to be imported via Components.utils.import().
 this.EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/system/gonk/nsINfcContentHelper.idl
+++ b/dom/system/gonk/nsINfcContentHelper.idl
@@ -2,21 +2,99 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIDOMDOMRequest.idl"
 
 interface nsIVariant;
 
-[scriptable, uuid(28c8f240-da8c-11e1-9b23-0800200c9a66)]
+[scriptable, function, uuid(271f48b0-c884-4f0b-a348-e29824c95168)]
+interface nsINfcPeerCallback : nsISupports
+{
+  /**
+   * Callback function used to notify NFC peer events.
+   *
+   * @param event
+   *        An event indicating 'PeerReady' or 'PeerLost'
+   *        One of NFC_EVENT_PEER_XXXX
+   *
+   * @param sessionToken
+   *        SessionToken received from Chrome process
+   */
+   void peerNotification(in unsigned long event,
+                         in DOMString sessionToken);
+};
+
+[scriptable, uuid(91c2760a-f41c-4174-ad68-614840d4e201)]
 interface nsINfcContentHelper : nsISupports
 {
+  const long NFC_EVENT_PEER_READY = 0x01;
+  const long NFC_EVENT_PEER_LOST  = 0x02;
+
   void setSessionToken(in DOMString sessionToken);
 
   nsIDOMDOMRequest getDetailsNDEF(in nsIDOMWindow window, in DOMString sessionToken);
   nsIDOMDOMRequest readNDEF(in nsIDOMWindow window, in DOMString sessionToken);
   nsIDOMDOMRequest writeNDEF(in nsIDOMWindow window, in nsIVariant records, in DOMString sessionToken);
   nsIDOMDOMRequest makeReadOnlyNDEF(in nsIDOMWindow window, in DOMString sessionToken);
 
   nsIDOMDOMRequest connect(in nsIDOMWindow window, in unsigned long techType, in DOMString sessionToken);
   nsIDOMDOMRequest close(in nsIDOMWindow window, in DOMString sessionToken);
+
+ /**
+  * Register the given application id with Chrome process
+  *
+  * @param window
+  *        Current window
+  *
+  * @param appId
+  *        Application ID to be registered
+  *
+  * @param event
+  *       Event to be registered. Either NFC_EVENT_PEER_READY or NFC_EVENT_PEER_LOST
+  *
+  * @param callback
+  *       Callback that is used to notify upper layers whenever PeerEvents happen.
+  */
+  void registerTargetForPeerEvent(in nsIDOMWindow window,
+                                  in unsigned long appId,
+                                  in octet event,
+                                  in nsINfcPeerCallback callback);
+ /**
+  * Unregister the given application id with Chrome process
+  *
+  * @param window
+  *        Current window
+  *
+  * @param appId
+  *        Application ID to be registered
+  *
+  * @param event
+  *       Event to be unregistered. Either NFC_EVENT_PEER_READY or NFC_EVENT_PEER_LOST
+  */
+  void unregisterTargetForPeerEvent(in nsIDOMWindow window,
+                                    in unsigned long appId,
+                                    in octet event);
+ /**
+  * Checks if the given application's id is a registered peer target (with the Chrome process)
+  *
+  * @param window
+  *        Current window
+  *
+  * @param appId
+  *        Application ID to be updated with Chrome process
+  *
+  * Returns DOMRequest, if appId is registered then 'onsuccess' is called else 'onerror'
+  */
+  nsIDOMDOMRequest checkP2PRegistration(in nsIDOMWindow window, in unsigned long appId);
+
+ /**
+  * Notify the Chrome process that user has accepted to share nfc message on P2P UI
+  *
+  * @param window
+  *        Current window
+  *
+  * @param appId
+  *        Application ID that is capable of handling NFC_EVENT_PEER_READY event
+  */
+  void notifyUserAcceptedP2P(in nsIDOMWindow window, in unsigned long appId);
 };
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -3003,29 +3003,22 @@ let RIL = {
     }
 
     // This was moved down from CARD_APPSTATE_READY
     this.requestNetworkInfo();
     if (newCardState == GECKO_CARDSTATE_READY) {
       // For type SIM, we need to check EF_phase first.
       // Other types of ICC we can send Terminal_Profile immediately.
       if (this.appType == CARD_APPTYPE_SIM) {
-        ICCRecordHelper.readICCPhase();
-        ICCRecordHelper.fetchICCRecords();
-      } else if (this.appType == CARD_APPTYPE_USIM) {
-        if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
-          this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
-        }
-        ICCRecordHelper.fetchICCRecords();
-      } else if (this.appType == CARD_APPTYPE_RUIM) {
-        if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
-          this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
-        }
-        RuimRecordHelper.fetchRuimRecords();
-      }
+        SimRecordHelper.readSimPhase();
+      } else if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) {
+        this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+      }
+
+      ICCRecordHelper.fetchICCRecords();
       this.reportStkServiceIsRunning();
     }
 
     this.cardState = newCardState;
     this.sendChromeMessage({rilMessageType: "cardstatechange",
                             cardState: this.cardState});
   },
 
@@ -4992,18 +4985,18 @@ RIL[REQUEST_GET_CURRENT_CALLS] = functio
     calls[call.callIndex] = call;
   }
   this._processCalls(calls);
 };
 RIL[REQUEST_DIAL] = function REQUEST_DIAL(length, options) {
   if (options.rilRequestError) {
     // The connection is not established yet.
     options.callIndex = -1;
-    this.getFailCauseCode(options);
-    return;
+    this._sendCallError(options.callIndex,
+                        RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]);
   }
 };
 RIL[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   this.iccInfoPrivate.imsi = Buf.readString();
@@ -5072,25 +5065,18 @@ RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = func
   if (!num) {
     // No response of REQUEST_LAST_CALL_FAIL_CAUSE. Change the call state into
     // 'disconnected' directly.
     this._handleDisconnectedCall(options);
     return;
   }
 
   let failCause = Buf.readInt32();
-  switch (failCause) {
-    case CALL_FAIL_NORMAL:
-      this._handleDisconnectedCall(options);
-      break;
-    default:
-      this._sendCallError(options.callIndex,
-                          RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause]);
-      break;
-  }
+  options.failCause = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause];
+  this._handleDisconnectedCall(options);
 };
 RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) {
   this._receivedNetworkInfo(NETWORK_INFO_SIGNAL);
 
   if (options.rilRequestError) {
     return;
   }
 
@@ -11195,42 +11181,25 @@ ICCIOHelper[ICC_COMMAND_UPDATE_RECORD] =
 /**
  * Helper for ICC records.
  */
 let ICCRecordHelper = {
   /**
    * Fetch ICC records.
    */
   fetchICCRecords: function fetchICCRecords() {
-    RIL.getIMSI();
-    this.readAD();
-    this.readSST();
-  },
-
-  /**
-   * Read EF_phase.
-   * This EF is only available in SIM.
-   */
-  readICCPhase: function readICCPhase() {
-    function callback() {
-      let strLen = Buf.readInt32();
-
-      let phase = GsmPDUHelper.readHexOctet();
-      // If EF_phase is coded '03' or greater, an ME supporting STK shall
-      // perform the PROFILE DOWNLOAD procedure.
-      if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD &&
-          phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
-        RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
-      }
-
-      Buf.readStringDelimiter(strLen);
-    }
-
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_PHASE,
-                                   callback: callback.bind(this)});
+    switch (RIL.appType) {
+      case CARD_APPTYPE_SIM:
+      case CARD_APPTYPE_USIM:
+        SimRecordHelper.fetchSimRecords();
+        break;
+      case CARD_APPTYPE_RUIM:
+        RuimRecordHelper.fetchRuimRecords();
+        break;
+    }
   },
 
   /**
    * Read the ICCID.
    */
   readICCID: function readICCID() {
     function callback() {
       let strLen = Buf.readInt32();
@@ -11244,182 +11213,16 @@ let ICCRecordHelper = {
       }
     }
 
     ICCIOHelper.loadTransparentEF({fileId: ICC_EF_ICCID,
                                    callback: callback.bind(this)});
   },
 
   /**
-   * Read the MSISDN from the ICC.
-   */
-  readMSISDN: function readMSISDN() {
-    function callback(options) {
-      let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
-      if (!contact ||
-          (RIL.iccInfo.msisdn !== undefined &&
-           RIL.iccInfo.msisdn === contact.number)) {
-        return;
-      }
-      RIL.iccInfo.msisdn = contact.number;
-      if (DEBUG) debug("MSISDN: " + RIL.iccInfo.msisdn);
-      ICCUtilsHelper.handleICCInfoChange();
-    }
-
-    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_MSISDN,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Read the AD (Administrative Data) from the ICC.
-   */
-  readAD: function readAD() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      // Each octet is encoded into two chars.
-      let octetLen = strLen / 2;
-      let ad = GsmPDUHelper.readHexOctetArray(octetLen);
-      Buf.readStringDelimiter(strLen);
-
-      if (DEBUG) {
-        let str = "";
-        for (let i = 0; i < ad.length; i++) {
-          str += ad[i] + ", ";
-        }
-        debug("AD: " + str);
-      }
-
-      // The 4th byte of the response is the length of MNC.
-      let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi,
-                                                      ad && ad[3]);
-      if (mccMnc) {
-        RIL.iccInfo.mcc = mccMnc.mcc;
-        RIL.iccInfo.mnc = mccMnc.mnc;
-        ICCUtilsHelper.handleICCInfoChange();
-      }
-    }
-
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_AD,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Read the SPN (Service Provider Name) from the ICC.
-   */
-  readSPN: function readSPN() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      // Each octet is encoded into two chars.
-      let octetLen = strLen / 2;
-      let spnDisplayCondition = GsmPDUHelper.readHexOctet();
-      // Minus 1 because the first octet is used to store display condition.
-      let spn = ICCPDUHelper.readAlphaIdentifier(octetLen - 1);
-      Buf.readStringDelimiter(strLen);
-
-      if (DEBUG) {
-        debug("SPN: spn = " + spn +
-              ", spnDisplayCondition = " + spnDisplayCondition);
-      }
-
-      RIL.iccInfoPrivate.spnDisplayCondition = spnDisplayCondition;
-      RIL.iccInfo.spn = spn;
-      ICCUtilsHelper.updateDisplayCondition();
-      ICCUtilsHelper.handleICCInfoChange();
-    }
-
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_SPN,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Read the (U)SIM Service Table from the ICC.
-   */
-  readSST: function readSST() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      // Each octet is encoded into two chars.
-      let octetLen = strLen / 2;
-      let sst = GsmPDUHelper.readHexOctetArray(octetLen);
-      Buf.readStringDelimiter(strLen);
-      RIL.iccInfoPrivate.sst = sst;
-      if (DEBUG) {
-        let str = "";
-        for (let i = 0; i < sst.length; i++) {
-          str += sst[i] + ", ";
-        }
-        debug("SST: " + str);
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) {
-        if (DEBUG) debug("MSISDN: MSISDN is available");
-        this.readMSISDN();
-      } else {
-        if (DEBUG) debug("MSISDN: MSISDN service is not available");
-      }
-
-      // Fetch SPN and PLMN list, if some of them are available.
-      if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
-        if (DEBUG) debug("SPN: SPN is available");
-        this.readSPN();
-      } else {
-        if (DEBUG) debug("SPN: SPN service is not available");
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("MDN")) {
-        if (DEBUG) debug("MDN: MDN available.");
-        this.readMBDN();
-      } else {
-        if (DEBUG) debug("MDN: MDN service is not available");
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) {
-        if (DEBUG) debug("SPDI: SPDI available.");
-        this.readSPDI();
-      } else {
-        if (DEBUG) debug("SPDI: SPDI service is not available");
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("PNN")) {
-        if (DEBUG) debug("PNN: PNN is available");
-        this.readPNN();
-      } else {
-        if (DEBUG) debug("PNN: PNN is not available");
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("OPL")) {
-        if (DEBUG) debug("OPL: OPL is available");
-        this.readOPL();
-      } else {
-        if (DEBUG) debug("OPL: OPL is not available");
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("CBMI")) {
-        this.readCBMI();
-      } else {
-        RIL.cellBroadcastConfigs.CBMI = null;
-      }
-      if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_CB")) {
-        this.readCBMID();
-      } else {
-        RIL.cellBroadcastConfigs.CBMID = null;
-      }
-      if (ICCUtilsHelper.isICCServiceAvailable("CBMIR")) {
-        this.readCBMIR();
-      } else {
-        RIL.cellBroadcastConfigs.CBMIR = null;
-      }
-      RIL._mergeAllCellBroadcastConfigs();
-    }
-
-    // ICC_EF_UST has the same value with ICC_EF_SST.
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_SST,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
    * Read ICC ADN like EF, i.e. EF_ADN, EF_FDN.
    *
    * @param fileId      EF id of the ADN or FDN.
    * @param onsuccess   Callback to be called when success.
    * @param onerror     Callback to be called when error.
    */
   readADNLike: function readADNLike(fileId, onsuccess, onerror) {
     function callback(options) {
@@ -11481,42 +11284,17 @@ let ICCRecordHelper = {
                                      recordNumber: contact.recordId,
                                      dataWriter: dataWriter.bind(this),
                                      pin2: pin2,
                                      callback: callback.bind(this),
                                      onerror: onerror});
   },
 
   /**
-   * Read ICC MBDN. (Mailbox Dialling Number)
-   *
-   * @see TS 131.102, clause 4.2.60
-   */
-  readMBDN: function readMBDN() {
-    function callback(options) {
-      let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
-      if (!contact ||
-          (RIL.iccInfoPrivate.mbdn !== undefined &&
-           RIL.iccInfoPrivate.mbdn === contact.number)) {
-        return;
-      }
-      RIL.iccInfoPrivate.mbdn = contact.number;
-      if (DEBUG) {
-        debug("MBDN, alphaId="+contact.alphaId+" number="+contact.number);
-      }
-      contact.rilMessageType = "iccmbdn";
-      RIL.sendChromeMessage(contact);
-    }
-
-    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_MBDN,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Read USIM Phonebook.
+   * Read USIM/RUIM Phonebook.
    *
    * @param onsuccess   Callback to be called when success.
    * @param onerror     Callback to be called when error.
    */
   readPBR: function readPBR(onsuccess, onerror) {
     function callback(options) {
       let strLen = Buf.readInt32();
       let octetLen = strLen / 2, readLen = 0;
@@ -11604,17 +11382,17 @@ let ICCRecordHelper = {
     ICCIOHelper.loadLinearFixedEF({fileId: fileId,
                                    recordNumber: recordNumber,
                                    recordSize: this._iapRecordSize,
                                    callback: callback.bind(this),
                                    onerror: onerror});
   },
 
   /**
-   * Update USIM Phonebook EF_IAP.
+   * Update USIM/RUIM Phonebook EF_IAP.
    *
    * @see TS 131.102, clause 4.4.2.13
    *
    * @param fileId       EF id of the IAP.
    * @param recordNumber The identifier of the record shall be updated.
    * @param iap          The IAP value to be written.
    * @param onsuccess    Callback to be called when success.
    * @param onerror      Callback to be called when error.
@@ -11640,17 +11418,17 @@ let ICCRecordHelper = {
   },
 
   /**
    * Cache EF_Email record size.
    */
   _emailRecordSize: null,
 
   /**
-   * Read USIM Phonebook EF_EMAIL.
+   * Read USIM/RUIM Phonebook EF_EMAIL.
    *
    * @see TS 131.102, clause 4.4.2.13
    *
    * @param fileId       EF id of the EMAIL.
    * @param fileType     The type of the EMAIL, one of the ICC_USIM_TYPE* constants.
    * @param recordNumber The number of the record shall be loaded.
    * @param onsuccess    Callback to be called when success.
    * @param onerror      Callback to be called when error.
@@ -11689,17 +11467,17 @@ let ICCRecordHelper = {
     ICCIOHelper.loadLinearFixedEF({fileId: fileId,
                                    recordNumber: recordNumber,
                                    recordSize: this._emailRecordSize,
                                    callback: callback.bind(this),
                                    onerror: onerror});
   },
 
   /**
-   * Update USIM Phonebook EF_EMAIL.
+   * Update USIM/RUIM Phonebook EF_EMAIL.
    *
    * @see TS 131.102, clause 4.4.2.13
    *
    * @param pbr          Phonebook Reference File.
    * @param recordNumber The identifier of the record shall be updated.
    * @param email        The value to be written.
    * @param adnRecordId  The record Id of ADN, only needed if the fileType of Email is TYPE2.
    * @param onsuccess    Callback to be called when success.
@@ -11732,17 +11510,17 @@ let ICCRecordHelper = {
  },
 
   /**
    * Cache EF_ANR record size.
    */
   _anrRecordSize: null,
 
   /**
-   * Read USIM Phonebook EF_ANR.
+   * Read USIM/RUIM Phonebook EF_ANR.
    *
    * @see TS 131.102, clause 4.4.2.9
    *
    * @param fileId       EF id of the ANR.
    * @param fileType     One of the ICC_USIM_TYPE* constants.
    * @param recordNumber The number of the record shall be loaded.
    * @param onsuccess    Callback to be called when success.
    * @param onerror      Callback to be called when error.
@@ -11775,18 +11553,19 @@ let ICCRecordHelper = {
     }
 
     ICCIOHelper.loadLinearFixedEF({fileId: fileId,
                                    recordNumber: recordNumber,
                                    recordSize: this._anrRecordSize,
                                    callback: callback.bind(this),
                                    onerror: onerror});
   },
-  /**
-   * Update USIM Phonebook EF_ANR.
+
+  /**
+   * Update USIM/RUIM Phonebook EF_ANR.
    *
    * @see TS 131.102, clause 4.4.2.9
    *
    * @param pbr          Phonebook Reference File.
    * @param recordNumber The identifier of the record shall be updated.
    * @param number       The value to be written.
    * @param adnRecordId  The record Id of ADN, only needed if the fileType of Email is TYPE2.
    * @param onsuccess    Callback to be called when success.
@@ -11821,17 +11600,292 @@ let ICCRecordHelper = {
     ICCIOHelper.updateLinearFixedEF({fileId: fileId,
                                      recordNumber: recordNumber,
                                      dataWriter: dataWriter,
                                      callback: onsuccess,
                                      onerror: onerror});
   },
 
   /**
-   * Read the SPDI (Service Provider Display Information) from the ICC.
+   * Find free record id.
+   *
+   * @param fileId      EF id.
+   * @param onsuccess   Callback to be called when success.
+   * @param onerror     Callback to be called when error.
+   */
+  findFreeRecordId: function findFreeRecordId(fileId, onsuccess, onerror) {
+    function callback(options) {
+      let strLen = Buf.readInt32();
+      let octetLen = strLen / 2;
+      let readLen = 0;
+
+      while (readLen < octetLen) {
+        let octet = GsmPDUHelper.readHexOctet();
+        readLen++;
+        if (octet != 0xff) {
+          break;
+        }
+      }
+
+      if (readLen == octetLen) {
+        // Find free record.
+        if (onsuccess) {
+          onsuccess(options.p1);
+        }
+        return;
+      } else {
+        Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
+      }
+
+      Buf.readStringDelimiter(strLen);
+
+      if (options.p1 < options.totalRecords) {
+        ICCIOHelper.loadNextRecord(options);
+      } else {
+        // No free record found.
+        let error = onerror || debug;
+        error("No free record found.");
+      }
+    }
+
+    ICCIOHelper.loadLinearFixedEF({fileId: fileId,
+                                   callback: callback.bind(this),
+                                   onerror: onerror});
+  },
+};
+
+/**
+ * Helper for (U)SIM Records.
+ */
+let SimRecordHelper = {
+  /**
+   * Fetch (U)SIM records.
+   */
+  fetchSimRecords: function fetchSimRecords() {
+    RIL.getIMSI();
+    this.readAD();
+    this.readSST();
+  },
+
+  /**
+   * Read EF_phase.
+   * This EF is only available in SIM.
+   */
+  readSimPhase: function readSimPhase() {
+    function callback() {
+      let strLen = Buf.readInt32();
+
+      let phase = GsmPDUHelper.readHexOctet();
+      // If EF_phase is coded '03' or greater, an ME supporting STK shall
+      // perform the PROFILE DOWNLOAD procedure.
+      if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD &&
+          phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) {
+        RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE);
+      }
+
+      Buf.readStringDelimiter(strLen);
+    }
+
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_PHASE,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read the MSISDN from the (U)SIM.
+   */
+  readMSISDN: function readMSISDN() {
+    function callback(options) {
+      let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
+      if (!contact ||
+          (RIL.iccInfo.msisdn !== undefined &&
+           RIL.iccInfo.msisdn === contact.number)) {
+        return;
+      }
+      RIL.iccInfo.msisdn = contact.number;
+      if (DEBUG) debug("MSISDN: " + RIL.iccInfo.msisdn);
+      ICCUtilsHelper.handleICCInfoChange();
+    }
+
+    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_MSISDN,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read the AD (Administrative Data) from the (U)SIM.
+   */
+  readAD: function readAD() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      let octetLen = strLen / 2;
+      let ad = GsmPDUHelper.readHexOctetArray(octetLen);
+      Buf.readStringDelimiter(strLen);
+
+      if (DEBUG) {
+        let str = "";
+        for (let i = 0; i < ad.length; i++) {
+          str += ad[i] + ", ";
+        }
+        debug("AD: " + str);
+      }
+
+      // The 4th byte of the response is the length of MNC.
+      let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi,
+                                                      ad && ad[3]);
+      if (mccMnc) {
+        RIL.iccInfo.mcc = mccMnc.mcc;
+        RIL.iccInfo.mnc = mccMnc.mnc;
+        ICCUtilsHelper.handleICCInfoChange();
+      }
+    }
+
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_AD,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read the SPN (Service Provider Name) from the (U)SIM.
+   */
+  readSPN: function readSPN() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      let octetLen = strLen / 2;
+      let spnDisplayCondition = GsmPDUHelper.readHexOctet();
+      // Minus 1 because the first octet is used to store display condition.
+      let spn = ICCPDUHelper.readAlphaIdentifier(octetLen - 1);
+      Buf.readStringDelimiter(strLen);
+
+      if (DEBUG) {
+        debug("SPN: spn = " + spn +
+              ", spnDisplayCondition = " + spnDisplayCondition);
+      }
+
+      RIL.iccInfoPrivate.spnDisplayCondition = spnDisplayCondition;
+      RIL.iccInfo.spn = spn;
+      ICCUtilsHelper.updateDisplayCondition();
+      ICCUtilsHelper.handleICCInfoChange();
+    }
+
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_SPN,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read the (U)SIM Service Table from the (U)SIM.
+   */
+  readSST: function readSST() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      let octetLen = strLen / 2;
+      let sst = GsmPDUHelper.readHexOctetArray(octetLen);
+      Buf.readStringDelimiter(strLen);
+      RIL.iccInfoPrivate.sst = sst;
+      if (DEBUG) {
+        let str = "";
+        for (let i = 0; i < sst.length; i++) {
+          str += sst[i] + ", ";
+        }
+        debug("SST: " + str);
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) {
+        if (DEBUG) debug("MSISDN: MSISDN is available");
+        this.readMSISDN();
+      } else {
+        if (DEBUG) debug("MSISDN: MSISDN service is not available");
+      }
+
+      // Fetch SPN and PLMN list, if some of them are available.
+      if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
+        if (DEBUG) debug("SPN: SPN is available");
+        this.readSPN();
+      } else {
+        if (DEBUG) debug("SPN: SPN service is not available");
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("MDN")) {
+        if (DEBUG) debug("MDN: MDN available.");
+        this.readMBDN();
+      } else {
+        if (DEBUG) debug("MDN: MDN service is not available");
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) {
+        if (DEBUG) debug("SPDI: SPDI available.");
+        this.readSPDI();
+      } else {
+        if (DEBUG) debug("SPDI: SPDI service is not available");
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("PNN")) {
+        if (DEBUG) debug("PNN: PNN is available");
+        this.readPNN();
+      } else {
+        if (DEBUG) debug("PNN: PNN is not available");
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("OPL")) {
+        if (DEBUG) debug("OPL: OPL is available");
+        this.readOPL();
+      } else {
+        if (DEBUG) debug("OPL: OPL is not available");
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("CBMI")) {
+        this.readCBMI();
+      } else {
+        RIL.cellBroadcastConfigs.CBMI = null;
+      }
+      if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_CB")) {
+        this.readCBMID();
+      } else {
+        RIL.cellBroadcastConfigs.CBMID = null;
+      }
+      if (ICCUtilsHelper.isICCServiceAvailable("CBMIR")) {
+        this.readCBMIR();
+      } else {
+        RIL.cellBroadcastConfigs.CBMIR = null;
+      }
+      RIL._mergeAllCellBroadcastConfigs();
+    }
+
+    // ICC_EF_UST has the same value with ICC_EF_SST.
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_SST,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read (U)SIM MBDN. (Mailbox Dialling Number)
+   *
+   * @see TS 131.102, clause 4.2.60
+   */
+  readMBDN: function readMBDN() {
+    function callback(options) {
+      let contact = ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
+      if (!contact ||
+          (RIL.iccInfoPrivate.mbdn !== undefined &&
+           RIL.iccInfoPrivate.mbdn === contact.number)) {
+        return;
+      }
+      RIL.iccInfoPrivate.mbdn = contact.number;
+      if (DEBUG) {
+        debug("MBDN, alphaId="+contact.alphaId+" number="+contact.number);
+      }
+      contact.rilMessageType = "iccmbdn";
+      RIL.sendChromeMessage(contact);
+    }
+
+    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_MBDN,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read the SPDI (Service Provider Display Information) from the (U)SIM.
    *
    * See TS 131.102 section 4.2.66 for USIM and TS 51.011 section 10.3.50
    * for SIM.
    */
   readSPDI: function readSPDI() {
     function callback() {
       let strLen = Buf.readInt32();
       let octetLen = strLen / 2;
@@ -11978,17 +12032,17 @@ let ICCRecordHelper = {
     }
 
     ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CBMIR,
                                    callback: callback.bind(this),
                                    onerror: onerror.bind(this)});
   },
 
   /**
-   * Read OPL (Operator PLMN List) from USIM.
+   * Read OPL (Operator PLMN List) from (U)SIM.
    *
    * See 3GPP TS 31.102 Sec. 4.2.59 for USIM
    *     3GPP TS 51.011 Sec. 10.3.42 for SIM.
    */
   readOPL: function readOPL() {
     let opl = [];
     function callback(options) {
       let strLen = Buf.readInt32();
@@ -12048,17 +12102,17 @@ let ICCRecordHelper = {
       }
     }
 
     ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_OPL,
                                    callback: callback.bind(this)});
   },
 
   /**
-   * Read PNN (PLMN Network Name) from USIM.
+   * Read PNN (PLMN Network Name) from (U)SIM.
    *
    * See 3GPP TS 31.102 Sec. 4.2.58 for USIM
    *     3GPP TS 51.011 Sec. 10.3.41 for SIM.
    */
   readPNN: function readPNN() {
     function callback(options) {
       let pnnElement;
       let strLen = Buf.readInt32();
@@ -12114,63 +12168,16 @@ let ICCRecordHelper = {
     }
 
     let pnn = [];
     ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_PNN,
                                    callback: callback.bind(this)});
   },
 
   /**
-   * Find free record id.
-   *
-   * @param fileId      EF id.
-   * @param onsuccess   Callback to be called when success.
-   * @param onerror     Callback to be called when error.
-   */
-  findFreeRecordId: function findFreeRecordId(fileId, onsuccess, onerror) {
-    function callback(options) {
-      let strLen = Buf.readInt32();
-      let octetLen = strLen / 2;
-      let readLen = 0;
-
-      while (readLen < octetLen) {
-        let octet = GsmPDUHelper.readHexOctet();
-        readLen++;
-        if (octet != 0xff) {
-          break;
-        }
-      }
-
-      if (readLen == octetLen) {
-        // Find free record.
-        if (onsuccess) {
-          onsuccess(options.p1);
-        }
-        return;
-      } else {
-        Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
-      }
-
-      Buf.readStringDelimiter(strLen);
-
-      if (options.p1 < options.totalRecords) {
-        ICCIOHelper.loadNextRecord(options);
-      } else {
-        // No free record found.
-        let error = onerror || debug;
-        error("No free record found.");
-      }
-    }
-
-    ICCIOHelper.loadLinearFixedEF({fileId: fileId,
-                                   callback: callback.bind(this),
-                                   onerror: onerror});
-  },
-
-  /**
    *  Read the list of PLMN (Public Land Mobile Network) entries
    *  We cannot directly rely on readSwappedNibbleBcdToString(),
    *  since it will no correctly handle some corner-cases that are
    *  not a problem in our case (0xFF 0xFF 0xFF).
    *
    *  @param length The number of PLMN records.
    *  @return An array of string corresponding to the PLMNs.
    */
@@ -12228,16 +12235,233 @@ let ICCRecordHelper = {
         break;
       }
       index ++;
     }
     return plmnList;
   },
 };
 
+let RuimRecordHelper = {
+  fetchRuimRecords: function fetchRuimRecords() {
+    this.getIMSI_M();
+    this.readCST();
+    this.readCDMAHome();
+    RIL.getCdmaSubscription();
+  },
+
+  /**
+   * Get IMSI_M from CSIM/RUIM.
+   * See 3GPP2 C.S0065 Sec. 5.2.2
+   */
+  getIMSI_M: function getIMSI_M() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      let encodedImsi = GsmPDUHelper.readHexOctetArray(strLen / 2);
+      Buf.readStringDelimiter(strLen);
+
+      if ((encodedImsi[CSIM_IMSI_M_PROGRAMMED_BYTE] & 0x80)) { // IMSI_M programmed
+        RIL.iccInfoPrivate.imsi = this.decodeIMSI(encodedImsi);
+        RIL.sendChromeMessage({rilMessageType: "iccimsi",
+                               imsi: RIL.iccInfoPrivate.imsi});
+
+        let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi);
+        if (mccMnc) {
+          RIL.iccInfo.mcc = mccMnc.mcc;
+          RIL.iccInfo.mnc = mccMnc.mnc;
+          ICCUtilsHelper.handleICCInfoChange();
+        }
+      }
+    }
+
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_IMSI_M,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Decode IMSI from IMSI_M
+   * See 3GPP2 C.S0005 Sec. 2.3.1
+   * +---+---------+------------+---+--------+---------+---+---------+--------+
+   * |RFU|   MCC   | programmed |RFU|  MNC   |  MIN1   |RFU|   MIN2  |  CLASS |
+   * +---+---------+------------+---+--------+---------+---+---------+--------+
+   * | 6 | 10 bits |   8 bits   | 1 | 7 bits | 24 bits | 6 | 10 bits | 8 bits |
+   * +---+---------+------------+---+--------+---------+---+---------+--------+
+   */
+  decodeIMSI: function decodeIMSI(encodedImsi) {
+    // MCC: 10 bits, 3 digits
+    let encodedMCC = ((encodedImsi[CSIM_IMSI_M_MCC_BYTE + 1] & 0x03) << 8) +
+                      (encodedImsi[CSIM_IMSI_M_MCC_BYTE] & 0xff);
+    let mcc = this.decodeIMSIValue(encodedMCC, 3);
+
+    // MNC: 7 bits, 2 digits
+    let encodedMNC =  encodedImsi[CSIM_IMSI_M_MNC_BYTE] & 0x7f;
+    let mnc = this.decodeIMSIValue(encodedMNC, 2);
+
+    // MIN2: 10 bits, 3 digits
+    let encodedMIN2 = ((encodedImsi[CSIM_IMSI_M_MIN2_BYTE + 1] & 0x03) << 8) +
+                       (encodedImsi[CSIM_IMSI_M_MIN2_BYTE] & 0xff);
+    let min2 = this.decodeIMSIValue(encodedMIN2, 3);
+
+    // MIN1: 10+4+10 bits, 3+1+3 digits
+    let encodedMIN1First3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 2] & 0xff) << 2) +
+                             ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0xc0) >> 6);
+    let min1First3 = this.decodeIMSIValue(encodedMIN1First3, 3);
+
+    let encodedFourthDigit = (encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x3c) >> 2;
+    if (encodedFourthDigit > 9) {
+      encodedFourthDigit = 0;
+    }
+    let fourthDigit = encodedFourthDigit.toString();
+
+    let encodedMIN1Last3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x03) << 8) +
+                            (encodedImsi[CSIM_IMSI_M_MIN1_BYTE] & 0xff);
+    let min1Last3 = this.decodeIMSIValue(encodedMIN1Last3, 3);
+
+    return mcc + mnc + min2 + min1First3 + fourthDigit + min1Last3;
+  },
+
+  /**
+   * Decode IMSI Helper function
+   * See 3GPP2 C.S0005 section 2.3.1.1
+   */
+  decodeIMSIValue: function decodeIMSIValue(encoded, length) {
+    let offset = length === 3 ? 111 : 11;
+    let value = encoded + offset;
+
+    for (let base = 10, temp = value, i = 0; i < length; i++) {
+      if (temp % 10 === 0) {
+        value -= base;
+      }
+      temp = Math.floor(value / base);
+      base = base * 10;
+    }
+
+    let s = value.toString();
+    while (s.length < length) {
+      s = "0" + s;
+    }
+
+    return s;
+  },
+
+  /**
+   * Read CDMAHOME for CSIM.
+   * See 3GPP2 C.S0023 Sec. 3.4.8.
+   */
+  readCDMAHome: function readCDMAHome() {
+    function callback(options) {
+      let strLen = Buf.readInt32();
+      let tempOctet = GsmPDUHelper.readHexOctet();
+      cdmaHomeSystemId.push(((GsmPDUHelper.readHexOctet() & 0x7f) << 8) | tempOctet);
+      tempOctet = GsmPDUHelper.readHexOctet();
+      cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet);
+
+      // Consuming the last octet: band class.
+      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
+
+      Buf.readStringDelimiter(strLen);
+      if (options.p1 < options.totalRecords) {
+        ICCIOHelper.loadNextRecord(options);
+      } else {
+        if (DEBUG) {
+          debug("CDMAHome system id: " + JSON.stringify(cdmaHomeSystemId));
+          debug("CDMAHome network id: " + JSON.stringify(cdmaHomeNetworkId));
+        }
+        RIL.cdmaHome = {
+          systemId: cdmaHomeSystemId,
+          networkId: cdmaHomeNetworkId
+        };
+      }
+    }
+
+    let cdmaHomeSystemId = [], cdmaHomeNetworkId = [];
+    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_CSIM_CDMAHOME,
+                                   callback: callback.bind(this)});
+  },
+
+  /**
+   * Read CDMA Service Table.
+   * See 3GPP2 C.S0023 Sec. 3.4.18
+   */
+  readCST: function readCST() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      RIL.iccInfoPrivate.cst = GsmPDUHelper.readHexOctetArray(strLen / 2);
+      Buf.readStringDelimiter(strLen);
+
+      if (DEBUG) {
+        let str = "";
+        for (let i = 0; i < RIL.iccInfoPrivate.cst.length; i++) {
+          str += RIL.iccInfoPrivate.cst[i] + ", ";
+        }
+        debug("CST: " + str);
+      }
+
+      if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
+        if (DEBUG) debug("SPN: SPN is available");
+        this.readSPN();
+      }
+    }
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_CST,
+                                   callback: callback.bind(this)});
+  },
+
+  readSPN: function readSPN() {
+    function callback() {
+      let strLen = Buf.readInt32();
+      let octetLen = strLen / 2;
+      let displayCondition = GsmPDUHelper.readHexOctet();
+      let codingScheme = GsmPDUHelper.readHexOctet();
+      // Skip one octet: language indicator.
+      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
+      let readLen = 3;
+
+      // SPN String ends up with 0xff.
+      let userDataBuffer = [];
+
+      while (readLen < octetLen) {
+        let octet = GsmPDUHelper.readHexOctet();
+        readLen++;
+        if (octet == 0xff) {
+          break;
+        }
+        userDataBuffer.push(octet);
+      }
+
+      BitBufferHelper.startRead(userDataBuffer);
+
+      let msgLen;
+      switch (CdmaPDUHelper.getCdmaMsgEncoding(codingScheme)) {
+      case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
+        msgLen = Math.floor(userDataBuffer.length * 8 / 7);
+        break;
+      case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
+        msgLen = userDataBuffer.length;
+        break;
+      case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
+        msgLen = Math.floor(userDataBuffer.length / 2);
+        break;
+      }
+
+      RIL.iccInfo.spn = CdmaPDUHelper.decodeCdmaPDUMsg(codingScheme, null, msgLen);
+      if (DEBUG) {
+        debug("CDMA SPN: " + RIL.iccInfo.spn +
+              ", Display condition: " + displayCondition);
+      }
+      RIL.iccInfoPrivate.spnDisplayCondition = displayCondition;
+      Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
+      Buf.readStringDelimiter(strLen);
+    }
+
+    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_SPN,
+                                   callback: callback.bind(this)});
+  }
+};
+
 /**
  * Helper functions for ICC utilities.
  */
 let ICCUtilsHelper = {
   /**
    * Get network names by using EF_OPL and EF_PNN
    *
    * @See 3GPP TS 31.102 sec. 4.2.58 and sec. 4.2.59 for USIM,
@@ -13174,233 +13398,16 @@ let ICCContactHelper = {
     let gotIAPCb = function gotIAPCb(iap) {
       iap[pbr[field].indexInIAP] = value;
       ICCRecordHelper.updateIAP(pbr.iap.fileId, recordNumber, iap, onsuccess, onerror);
     }.bind(this);
     ICCRecordHelper.readIAP(pbr.iap.fileId, recordNumber, gotIAPCb, onerror);
   },
 };
 
-let RuimRecordHelper = {
-  fetchRuimRecords: function fetchRuimRecords() {
-    this.getIMSI_M();
-    this.readCST();
-    this.readCDMAHome();
-    RIL.getCdmaSubscription();
-  },
-
-  /**
-   * Get IMSI_M from CSIM/RUIM.
-   * See 3GPP2 C.S0065 Sec. 5.2.2
-   */
-  getIMSI_M: function getIMSI_M() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      let encodedImsi = GsmPDUHelper.readHexOctetArray(strLen / 2);
-      Buf.readStringDelimiter(strLen);
-
-      if ((encodedImsi[CSIM_IMSI_M_PROGRAMMED_BYTE] & 0x80)) { // IMSI_M programmed
-        RIL.iccInfoPrivate.imsi = this.decodeIMSI(encodedImsi);
-        RIL.sendChromeMessage({rilMessageType: "iccimsi",
-                               imsi: RIL.iccInfoPrivate.imsi});
-
-        let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi);
-        if (mccMnc) {
-          RIL.iccInfo.mcc = mccMnc.mcc;
-          RIL.iccInfo.mnc = mccMnc.mnc;
-          ICCUtilsHelper.handleICCInfoChange();
-        }
-      }
-    }
-
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_IMSI_M,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Decode IMSI from IMSI_M
-   * See 3GPP2 C.S0005 Sec. 2.3.1
-   * +---+---------+------------+---+--------+---------+---+---------+--------+
-   * |RFU|   MCC   | programmed |RFU|  MNC   |  MIN1   |RFU|   MIN2  |  CLASS |
-   * +---+---------+------------+---+--------+---------+---+---------+--------+
-   * | 6 | 10 bits |   8 bits   | 1 | 7 bits | 24 bits | 6 | 10 bits | 8 bits |
-   * +---+---------+------------+---+--------+---------+---+---------+--------+
-   */
-  decodeIMSI: function decodeIMSI(encodedImsi) {
-    // MCC: 10 bits, 3 digits
-    let encodedMCC = ((encodedImsi[CSIM_IMSI_M_MCC_BYTE + 1] & 0x03) << 8) +
-                      (encodedImsi[CSIM_IMSI_M_MCC_BYTE] & 0xff);
-    let mcc = this.decodeIMSIValue(encodedMCC, 3);
-
-    // MNC: 7 bits, 2 digits
-    let encodedMNC =  encodedImsi[CSIM_IMSI_M_MNC_BYTE] & 0x7f;
-    let mnc = this.decodeIMSIValue(encodedMNC, 2);
-
-    // MIN2: 10 bits, 3 digits
-    let encodedMIN2 = ((encodedImsi[CSIM_IMSI_M_MIN2_BYTE + 1] & 0x03) << 8) +
-                       (encodedImsi[CSIM_IMSI_M_MIN2_BYTE] & 0xff);
-    let min2 = this.decodeIMSIValue(encodedMIN2, 3);
-
-    // MIN1: 10+4+10 bits, 3+1+3 digits
-    let encodedMIN1First3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 2] & 0xff) << 2) +
-                             ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0xc0) >> 6);
-    let min1First3 = this.decodeIMSIValue(encodedMIN1First3, 3);
-
-    let encodedFourthDigit = (encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x3c) >> 2;
-    if (encodedFourthDigit > 9) {
-      encodedFourthDigit = 0;
-    }
-    let fourthDigit = encodedFourthDigit.toString();
-
-    let encodedMIN1Last3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x03) << 8) +
-                            (encodedImsi[CSIM_IMSI_M_MIN1_BYTE] & 0xff);
-    let min1Last3 = this.decodeIMSIValue(encodedMIN1Last3, 3);
-
-    return mcc + mnc + min2 + min1First3 + fourthDigit + min1Last3;
-  },
-
-  /**
-   * Decode IMSI Helper function
-   * See 3GPP2 C.S0005 section 2.3.1.1
-   */
-  decodeIMSIValue: function decodeIMSIValue(encoded, length) {
-    let offset = length === 3 ? 111 : 11;
-    let value = encoded + offset;
-
-    for (let base = 10, temp = value, i = 0; i < length; i++) {
-      if (temp % 10 === 0) {
-        value -= base;
-      }
-      temp = Math.floor(value / base);
-      base = base * 10;
-    }
-
-    let s = value.toString();
-    while (s.length < length) {
-      s = "0" + s;
-    }
-
-    return s;
-  },
-
-  /**
-   * Read CDMAHOME for CSIM.
-   * See 3GPP2 C.S0023 Sec. 3.4.8.
-   */
-  readCDMAHome: function readCDMAHome() {
-    function callback(options) {
-      let strLen = Buf.readInt32();
-      let tempOctet = GsmPDUHelper.readHexOctet();
-      cdmaHomeSystemId.push(((GsmPDUHelper.readHexOctet() & 0x7f) << 8) | tempOctet);
-      tempOctet = GsmPDUHelper.readHexOctet();
-      cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet);
-
-      // Consuming the last octet: band class.
-      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
-
-      Buf.readStringDelimiter(strLen);
-      if (options.p1 < options.totalRecords) {
-        ICCIOHelper.loadNextRecord(options);
-      } else {
-        if (DEBUG) {
-          debug("CDMAHome system id: " + JSON.stringify(cdmaHomeSystemId));
-          debug("CDMAHome network id: " + JSON.stringify(cdmaHomeNetworkId));
-        }
-        RIL.cdmaHome = {
-          systemId: cdmaHomeSystemId,
-          networkId: cdmaHomeNetworkId
-        };
-      }
-    }
-
-    let cdmaHomeSystemId = [], cdmaHomeNetworkId = [];
-    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_CSIM_CDMAHOME,
-                                   callback: callback.bind(this)});
-  },
-
-  /**
-   * Read CDMA Service Table.
-   * See 3GPP2 C.S0023 Sec. 3.4.18
-   */
-  readCST: function readCST() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      // Each octet is encoded into two chars.
-      RIL.iccInfoPrivate.cst = GsmPDUHelper.readHexOctetArray(strLen / 2);
-      Buf.readStringDelimiter(strLen);
-
-      if (DEBUG) {
-        let str = "";
-        for (let i = 0; i < RIL.iccInfoPrivate.cst.length; i++) {
-          str += RIL.iccInfoPrivate.cst[i] + ", ";
-        }
-        debug("CST: " + str);
-      }
-
-      if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
-        if (DEBUG) debug("SPN: SPN is available");
-        this.readSPN();
-      }
-    }
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_CST,
-                                   callback: callback.bind(this)});
-  },
-
-  readSPN: function readSPN() {
-    function callback() {
-      let strLen = Buf.readInt32();
-      let octetLen = strLen / 2;
-      let displayCondition = GsmPDUHelper.readHexOctet();
-      let codingScheme = GsmPDUHelper.readHexOctet();
-      // Skip one octet: language indicator.
-      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
-      let readLen = 3;
-
-      // SPN String ends up with 0xff.
-      let userDataBuffer = [];
-
-      while (readLen < octetLen) {
-        let octet = GsmPDUHelper.readHexOctet();
-        readLen++;
-        if (octet == 0xff) {
-          break;
-        }
-        userDataBuffer.push(octet);
-      }
-
-      BitBufferHelper.startRead(userDataBuffer);
-
-      let msgLen;
-      switch (CdmaPDUHelper.getCdmaMsgEncoding(codingScheme)) {
-      case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
-        msgLen = Math.floor(userDataBuffer.length * 8 / 7);
-        break;
-      case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
-        msgLen = userDataBuffer.length;
-        break;
-      case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
-        msgLen = Math.floor(userDataBuffer.length / 2);
-        break;
-      }
-
-      RIL.iccInfo.spn = CdmaPDUHelper.decodeCdmaPDUMsg(codingScheme, null, msgLen);
-      if (DEBUG) {
-        debug("CDMA SPN: " + RIL.iccInfo.spn +
-              ", Display condition: " + displayCondition);
-      }
-      RIL.iccInfoPrivate.spnDisplayCondition = displayCondition;
-      Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
-      Buf.readStringDelimiter(strLen);
-    }
-
-    ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_SPN,
-                                   callback: callback.bind(this)});
-  }
-};
-
 /**
  * Global stuff.
  */
 
 // Initialize buffers. This is a separate function so that unit tests can
 // re-initialize the buffers at will.
 Buf.init();
 
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -2134,17 +2134,17 @@ add_test(function test_mcc_mnc_parsing()
   run_next_test();
  });
 
  /**
   * Verify reading EF_AD and parsing MCC/MNC
   */
 add_test(function test_reading_ad_and_parsing_mcc_mnc() {
   let worker = newUint8Worker();
-  let record = worker.ICCRecordHelper;
+  let record = worker.SimRecordHelper;
   let helper = worker.GsmPDUHelper;
   let ril    = worker.RIL;
   let buf    = worker.Buf;
   let io     = worker.ICCIOHelper;
 
   function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) {
     ril.iccInfoPrivate.imsi = imsi;
 
@@ -2181,17 +2181,17 @@ add_test(function test_reading_ad_and_pa
   do_test(undefined, "310260542718417", "310", "260");
   do_test(0x02,      "310260542718417", "310", "26" );
 
   run_next_test();
 });
 
 add_test(function test_reading_optional_efs() {
   let worker = newUint8Worker();
-  let record = worker.ICCRecordHelper;
+  let record = worker.SimRecordHelper;
   let gsmPdu = worker.GsmPDUHelper;
   let ril    = worker.RIL;
   let buf    = worker.Buf;
   let io     = worker.ICCIOHelper;
 
   function buildSST(supportedEf) {
     let sst = [];
     let len = supportedEf.length;
@@ -2261,8 +2261,79 @@ add_test(function test_reading_optional_
   let supportedEf = ["MSISDN", "MDN"];
   ril.appType = CARD_APPTYPE_SIM;
   do_test(buildSST(supportedEf), supportedEf);
   ril.appType = CARD_APPTYPE_USIM;
   do_test(buildSST(supportedEf), supportedEf);
 
   run_next_test();
 });
+
+/**
+ * Verify fetchSimRecords.
+ */
+add_test(function test_fetch_sim_recodes() {
+  let worker = newWorker();
+  let RIL = worker.RIL;
+  let iccRecord = worker.ICCRecordHelper;
+  let simRecord = worker.SimRecordHelper;
+
+  function testFetchSimRecordes(expectCalled) {
+    let ifCalled = [];
+
+    RIL.getIMSI = function () {
+      ifCalled.push("getIMSI");
+    };
+
+    simRecord.readAD = function () {
+      ifCalled.push("readAD");
+    };
+
+    simRecord.readSST = function () {
+      ifCalled.push("readSST");
+    };
+
+    simRecord.fetchSimRecords();
+
+    for (let i = 0; i < expectCalled.length; i++ ) {
+      if (ifCalled[i] != expectCalled[i]) {
+        do_print(expectCalled[i] + " is not called.");
+        do_check_true(false);
+      }
+    }
+  }
+
+  let expectCalled = ["getIMSI", "readAD", "readSST"];
+  testFetchSimRecordes(expectCalled);
+
+  run_next_test();
+});
+
+add_test(function test_fetch_icc_recodes() {
+  let worker = newWorker();
+  let RIL = worker.RIL;
+  let iccRecord = worker.ICCRecordHelper;
+  let simRecord = worker.SimRecordHelper;
+  let ruimRecord = worker.RuimRecordHelper;
+  let fetchTag = 0x00;
+
+  simRecord.fetchSimRecords = function () {
+    fetchTag = 0x01;
+  };
+
+  ruimRecord.fetchRuimRecords = function () {
+    fetchTag = 0x02;
+  };
+
+  RIL.appType = CARD_APPTYPE_SIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x01);
+
+  RIL.appType = CARD_APPTYPE_RUIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x02);
+
+  RIL.appType = CARD_APPTYPE_USIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x01);
+
+  run_next_test();
+});
--- a/dom/system/gonk/tests/test_ril_worker_ruim.js
+++ b/dom/system/gonk/tests/test_ril_worker_ruim.js
@@ -67,17 +67,16 @@ add_test(function test_ruim_file_path_id
               EF_PATH_MF_SIM + EF_PATH_DF_CDMA);
 
   run_next_test();
 });
 
 add_test(function test_fetch_ruim_recodes() {
   let worker = newWorker();
   let RIL = worker.RIL;
-  let iccHelper = worker.ICCRecordHelper;
   let ruimHelper = worker.RuimRecordHelper;
 
   function testFetchRuimRecordes(expectCalled) {
     let ifCalled = [];
 
     ruimHelper.getIMSI_M = function () {
       ifCalled.push("getIMSI_M");
     };
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ b/dom/telephony/gonk/TelephonyProvider.js
@@ -491,24 +491,30 @@ TelephonyProvider.prototype = {
       number: aCall.number,
       duration: duration,
       direction: aCall.isOutgoing ? "outgoing" : "incoming"
     };
     gSystemMessenger.broadcastMessage("telephony-call-ended", data);
 
     this._updateCallAudioState(aCall, null);
 
-    this._notifyAllListeners("callStateChanged", [aClientId,
-                                                  aCall.callIndex,
-                                                  aCall.state,
-                                                  aCall.number,
-                                                  aCall.isActive,
-                                                  aCall.isOutgoing,
-                                                  aCall.isEmergency,
-                                                  aCall.isConference]);
+    if (!aCall.failCause ||
+        aCall.failCause === RIL.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING) {
+      this._notifyAllListeners("callStateChanged", [aClientId,
+                                                    aCall.callIndex,
+                                                    aCall.state,
+                                                    aCall.number,
+                                                    aCall.isActive,
+                                                    aCall.isOutgoing,
+                                                    aCall.isEmergency,
+                                                    aCall.isConference]);
+      return;
+    }
+
+    this.notifyCallError(aClientId, aCall.callIndex, aCall.failCause);
   },
 
   /**
    * Handle call error.
    */
   notifyCallError: function notifyCallError(aClientId, aCallIndex, aErrorMsg) {
     this._notifyAllListeners("notifyError", [aClientId, aCallIndex, aErrorMsg]);
   },
--- a/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/frameQuotaSessionOnly.html
@@ -1,41 +1,32 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <title>slave for sessionStorage test</title>
 
 <script type="text/javascript" src="interOriginFrame.js"></script>
 <script type="text/javascript">
 
 const DOM_QUOTA_REACHED = 2152924150;
-const Cc = SpecialPowers.Cc;
 
 function checkException(func, exc)
 {
   var exceptionThrew = false;
   try {
     func();
   }
   catch (ex) {
     exceptionThrew = true;
     is(ex.result, exc, "Expected "+exc+" exception");
   }
   ok(exceptionThrew, "Exception "+exc+" threw at "+location);
 }
 
 function doStep()
 {
-  var io = Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
-
   var query = location.search.substring(1);
   var queries = query.split("&");
 
   var operation = queries[0];
   var keyName = queries[1];
   var result = queries[2];
 
   switch (result)
@@ -90,28 +81,31 @@ function doStep()
       break;
 
     case "":
     default:
       switch (operation)
       {
         case "clear":
           localStorage.clear();
-          cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
           break;
       }
 
       break;
   }
 
   // Just inform the master we are finished now
   postMsg("done");
   return false;
 }
 
+function startTest() {
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], function() {
+    postMsg('frame loaded');
+  });
+}
 </script>
 
 </head>
 
-<body onload="postMsg('frame loaded');">
+<body onload="startTest();">
 </body>
 </html>
--- a/dom/tests/mochitest/localstorage/localStorageCommon.js
+++ b/dom/tests/mochitest/localstorage/localStorageCommon.js
@@ -31,16 +31,15 @@ function localStorageClearAll()
 
 function localStorageClearDomain(domain)
 {
   os().notifyObservers(null, "browser:purge-domain-data", domain);
 }
 
 function os()
 {
-  return SpecialPowers.Cc["@mozilla.org/observer-service;1"]
-                      .getService(SpecialPowers.Ci.nsIObserverService);
+  return SpecialPowers.Services.obs;
 }
 
 function notify(top)
 {
   os().notifyObservers(null, top, null);
 }
--- a/dom/tests/mochitest/localstorage/mochitest.ini
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -17,18 +17,17 @@ support-files =
   localStorageCommon.js
 
 [test_appIsolation.html]
 [test_brokenUTF-16.html]
 [test_bug600307-DBOps.html]
 [test_bug746272-1.html]
 [test_bug746272-2.html]
 [test_cookieBlock.html]
-[test_cookieSession-phase1.html]
-[test_cookieSession-phase2.html]
+[test_cookieSession.html]
 [test_embededNulls.html]
 [test_keySync.html]
 [test_localStorageBase.html]
 [test_localStorageBaseSessionOnly.html]
 [test_localStorageCookieSettings.html]
 [test_localStorageEnablePref.html]
 [test_localStorageKeyOrder.html]
 [test_localStorageOriginsDiff.html]
--- a/dom/tests/mochitest/localstorage/test_cookieBlock.html
+++ b/dom/tests/mochitest/localstorage/test_cookieBlock.html
@@ -4,47 +4,39 @@
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
 function startTest()
 {
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DENY);
-
   try {
     localStorage.setItem("blocked", "blockedvalue");
     ok(false, "Exception for localStorage.setItem, ACCESS_DENY");
   }
   catch (ex) {
     ok(true, "Exception for localStorage.setItem, ACCESS_DENY");
   }
 
   try {
     localStorage.getItem("blocked");
     ok(false, "Exception for localStorage.getItem, ACCESS_DENY");
   }
   catch (ex) {
     ok(true, "Exception for localStorage.getItem, ACCESS_DENY");
   }
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
+SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': false, 'context': document}], startTest);
+
 </script>
 
 </head>
 
-<body onload="startTest();">
+<body>
 
 </body>
 </html>
deleted file mode 100644
--- a/dom/tests/mochitest/localstorage/test_cookieSession-phase1.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title>cookie per-session only test</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/*
-  Set cookie access to be just per session and store to the localStorage.
-  Content stored must prevail only for session of the browser, so it must
-  be accessible in another window we try to access that key in the same
-  storage.
- */
-
-function startTest()
-{
-  localStorage.setItem("persistent1", "persistent value 1");
-  localStorage.setItem("persistent2", "persistent value 2");
-
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
-
-  localStorage.setItem("session only", "session value");
-  is(localStorage.getItem("session only"), "session value");
-  is(localStorage.getItem("persistent1"), "persistent value 1");
-  is(localStorage.getItem("persistent2"), "persistent value 2");
-
-  SimpleTest.finish();
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body onload="startTest();">
-
-</body>
-</html>
deleted file mode 100644
--- a/dom/tests/mochitest/localstorage/test_cookieSession-phase2.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<title>cookie per-session only test</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-function startTest()
-{
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-
-  is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
-  is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
-  is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
-
-  localStorage.setItem("persistent1", "changed persistent value 1");
-  localStorage.removeItem("persistent2");
-
-  is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
-  is(localStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
-  is(localStorage.getItem("persistent2"), null, "Persistent value removed");
-
-  // This clear has to delete only changes made in session only mode
-  localStorage.clear();
-
-  is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
-  is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
-
-  localStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
-  is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
-  is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
-  is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
-  is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
-
-  is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(localStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
-  is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
-  is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
-  localStorage.clear();
-
-  is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
-  is(localStorage.getItem("persistent1"), null, "Persistent value not present after delete");
-  is(localStorage.getItem("persistent2"), null, "Persistent value not present after delete");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
-
-  is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
-  is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
-  is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
-  SimpleTest.finish();
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body onload="startTest();">
-
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/localstorage/test_cookieSession.html
@@ -0,0 +1,132 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>cookie per-session only test</title>
+
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+/*
+  Set cookie access to be just per session and store to the localStorage.
+  Content stored must prevail only for session of the browser, so it must
+  be accessible in another window we try to access that key in the same
+  storage.
+ */
+
+function pushCookie(aPermission, aNext) {
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': aPermission, 'context': document}], aNext);
+}
+
+function test1() {
+  localStorage.setItem("persistent1", "persistent value 1");
+  localStorage.setItem("persistent2", "persistent value 2");
+
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, test1_b);
+}
+
+function test1_b() {
+  localStorage.setItem("session only", "session value");
+  parent.is(localStorage.getItem("session only"), "session value");
+  parent.is(localStorage.getItem("persistent1"), "persistent value 1");
+  parent.is(localStorage.getItem("persistent2"), "persistent value 2");
+
+  window.location.search = '?2';
+}
+
+function test2()
+{
+  parent.is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+  parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+  parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+
+  localStorage.setItem("persistent1", "changed persistent value 1");
+  localStorage.removeItem("persistent2");
+
+  parent.is(localStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+  parent.is(localStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
+  parent.is(localStorage.getItem("persistent2"), null, "Persistent value removed");
+
+  // This clear has to delete only changes made in session only mode
+  localStorage.clear();
+
+  parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+  parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+  parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+
+  localStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
+
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT, function() { window.location.search = '?3'; });
+}
+
+function test3() {
+  parent.is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
+  parent.is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+  parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+  parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, function() { window.location.search = '?4'; });
+}
+
+function test4() {
+  parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+  parent.is(localStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
+  parent.is(localStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
+  parent.is(localStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
+
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT, function() { window.location.search = '?5'; });
+}
+
+function test5() {
+  localStorage.clear();
+
+  parent.is(localStorage.getItem("session only"), null, "No value when cookies are in default mode");
+  parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present after delete");
+  parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present after delete");
+
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, function() { window.location.search = '?6'; });
+}
+
+function test6() {
+  parent.is(localStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+  parent.is(localStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+  parent.is(localStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+  parent.is(localStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+
+  parent.SimpleTest.finish();
+}
+
+function startTest() {
+  switch (location.search) {
+    case '?1':
+      test1();
+      break;
+    case '?2':
+      test2();
+      break;
+    case '?3':
+      test3();
+      break;
+    case '?4':
+      test4();
+      break;
+    case '?5':
+      test5();
+      break;
+    case '?6':
+      test6();
+      break;
+    default:
+      SimpleTest.waitForExplicitFinish();
+      var iframe = document.createElement('iframe');
+      iframe.src = 'test_cookieSession.html?1';
+      document.body.appendChild(iframe);
+  }
+}
+</script>
+
+</head>
+
+<body onload="startTest()">
+</body>
+</html>
--- a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -4,24 +4,20 @@
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
 function startTest()
 {
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], test1);
+}
 
-
+function test1() {
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
   is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
   is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], undefined, "Nonexisting item is undefined (array access)");
   is(localStorage.nonexisting, undefined, "Nonexisting item is undefined (property access)");
@@ -190,19 +186,16 @@ function startTest()
   is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
   localStorage.clear();
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
--- a/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html
@@ -2,46 +2,46 @@
 <head>
 <title>localStorage cookies settings test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-window.Services = SpecialPowers.Services;
+SimpleTest.waitForExplicitFinish();
 
 // Set cookies behavior to "always reject".
-Services.prefs.setIntPref("network.cookie.cookieBehavior", 2);
-try {
-  localStorage.setItem("contentkey", "test-value");
-  ok(false, "Setting localStorageItem should throw a security exception");
-}
-catch(ex) {
-  is(ex.name, "SecurityError");
+SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 2]]},
+                          test1);
+
+function test1() {
+  try {
+    localStorage.setItem("contentkey", "test-value");
+    ok(false, "Setting localStorageItem should throw a security exception");
+  }
+  catch(ex) {
+    is(ex.name, "SecurityError");
+  }
+
+  // Set cookies behavior to "ask every time".
+  SpecialPowers.pushPrefEnv({"set": [["network.cookie.lifetimePolicy", 1]],
+                             "clear": [["network.cookie.cookieBehavior"]]},
+                            test2);
 }
 
-try {
-  Services.prefs.clearUserPref("network.cookie.cookieBehavior");
-}
-catch (ex) {}
-
+function test2() {
+  try {
+    localStorage.setItem("contentkey", "test-value");
+    ok(false, "Setting localStorageItem should throw a security exception");
+  }
+  catch(ex) {
+    is(ex.name, "SecurityError");
+  }
 
-// Set cookies behavior to "ask every time".
-Services.prefs.setIntPref("network.cookie.lifetimePolicy", 1);
-try {
-  localStorage.setItem("contentkey", "test-value");
-  ok(false, "Setting localStorageItem should throw a security exception");
+  SimpleTest.finish();
 }
-catch(ex) {
-  is(ex.name, "SecurityError");
-}
-
-try {
-  Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
-}
-catch (ex) {}
 
 </script>
 </head>
 <body>
 </body>
 </html>
--- a/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageEnablePref.html
@@ -2,77 +2,55 @@
 <head>
 <title>localStorage enable preference test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-function setDOMStorageEnabled(enabled)
-{
-  var prefs = SpecialPowers.Cc["@mozilla.org/preferences-service;1"]
-              .getService(SpecialPowers.Ci.nsIPrefBranch);
-  prefs.setBoolPref("dom.storage.enabled", enabled);
-}
-
 function checkException(func, exc)
 {
   var exceptionThrew = false;
   try {
     func();
   }
   catch (ex) {
     exceptionThrew = true;
     is(ex.name, exc, "Expected "+exc+" exception");
   }
   ok(exceptionThrew, "Exception "+exc+" threw");
 }
 
-function startTest()
-{
-  setDOMStorageEnabled(true);
-
+var storage;
+function test1() {
   is(typeof(window.localStorage), "object", "Storage is present");
-  var storage = window.localStorage;
+  storage = window.localStorage;
 
-  setDOMStorageEnabled(false);
+  SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", false]]}, test2);
+}
 
+function test2() {
   is(window.localStorage, null, "Storage is null");
 
   checkException(function() {storage.setItem("test", "value");}, "SecurityError");
 
-  setDOMStorageEnabled(true);
+  SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", true]]}, test3);
+}
 
+function test3() {
   is(typeof(window.localStorage), "object", "Storage is present again");
   storage.setItem("test", "value");
   ok(storage.getItem("test"), "value", "value can be set");
-}
-
-function cleanup()
-{
-  setDOMStorageEnabled(true);
   window.localStorage.clear();
   SimpleTest.finish();
 }
 
-function doTest()
-{
-  try
-  {
-    startTest();
-  }
-  catch(exc)
-  {
-    ok(false, exc+" was threw during the test")
-  }
-  finally
-  {
-    cleanup();
-  }
+function doTest() {
+  SpecialPowers.pushPrefEnv({"set": [["dom.storage.enabled", true]]}, test1);
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
--- a/dom/tests/mochitest/localstorage/test_localStorageQuota.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuota.html
@@ -2,46 +2,27 @@
 <head>
 <title>localStorage and DOM quota test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <script type="text/javascript" src="interOriginTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
+//Note: this test is currently giving failures when running standalone, see bug 914865
 
 var currentTest = 1;
-var prefs = SpecialPowers.Cc["@mozilla.org/preferences-service;1"]
-            .getService(SpecialPowers.Ci.nsIPrefBranch);
-var quota;
-var origBlockDisplay;
-var origBlockActive;
 
 function doNextTest()
 {
   slave = frame;
 
   switch (currentTest)
   {
-    // Initialy setup the quota to testing value of 1024B and
-    // set a 500 bytes key with name length 1 (allocate 501 bytes)
     case 1:
-      try {
-        quota = prefs.getIntPref("dom.storage.default_quota");
-      } catch (ex) {
-        quota = 5*1024;
-      }
-      prefs.setIntPref("dom.storage.default_quota", 1);
-
-      origBlockDisplay = prefs.getBoolPref("security.mixed_content.block_display_content");
-      origBlockActive = prefs.getBoolPref("security.mixed_content.block_active_content");
-
-      prefs.setBoolPref("security.mixed_content.block_display_content", false);
-      prefs.setBoolPref("security.mixed_content.block_active_content", false);
-
       slaveOrigin = "http://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
       break;
 
     // In subdomain now set another key with length 500 bytes, i.e.
     // allocate 501 bytes
     case 2:
       slaveOrigin = "http://test1.example.com";
@@ -98,31 +79,33 @@ function doNextTest()
 
     case 10:
       // Do a clean up...
       slaveOrigin = "https://test2.example.com";
       slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
       break;
 
     default: // end
-      prefs.setIntPref("dom.storage.default_quota", quota);
-      prefs.setBoolPref("security.mixed_content.block_display_content", origBlockDisplay);
-      prefs.setBoolPref("security.mixed_content.block_active_content", origBlockActive);
       SimpleTest.finish();
   }
 
   ++currentTest;
 }
 
 function doStep()
 {
 }
 
 SimpleTest.waitForExplicitFinish();
 
+function startTest() {
+  // Initialy setup the quota to testing value of 1024B and
+  // set a 500 bytes key with name length 1 (allocate 501 bytes)
+  SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, doNextTest);
+}
 </script>
 
 </head>
 
-<body onload="doNextTest();">
+<body onload="startTest();">
   <iframe src="" name="frame"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html
@@ -4,52 +4,24 @@
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <script type="text/javascript" src="interOriginTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
 var currentTest = 1;
-var prefs = SpecialPowers.Cc["@mozilla.org/preferences-service;1"]
-            .getService(SpecialPowers.Ci.nsIPrefBranch);
-var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-  .getService(SpecialPowers.Ci.nsIIOService);
-var uri = io.newURI(window.location, "", null);
-var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-  .getService(SpecialPowers.Ci.nsICookiePermission);
-
-cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
-
-var quota;
-var origBlockDisplay;
-var origBlockActive;
 
 function doNextTest()
 {
   slave = frame;
 
   switch (currentTest)
   {
-    // Initialy setup the quota to testing value of 1024B and
-    // set a 500 bytes key with name length 1 (allocate 501 bytes)
     case 1:
-      try {
-        quota = prefs.getIntPref("dom.storage.default_quota");
-      } catch (ex) {
-        quota = 5*1024;
-      }
-      prefs.setIntPref("dom.storage.default_quota", 1);
-
-      origBlockDisplay = prefs.getBoolPref("security.mixed_content.block_display_content");
-      origBlockActive = prefs.getBoolPref("security.mixed_content.block_active_content");
-
-      prefs.setBoolPref("security.mixed_content.block_display_content", false);
-      prefs.setBoolPref("security.mixed_content.block_active_content", false);
-
       slaveOrigin = "http://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
       break;
 
     // In subdomain now set another key with length 500 bytes, i.e.
     // allocate 501 bytes
     case 2:
       slaveOrigin = "http://test1.example.com";
@@ -106,32 +78,35 @@ function doNextTest()
 
     case 10:
       // Do a clean up...
       slaveOrigin = "https://test2.example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
       break;
 
     default:
-      prefs.setIntPref("dom.storage.default_quota", quota);
-      prefs.setBoolPref("security.mixed_content.block_display_content", origBlockDisplay);
-      prefs.setBoolPref("security.mixed_content.block_active_content", origBlockActive);
-      cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
       SimpleTest.finish();
   }
 
   ++currentTest;
 }
 
 function doStep()
 {
 }
 
 SimpleTest.waitForExplicitFinish();
 
+function startTest() {
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], function() {
+    // Initialy setup the quota to testing value of 1024B and
+    // set a 500 bytes key with name length 1 (allocate 501 bytes)
+    SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, doNextTest);
+  });
+}
 </script>
 
 </head>
 
-<body onload="doNextTest();">
+<body onload="startTest();">
   <iframe src="" name="frame"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html
@@ -3,61 +3,32 @@
 <title>localStorage and DOM quota test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <script type="text/javascript" src="interOriginTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-const Cc = SpecialPowers.Cc;
-
 var currentTest = 1;
-var prefs = Cc["@mozilla.org/preferences-service;1"]
-            .getService(SpecialPowers.Ci.nsIPrefBranch);
-var io = Cc["@mozilla.org/network/io-service;1"]
-  .getService(SpecialPowers.Ci.nsIIOService);
-var uri = io.newURI(window.location, "", null);
-var cp = Cc["@mozilla.org/cookie/permission;1"]
-  .getService(SpecialPowers.Ci.nsICookiePermission);
-
-var quota;
-var origBlockDisplay;
-var origBlockActive;
 
 function doNextTest()
 {
   slave = frame;
 
   switch (currentTest)
   {
-    // Initialy setup the quota to testing value of 1024B and
-    // set a 500 bytes key with name length 1 (allocate 501 bytes)
     case 1:
-      try {
-        quota = prefs.getIntPref("dom.storage.default_quota");
-      } catch (ex) {
-        quota = 5*1024;
-      }
-      prefs.setIntPref("dom.storage.default_quota", 1);
-
-      origBlockDisplay = prefs.getBoolPref("security.mixed_content.block_display_content");
-      origBlockActive = prefs.getBoolPref("security.mixed_content.block_active_content");
-
-      prefs.setBoolPref("security.mixed_content.block_display_content", false);
-      prefs.setBoolPref("security.mixed_content.block_active_content", false)
-
       slaveOrigin = "http://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
       break;
 
     // In subdomain now set another key with length 500 bytes, i.e.
     // allocate 501 bytes
     case 2:
-      cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
       slaveOrigin = "http://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
       break;
 
     // Try to set the same key value again to check we don't fail
     // even 1002 bytes has already been exhausted from the quota
     // We just change the value of an existing key.
     case 3:
@@ -90,36 +61,38 @@ function doNextTest()
       slaveOrigin = "https://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
       break;
 
     case 8:
       // Do a clean up...
       slaveOrigin = "http://example.com";
       slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
-      cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
       break;
 
     default:
-      prefs.setIntPref("dom.storage.default_quota", quota);
-      prefs.setBoolPref("security.mixed_content.block_display_content", origBlockDisplay);
-      prefs.setBoolPref("security.mixed_content.block_active_content", origBlockActive);
-      cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
       SimpleTest.finish();
   }
 
   ++currentTest;
 }
 
 function doStep()
 {
 }
 
 SimpleTest.waitForExplicitFinish();
 
+function startTest() {
+  // Initialy setup the quota to testing value of 1024B and
+  // set a 500 bytes key with name length 1 (allocate 501 bytes)
+  SpecialPowers.pushPrefEnv({"set": [["dom.storage.default_quota", 1], ["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, function() {
+      SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], doNextTest);
+  });
+}
 </script>
 
 </head>
 
-<body onload="doNextTest();">
+<body onload="startTest();">
   <iframe src="" name="frame"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/localstorage/test_localStorageReplace.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageReplace.html
@@ -12,19 +12,16 @@
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
 var shell;
 var shellType;
 var failureRegExp = new RegExp("^FAILURE");
-var origBlockDisplay;
-var origBlockActive;
-
 
 window.addEventListener("message", onMessageReceived, false);
 
 function onMessageReceived(event)
 {
   switch (event.data)
   {
     case "init_done":
@@ -45,46 +42,37 @@ function onMessageReceived(event)
           // We finished testing in a frame
           // proceed with test in a separate window
           shellType = "window";
           shell = window.open("http://example.org:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?init&" + shellType);
           break;
 
         case "window":
           shell.close();
-          window.setTimeout(function() {endTest();}, 0);
+          window.setTimeout(function() {SimpleTest.finish();}, 0);
           break;
       }
       break;
 
     default:
       SimpleTest.ok(!event.data.match(failureRegExp), event.data);
       break;
   }
 }
 
-function startTest()
-{
-  origBlockDisplay = SpecialPowers.getBoolPref("security.mixed_content.block_display_content");
-  origBlockActive = SpecialPowers.getBoolPref("security.mixed_content.block_active_content");
-  SpecialPowers.setBoolPref("security.mixed_content.block_display_content", false);
-  SpecialPowers.setBoolPref("security.mixed_content.block_active_content", false);
+function startTest() {
+  SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_display_content", false], ["security.mixed_content.block_active_content", false]]}, test1);
+}
 
+function test1() {
   shellType = "frame";
   shell = frame;
   shell.location = "http://example.org:80/tests/dom/tests/mochitest/localstorage/frameReplace.html?init&" + shellType;
 }
 
-function endTest()
-{
-  SpecialPowers.setBoolPref("security.mixed_content.block_display_content", origBlockDisplay);
-  SpecialPowers.setBoolPref("security.mixed_content.block_active_content", origBlockActive);
-  SimpleTest.finish();
-}
-
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
 <body onload="startTest();">
   <iframe src="" name="frame"></iframe>
--- a/dom/tests/mochitest/sessionstorage/test_cookieSession.html
+++ b/dom/tests/mochitest/sessionstorage/test_cookieSession.html
@@ -9,90 +9,116 @@
 
 /*
   Set cookie access to be just per session and store to the sessionStorage.
   Content stored must prevail only for session of the browser, so it must
   be accessible in another window we try to access that key in the same
   storage.
  */
 
-function startTest()
-{
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
+function pushCookie(aValue, aNext) {
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': aValue, 'context': document}], pushPermissionAndTest);
+}
 
-  // ==================== start of the test ============================
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+function pushPermissionAndTest() {
+  var test = tests.shift();
+  if (test) {
+    document.getElementById('testframe').onload = test;
+    /* After every permission change, an iframe has to be reloaded,
+       otherwise this test causes failures in b2g (oop) mochitest, because
+       the permission changes don't seem to be always picked up
+       by the code that excercises it */
+    document.getElementById('testframe').contentWindow.location.reload();
+  } else {
+    ok(false, 'should not be reached');
+    SimpleTest.finish();
+  }
+}
 
-  sessionStorage.setItem("persistent1", "persistent value 1");
-  sessionStorage.setItem("persistent2", "persistent value 2");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+function startTest() {
+  pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+}
 
-  sessionStorage.setItem("session only", "session value");
-  is(sessionStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
-  is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
-  is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+var tests = [
+  function test1() {
+    sessionStorage.setItem("persistent1", "persistent value 1");
+    sessionStorage.setItem("persistent2", "persistent value 2");
 
-  sessionStorage.setItem("persistent1", "changed persistent value 1");
-  sessionStorage.removeItem("persistent2");
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+  },
 
-  is(sessionStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
-  is(sessionStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
-  is(sessionStorage.getItem("persistent2"), null, "Persistent value removed");
+  function test2() {
+    sessionStorage.setItem("session only", "session value");
+    is(sessionStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+    is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+    is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
 
-  // This clear has to delete only changes made in session only mode
-  sessionStorage.clear();
+    sessionStorage.setItem("persistent1", "changed persistent value 1");
+    sessionStorage.removeItem("persistent2");
 
-  is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(sessionStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
-  is(sessionStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+    is(sessionStorage.getItem("session only"), "session value", "Value present when cookies in session-only mode");
+    is(sessionStorage.getItem("persistent1"), "changed persistent value 1", "Persistent value present");
+    is(sessionStorage.getItem("persistent2"), null, "Persistent value removed");
+
+    // This clear has to delete only changes made in session only mode
+    sessionStorage.clear();
 
-  sessionStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
-
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+    is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+    is(sessionStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+    is(sessionStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
 
-  is(sessionStorage.getItem("session only"), null, "No value when cookies are in default mode");
-  is(sessionStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
-  is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
-  is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
+    sessionStorage.setItem("session only 2", "must be deleted on drop of session-only cookies permissions");
+
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+  },
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+  function test3() {
+    is(sessionStorage.getItem("session only"), null, "No value when cookies are in default mode");
+    is(sessionStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+    is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present");
+    is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present");
 
-  is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(sessionStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
-  is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
-  is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+  },
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+  function test4() {
+    is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+    is(sessionStorage.getItem("session only 2"), null, "Value not present when cookies in session-only mode after delete");
+    is(sessionStorage.getItem("persistent1"), "persistent value 1", "Persistent value present again");
+    is(sessionStorage.getItem("persistent2"), "persistent value 2", "Persistent value present again");
 
-  sessionStorage.clear();
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+  },
+
+  function test5() {
+    sessionStorage.clear();
 
-  is(sessionStorage.getItem("session only"), null, "No value when cookies are in default mode");
-  is(sessionStorage.getItem("persistent1"), null, "Persistent value not present after delete");
-  is(sessionStorage.getItem("persistent2"), null, "Persistent value not present after delete");
+    is(sessionStorage.getItem("session only"), null, "No value when cookies are in default mode");
+    is(sessionStorage.getItem("persistent1"), null, "Persistent value not present after delete");
+    is(sessionStorage.getItem("persistent2"), null, "Persistent value not present after delete");
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+  },
 
-  is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
-  is(sessionStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
-  is(sessionStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
-  is(sessionStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
+  function test6() {
+    is(sessionStorage.getItem("session only"), null, "Value not present when cookies in session-only mode after delete");
+    is(sessionStorage.getItem("session only 2"), null, "No value when cookies are in default mode");
+    is(sessionStorage.getItem("persistent1"), null, "Persistent value not present in session only after delete");
+    is(sessionStorage.getItem("persistent2"), null, "Persistent value not present in session only after delete");
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+    pushCookie(SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
+  },
 
-  SimpleTest.finish();
-}
+  function test7() {
+    SimpleTest.finish();
+  }
+];
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
 <body onload="startTest();">
-
+<iframe id="testframe" src="data:text/html;charset=utf-8,"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/sessionstorage/test_sessionStorageBaseSessionOnly.html
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBaseSessionOnly.html
@@ -2,25 +2,43 @@
 <head>
 <title>sessionStorage basic test, while in sesison only mode</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-function startTest()
-{
-  var io = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-    .getService(SpecialPowers.Ci.nsIIOService);
-  var uri = io.newURI(window.location, "", null);
-  var cp = SpecialPowers.Cc["@mozilla.org/cookie/permission;1"]
-    .getService(SpecialPowers.Ci.nsICookiePermission);
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION);
+var testframe;
+function iframeOnload(aValue) {
+  switch (aValue) {
+    case 1:
+      testframe.onload = test1;
+      break;
+    case 2:
+      testframe.onload = test2;
+      break;
+    default:
+      of(false, 'should not be reached');
+      SimpleTest.finish();
+      return;
+  }
+  /* After every permission change, an iframe has to be reloaded, 
+     otherwise this test causes failures in b2g (oop) mochitest, because
+     the permission changes don't seem to be always picked up
+     by the code that excercises it */
+  testframe.contentWindow.location.reload();
+}
 
+function startTest() {
+  testframe = document.getElementById('testframe');
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION, 'context': document}], function() { iframeOnload(1); });
+}
+
+function test1() {
 
   // Initially check the sessionStorage is empty
   is(sessionStorage.length, 0, "The storage is empty [1]");
   is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(sessionStorage["nonexisting"], undefined, "Nonexisting item is undefined (array access)");
@@ -190,25 +208,26 @@ function startTest()
   is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(sessionStorage.getItem("key1"), null, "key1 removed");
   is(sessionStorage.getItem("key2"), null, "key2 removed");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
   sessionStorage.removeItem("key1"); // Just check there is no exception
   sessionStorage.removeItem("key2"); // Just check there is no exception
 
+  SpecialPowers.pushPermissions([{'type': 'cookie', 'allow': SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT, 'context': document}], function() { iframeOnload(2); });
+}
 
-  cp.setAccess(uri, SpecialPowers.Ci.nsICookiePermission.ACCESS_DEFAULT);
-
+function test2() {
   sessionStorage.clear();
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 
 </head>
 
 <body onload="startTest();">
-
+<iframe id="testframe" src="data:text/html;charset=utf-8,"></iframe>
 </body>
 </html>
--- a/dom/webidl/MozNfc.webidl
+++ b/dom/webidl/MozNfc.webidl
@@ -5,12 +5,27 @@
  /* Copyright © 2013 Deutsche Telekom, Inc. */
 
 [JSImplementation="@mozilla.org/navigatorNfc;1",
  NavigatorProperty="mozNfc"]
 interface MozNfc : EventTarget {
    MozNFCTag getNFCTag(DOMString sessionId);
    MozNFCPeer getNFCPeer(DOMString sessionId);
 
-   /*attribute EventHandler onpeerfound;
+   /**
+    * API to check if the given application's manifest
+    * URL is registered with the Chrome Process or not.
+    *
+    * Returns success if given manifestUrl is registered for 'onpeerready',
+    * otherwise error
+    *
+    * Users of this API should have valid permissions 'nfc-manager'
+    * and 'nfc-write'
+    */
+   DOMRequest checkP2PRegistration(DOMString manifestUrl);
+
+   attribute EventHandler onpeerready;
    attribute EventHandler onpeerlost;
-   attribute EventHandler onforegrounddispatch;*/
+   [ChromeOnly]
+   void eventListenerWasAdded(DOMString aType);
+   [ChromeOnly]
+   void eventListenerWasRemoved(DOMString aType);
 };
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1036,17 +1036,17 @@ public:
                                                       GrGLInterface* aGrGLInterface,
                                                       const IntSize &aSize,
                                                       SurfaceFormat aFormat);
 
   static void
     SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes);
 #endif
 
-  static void PurgeTextureCaches();
+  static void PurgeAllCaches();
 
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
   static TemporaryRef<GlyphRenderingOptions>
     CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting);
 #endif
   static TemporaryRef<DrawTarget>
     CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB);
 
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -127,33 +127,30 @@ DrawTargetSkia::SetGlobalCacheLimits(int
 {
   sTextureCacheCount = aCount;
   sTextureCacheSizeInBytes = aSizeInBytes;
 
   DrawTargetSkia::RebalanceCacheLimits();
 }
 
 void
-DrawTargetSkia::PurgeCache()
+DrawTargetSkia::PurgeCaches()
 {
   if (mGrContext) {
-    mGrContext->purgeCache();
+    mGrContext->freeGpuResources();
   }
 }
 
 /* static */ void
-DrawTargetSkia::PurgeTextureCaches()
+DrawTargetSkia::PurgeAllCaches()
 {
   std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
   uint32_t targetCount = targets.size();
-  if (targetCount == 0)
-    return;
-
   for (uint32_t i = 0; i < targetCount; i++) {
-    targets[i]->PurgeCache();
+    targets[i]->PurgeCaches();
   }
 }
 
 #endif
 
 static SkBitmap
 GetBitmapForSurface(SourceSurface *aSurface)
 {
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -106,21 +106,21 @@ public:
 #ifdef USE_SKIA_GPU
   virtual GenericRefCountedBase* GetGLContext() const MOZ_OVERRIDE { return mGLContext; }
   void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
                                          GrGLInterface* aGrGLInterface,
                                          const IntSize &aSize,
                                          SurfaceFormat aFormat) MOZ_OVERRIDE;
 
   void SetCacheLimits(int aCount, int aSizeInBytes);
-  void PurgeCache();
+  void PurgeCaches();
 
   static void SetGlobalCacheLimits(int aCount, int aSizeInBytes);
   static void RebalanceCacheLimits();
-  static void PurgeTextureCaches();
+  static void PurgeAllCaches();
 #endif
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -544,20 +544,20 @@ Factory::CreateDrawTargetSkiaWithGLConte
 void
 Factory::SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes)
 {
     DrawTargetSkia::SetGlobalCacheLimits(aCount, aSizeInBytes);
 }
 #endif // USE_SKIA_GPU
 
 void
-Factory::PurgeTextureCaches()
+Factory::PurgeAllCaches()
 {
 #ifdef USE_SKIA_GPU
-  DrawTargetSkia::PurgeTextureCaches();
+  DrawTargetSkia::PurgeAllCaches();
 #endif
 }
 
 #ifdef USE_SKIA_FREETYPE
 TemporaryRef<GlyphRenderingOptions>
 Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting)
 {
   RefPtr<GlyphRenderingOptionsCairo> options =
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -99,16 +99,23 @@ TextureHost::Create(uint64_t aID,
                     ISurfaceAllocator* aDeallocator,
                     TextureFlags aFlags)
 {
   switch (Compositor::GetBackend()) {
     case LAYERS_OPENGL:
       return CreateTextureHostOGL(aID, aDesc, aDeallocator, aFlags);
     case LAYERS_BASIC:
       return CreateTextureHostBasic(aID, aDesc, aDeallocator, aFlags);
+#ifdef MOZ_WIDGET_GONK
+    case LAYERS_NONE:
+      // Power on video reqests to allocate TextureHost,
+      // when Compositor is still not present. This is a very hacky workaround.
+      // See Bug 944420.
+      return CreateTextureHostOGL(aID, aDesc, aDeallocator, aFlags);
+#endif
 #ifdef XP_WIN
     case LAYERS_D3D11:
     case LAYERS_D3D9:
       // XXX - not implemented yet
 #endif
     default:
       MOZ_CRASH("Couldn't create texture host");
       return nullptr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -228,17 +228,17 @@ public:
 NS_IMPL_ISUPPORTS1(MemoryPressureObserver, nsIObserver)
 
 NS_IMETHODIMP
 MemoryPressureObserver::Observe(nsISupports *aSubject,
                                 const char *aTopic,
                                 const PRUnichar *someData)
 {
     NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
-    Factory::PurgeTextureCaches();
+    Factory::PurgeAllCaches();
     return NS_OK;
 }
 
 // this needs to match the list of pref font.default.xx entries listed in all.js!
 // the order *must* match the order in eFontPrefLang
 static const char *gPrefLangNames[] = {
     "x-western",
     "x-central-euro",
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -369,37 +369,29 @@
     "dom/tests/mochitest/geolocation/test_mozsettings.html":"",
     "dom/tests/mochitest/geolocation/test_mozsettingsWatch.html":"",
     "dom/tests/mochitest/geolocation/test_optional_api_params.html":"",
     "dom/tests/mochitest/geolocation/test_shutdown.html":"",
     "dom/tests/mochitest/geolocation/test_timerRestartWatch.html":"",
     "dom/tests/mochitest/geolocation/test_windowClose.html":"",
     "dom/tests/mochitest/geolocation/test_worseAccuracyDoesNotBlockCallback.html":"",
 
-
     "dom/tests/mochitest/localstorage/test_appIsolation.html":"needs https to work",
 
-    "dom/tests/mochitest/localstorage/test_cookieBlock.html":"bug 913706",
-    "dom/tests/mochitest/localstorage/test_cookieSession-phase1.html":"",
-    "dom/tests/mochitest/localstorage/test_cookieSession-phase2.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageBase.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageCookieSettings.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageEnablePref.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageQuota.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html":"",
-    "dom/tests/mochitest/localstorage/test_localStorageReplace.html":"",
-    "dom/tests/mochitest/sessionstorage/test_cookieSession.html":"",
-    "dom/tests/mochitest/sessionstorage/test_sessionStorageBaseSessionOnly.html":"",
+    "dom/tests/mochitest/localstorage/test_cookieSession.html":"4 failures",
+    "dom/tests/mochitest/localstorage/test_localStorageBase.html":"no storage chrome event received",
+    "dom/tests/mochitest/localstorage/test_localStorageOriginsSchemaDiffs.html":"needs https support",
+    "dom/tests/mochitest/localstorage/test_localStorageQuota.html":"needs https support",
+    "dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly.html":"needs https support",
+    "dom/tests/mochitest/localstorage/test_localStorageQuotaSessionOnly2.html":"needs https support",
+    "dom/tests/mochitest/sessionstorage/test_cookieSession.html":"4 failures",
+    "dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html":"no storage chrome event received",
+    "dom/tests/mochitest/sessionstorage/test_sessionStorageHttpHttps.html":"needs https to work",
 
     "dom/tests/mochitest/pointerlock/test_pointerlock-api.html":"window.open focus issues (using fullscreen)",
-    "dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html":"",
-    "dom/tests/mochitest/sessionstorage/test_sessionStorageHttpHttps.html":"needs https to work",
     "dom/tests/mochitest/webapps/test_bug_779982.html":"",
     "dom/tests/mochitest/whatwg/test_postMessage_closed.html":"bug 894914 - wrong data - got FAIL, expected message",
 
     "dom/workers/test/test_suspend.html":"test timed out, might need more time",
     "dom/workers/test/test_xhr_parameters.html":"",
     "dom/workers/test/test_xhr_system.html":"",
     "dom/workers/test/test_closeOnGC.html": "times out",
     "dom/workers/test/test_errorPropagation.html":"times out",
--- a/testing/mochitest/tests/test_SpecialPowersPushPermissions.html
+++ b/testing/mochitest/tests/test_SpecialPowersPushPermissions.html
@@ -4,28 +4,32 @@
   <title>Test for SpecialPowers extension</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onload="starttest();">
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
-var pm = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
-                      .getService(SpecialPowers.Ci.nsIPermissionManager);
-const ALLOW_ACTION = pm.ALLOW_ACTION;
-const DENY_ACTION = pm.DENY_ACTION;
-const UNKNOWN_ACTION = pm.UNKNOWN_ACTION;
-const PROMPT_ACTION = pm.PROMPT_ACTION;
+const ALLOW_ACTION = SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION;
+const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+const UNKNOWN_ACTION = SpecialPowers.Ci.nsIPermissionManager.UNKNOWN_ACTION;
+const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
+const ACCESS_SESSION = SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION;
+const ACCESS_ALLOW_FIRST_PARTY_ONLY = SpecialPowers.Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY;
+const ACCESS_LIMIT_THIRD_PARTY = SpecialPowers.Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY;
 
 function starttest(){
   SpecialPowers.addPermission("pPROMPT", PROMPT_ACTION, document);
   SpecialPowers.addPermission("pALLOW", ALLOW_ACTION, document);
   SpecialPowers.addPermission("pDENY", DENY_ACTION, document);
   SpecialPowers.addPermission("pREMOVE", ALLOW_ACTION, document);
+  SpecialPowers.addPermission("pSESSION", ACCESS_SESSION, document);
+  SpecialPowers.addPermission("pFIRSTPARTY", ACCESS_ALLOW_FIRST_PARTY_ONLY, document);
+  SpecialPowers.addPermission("pTHIRDPARTY", ACCESS_LIMIT_THIRD_PARTY, document);
 
   setTimeout(test1, 0);
 }
 
 SimpleTest.waitForExplicitFinish();
 
 function test1() {
   if (!SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document)) {
@@ -35,32 +39,45 @@ function test1() {
     dump('/**** deny not set ****/\n');
     setTimeout(test1, 0);
   } else if (!SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document)) {
     dump('/**** prompt not set ****/\n');
     setTimeout(test1, 0);
   } else if (!SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document)) {
     dump('/**** remove not set ****/\n');
     setTimeout(test1, 0);
+  } else if (!SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document)) {
+    dump('/**** ACCESS_SESSION not set ****/\n');
+    setTimeout(test1, 0);
+  } else if (!SpecialPowers.testPermission('pFIRSTPARTY', ACCESS_ALLOW_FIRST_PARTY_ONLY, document)) {
+    dump('/**** ACCESS_ALLOW_FIRST_PARTY_ONLY not set ****/\n');
+    setTimeout(test1, 0);
+  } else if (!SpecialPowers.testPermission('pTHIRDPARTY', ACCESS_LIMIT_THIRD_PARTY, document)) {
+    dump('/**** ACCESS_LIMIT_THIRD_PARTY not set ****/\n');
+    setTimeout(test1, 0);
   } else {
     test2();
   }
 }
 
 function test2() {
   ok(SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN value should have UNKOWN permission');
-  SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': true, 'context': document}, {'type': 'pREMOVE', 'remove': true, 'context': document}], test3);
+  SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': true, 'context': document}, {'type': 'pSESSION', 'allow': true, 'context': document}, {'type': 'pFIRSTPARTY', 'allow': true, 'context': document}, {'type': 'pTHIRDPARTY', 'allow': true, 'context': document}, {'type': 'pREMOVE', 'remove': true, 'context': document}], test3);
 }
 
 function test3() {
   ok(SpecialPowers.testPermission('pUNKNOWN', ALLOW_ACTION, document), 'pUNKNOWN value should have ALLOW permission');
   ok(SpecialPowers.testPermission('pPROMPT', ALLOW_ACTION, document), 'pPROMPT value should have ALLOW permission');
   ok(SpecialPowers.testPermission('pALLOW', DENY_ACTION, document), 'pALLOW should have DENY permission');
   ok(SpecialPowers.testPermission('pDENY', ALLOW_ACTION, document), 'pDENY should have ALLOW permission');
   ok(SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document), 'pREMOVE should have REMOVE permission');
+  ok(SpecialPowers.testPermission('pSESSION', ALLOW_ACTION, document), 'pSESSION should have ALLOW permission');
+  ok(SpecialPowers.testPermission('pFIRSTPARTY', ALLOW_ACTION, document), 'pFIRSTPARTY should have ALLOW permission');
+  ok(SpecialPowers.testPermission('pTHIRDPARTY', ALLOW_ACTION, document), 'pTHIRDPARTY should have ALLOW permission');
+
   // only pPROMPT (last one) is different, the other stuff is just to see if it doesn't cause test failures
   SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': true, 'context': document}, {'type': 'pALLOW', 'allow': false, 'context': document}, {'type': 'pDENY', 'allow': true, 'context': document}, {'type': 'pPROMPT', 'allow': false, 'context': document}, {'type': 'pREMOVE', 'remove': true, 'context': document}], test3b);
 }
 
 function test3b() {
   ok(SpecialPowers.testPermission('pPROMPT', DENY_ACTION, document), 'pPROMPT value should have DENY permission');
   SpecialPowers.pushPermissions([{'type': 'pUNKNOWN', 'allow': DENY_ACTION, 'context': document}, {'type': 'pALLOW', 'allow': PROMPT_ACTION, 'context': document}, {'type': 'pDENY', 'allow': PROMPT_ACTION, 'context': document}, {'type': 'pPROMPT', 'allow': ALLOW_ACTION, 'context': document}], test4);
 }
@@ -76,21 +93,27 @@ function test4() {
 
 
 function test5() {
   ok(SpecialPowers.testPermission('pUNKNOWN', UNKNOWN_ACTION, document), 'pUNKNOWN should have UNKNOWN permission');
   ok(SpecialPowers.testPermission('pALLOW', ALLOW_ACTION, document), 'pALLOW should have ALLOW permission');
   ok(SpecialPowers.testPermission('pDENY', DENY_ACTION, document), 'pDENY should have DENY permission');
   ok(SpecialPowers.testPermission('pPROMPT', PROMPT_ACTION, document), 'pPROMPT should have PROMPT permission');
   ok(SpecialPowers.testPermission('pREMOVE', ALLOW_ACTION, document), 'pREMOVE should have ALLOW permission');
+  ok(SpecialPowers.testPermission('pSESSION', ACCESS_SESSION, document), 'pSESSION should have ACCESS_SESSION permission');
+  ok(SpecialPowers.testPermission('pFIRSTPARTY', ACCESS_ALLOW_FIRST_PARTY_ONLY, document), 'pFIRSTPARTY should have ACCESS_ALLOW_FIRST_PARTY_ONLY permission');
+  ok(SpecialPowers.testPermission('pTHIRDPARTY', ACCESS_LIMIT_THIRD_PARTY, document), 'pTHIRDPARTY should have ACCESS_LIMIT_THIRD_PARTY permission');
 
   SpecialPowers.removePermission("pPROMPT", document);
   SpecialPowers.removePermission("pALLOW", document);
   SpecialPowers.removePermission("pDENY", document);
   SpecialPowers.removePermission("pREMOVE", document);
+  SpecialPowers.removePermission("pSESSION", document);
+  SpecialPowers.removePermission("pFIRSTPARTY", document);
+  SpecialPowers.removePermission("pTHIRDPARTY", document);
 
   setTimeout(test6, 0);
 }
 
 function test6() {
   if (!SpecialPowers.testPermission('pALLOW', UNKNOWN_ACTION, document)) {
     dump('/**** allow still set ****/\n');
     setTimeout(test6, 0);
@@ -98,16 +121,25 @@ function test6() {
     dump('/**** deny still set ****/\n');
     setTimeout(test6, 0);
   } else if (!SpecialPowers.testPermission('pPROMPT', UNKNOWN_ACTION, document)) {
     dump('/**** prompt still set ****/\n');
     setTimeout(test6, 0);
   } else if (!SpecialPowers.testPermission('pREMOVE', UNKNOWN_ACTION, document)) {
     dump('/**** remove still set ****/\n');
     setTimeout(test6, 0);
+  } else if (!SpecialPowers.testPermission('pSESSION', UNKNOWN_ACTION, document)) {
+    dump('/**** pSESSION still set ****/\n');
+    setTimeout(test6, 0);
+  } else if (!SpecialPowers.testPermission('pFIRSTPARTY', UNKNOWN_ACTION, document)) {
+    dump('/**** pFIRSTPARTY still set ****/\n');
+    setTimeout(test6, 0);
+  } else if (!SpecialPowers.testPermission('pTHIRDPARTY', UNKNOWN_ACTION, document)) {
+    dump('/**** pTHIRDPARTY still set ****/\n');
+    setTimeout(test6, 0);
   } else {
     SimpleTest.finish();
   }
 }
 </script>
 </pre>
 </body>
 </html>
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -621,16 +621,22 @@ SpecialPowersAPI.prototype = {
         var permission = inPermissions[p];
         var originalValue = Ci.nsIPermissionManager.UNKNOWN_ACTION;
         if (this.testPermission(permission.type, Ci.nsIPermissionManager.ALLOW_ACTION, permission.context)) {
           originalValue = Ci.nsIPermissionManager.ALLOW_ACTION;
         } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.DENY_ACTION, permission.context)) {
           originalValue = Ci.nsIPermissionManager.DENY_ACTION;
         } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.PROMPT_ACTION, permission.context)) {
           originalValue = Ci.nsIPermissionManager.PROMPT_ACTION;
+        } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_SESSION, permission.context)) {
+          originalValue = Ci.nsICookiePermission.ACCESS_SESSION;
+        } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY, permission.context)) {
+          originalValue = Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY;
+        } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY, permission.context)) {
+          originalValue = Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY;
         }
 
         let [url, appId, isInBrowserElement] = this._getInfoFromPermissionArg(permission.context);
 
         let perm;
         if (typeof permission.allow !== 'boolean') {
           perm = permission.allow;
         } else {