Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 03 Dec 2013 17:04:22 -0500
changeset 158608 79d250edda15cb5c9661ab7539733fd588f21a83
parent 158576 85694fd9b17cf468f11350af85f82f79d16e2e39 (current diff)
parent 158607 82dd6c40effc57efda16deb26194dc76890bb081 (diff)
child 158609 2cc86a28ff05a6a6ea621bf792591439b53d5d9c
child 158718 70b6149628d238dad9234c800a3e91907535e100
push id25750
push userryanvm@gmail.com
push dateTue, 03 Dec 2013 22:04:21 +0000
treeherdermozilla-central@79d250edda15 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c.
dom/bluetooth/BluetoothOppManager.cpp
dom/bluetooth/BluetoothOppManager.h
dom/bluetooth/BluetoothSocket.cpp
dom/bluetooth/BluetoothUnixSocketConnector.cpp
dom/bluetooth/BluetoothUnixSocketConnector.h
--- 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/
 #
 
-More Windows webidl changes 
+Bug 915533 - Remove unused files under dom/bluetooth.
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -843,10 +843,13 @@ pref("b2g.neterror.url", "app://system.g
 
 // Enable Web Speech synthesis API
 pref("media.webspeech.synth.enabled", true);
 
 // Downloads API
 pref("dom.mozDownloads.enabled", true);
 pref("dom.downloads.max_retention_days", 7);
 
+// Inactivity time in milliseconds after which we shut down the OS.File worker.
+pref("osfile.reset_worker_delay", 5000);
+
 // The URL of the Firefox Accounts auth server backend
 pref("identity.fxaccounts.auth.uri", "https://api-accounts.dev.lcip.org/v1");
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1260,80 +1260,109 @@ window.addEventListener('ContentStart', 
       channel: aData
     });
     shell.visibleNormalAudioActive = (aData == 'normal');
 }, "visible-audio-channel-changed", false);
 })();
 
 (function recordingStatusTracker() {
   // Recording status is tracked per process with following data structure:
-  // {<processId>: {count: <N>,
-  //                requestURL: <requestURL>,
-  //                isApp: <isApp>,
-  //                audioCount: <N>,
-  //                videoCount: <N>}}
+  // {<processId>: {<requestURL>: {isApp: <isApp>,
+  //                               count: <N>,
+  //                               audioCount: <N>,
+  //                               videoCount: <N>}}
   let gRecordingActiveProcesses = {};
 
   let recordingHandler = function(aSubject, aTopic, aData) {
     let props = aSubject.QueryInterface(Ci.nsIPropertyBag2);
     let processId = (props.hasKey('childID')) ? props.get('childID')
                                               : 'main';
     if (processId && !gRecordingActiveProcesses.hasOwnProperty(processId)) {
-      gRecordingActiveProcesses[processId] = {count: 0,
-                                              requestURL: props.get('requestURL'),
-                                              isApp: props.get('isApp'),
-                                              audioCount: 0,
-                                              videoCount: 0 };
+      gRecordingActiveProcesses[processId] = {};
     }
 
-    let currentActive = gRecordingActiveProcesses[processId];
-    let wasActive = (currentActive['count'] > 0);
-    let wasAudioActive = (currentActive['audioCount'] > 0);
-    let wasVideoActive = (currentActive['videoCount'] > 0);
+    let commandHandler = function (requestURL, command) {
+      let currentProcess = gRecordingActiveProcesses[processId];
+      let currentActive = currentProcess[requestURL];
+      let wasActive = (currentActive['count'] > 0);
+      let wasAudioActive = (currentActive['audioCount'] > 0);
+      let wasVideoActive = (currentActive['videoCount'] > 0);
+
+      switch (command.type) {
+        case 'starting':
+          currentActive['count']++;
+          currentActive['audioCount'] += (command.isAudio) ? 1 : 0;
+          currentActive['videoCount'] += (command.isVideo) ? 1 : 0;
+          break;
+        case 'shutdown':
+          currentActive['count']--;
+          currentActive['audioCount'] -= (command.isAudio) ? 1 : 0;
+          currentActive['videoCount'] -= (command.isVideo) ? 1 : 0;
+          break;
+        case 'content-shutdown':
+          currentActive['count'] = 0;
+          currentActive['audioCount'] = 0;
+          currentActive['videoCount'] = 0;
+          break;
+      }
+
+      if (currentActive['count'] > 0) {
+        currentProcess[requestURL] = currentActive;
+      } else {
+        delete currentProcess[requestURL];
+      }
+
+      // We need to track changes if any active state is changed.
+      let isActive = (currentActive['count'] > 0);
+      let isAudioActive = (currentActive['audioCount'] > 0);
+      let isVideoActive = (currentActive['videoCount'] > 0);
+      if ((isActive != wasActive) ||
+          (isAudioActive != wasAudioActive) ||
+          (isVideoActive != wasVideoActive)) {
+        shell.sendChromeEvent({
+          type: 'recording-status',
+          active: isActive,
+          requestURL: requestURL,
+          isApp: currentActive['isApp'],
+          isAudio: isAudioActive,
+          isVideo: isVideoActive
+        });
+      }
+    };
 
     switch (aData) {
       case 'starting':
-        currentActive['count']++;
-        currentActive['audioCount'] += (props.get('isAudio')) ? 1 : 0;
-        currentActive['videoCount'] += (props.get('isVideo')) ? 1 : 0;
-        break;
       case 'shutdown':
-        currentActive['count']--;
-        currentActive['audioCount'] -= (props.get('isAudio')) ? 1 : 0;
-        currentActive['videoCount'] -= (props.get('isVideo')) ? 1 : 0;
+        // create page record if it is not existed yet.
+        let requestURL = props.get('requestURL');
+        if (requestURL &&
+            !gRecordingActiveProcesses[processId].hasOwnProperty(requestURL)) {
+          gRecordingActiveProcesses[processId][requestURL] = {isApp: props.get('isApp'),
+                                                              count: 0,
+                                                              audioCount: 0,
+                                                              videoCount: 0};
+        }
+        commandHandler(requestURL, { type: aData,
+                                     isAudio: props.get('isAudio'),
+                                     isVideo: props.get('isVideo')});
         break;
       case 'content-shutdown':
-        currentActive['count'] = 0;
-        currentActive['audioCount'] = 0;
-        currentActive['videoCount'] = 0;
+        // iterate through all the existing active processes
+        Object.keys(gRecordingActiveProcesses[processId]).foreach(function(requestURL) {
+          commandHandler(requestURL, { type: aData,
+                                       isAudio: true,
+                                       isVideo: true});
+        });
         break;
     }
 
-    if (currentActive['count'] > 0) {
-      gRecordingActiveProcesses[processId] = currentActive;
-    } else {
+    // clean up process record if no page record in it.
+    if (Object.keys(gRecordingActiveProcesses[processId]).length == 0) {
       delete gRecordingActiveProcesses[processId];
     }
-
-    // We need to track changes if any active state is changed.
-    let isActive = (currentActive['count'] > 0);
-    let isAudioActive = (currentActive['audioCount'] > 0);
-    let isVideoActive = (currentActive['videoCount'] > 0);
-    if ((isActive != wasActive) ||
-        (isAudioActive != wasAudioActive) ||
-        (isVideoActive != wasVideoActive)) {
-      shell.sendChromeEvent({
-        type: 'recording-status',
-        active: isActive,
-        requestURL: currentActive['requestURL'],
-        isApp: currentActive['isApp'],
-        isAudio: isAudioActive,
-        isVideo: isVideoActive
-      });
-    }
   };
   Services.obs.addObserver(recordingHandler, 'recording-device-events', false);
   Services.obs.addObserver(recordingHandler, 'recording-device-ipc-events', false);
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     // send additional recording events if content process is being killed
     let processId = aSubject.QueryInterface(Ci.nsIPropertyBag2).get('childID');
     if (gRecordingActiveProcesses.hasOwnProperty(processId)) {
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "001672effec8835928519312c1075a842af9166c", 
+    "revision": "428cccdc7a3b4c40f40dda80b6031d26ac9d2d68", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/releng-hamachi.tt
+++ b/b2g/config/hamachi/releng-hamachi.tt
@@ -1,12 +1,12 @@
 [
 {
-"size": 85358580,
-"digest": "e26e3501b4119724f94d5d3edcdfefde00faceddab3114c9c3b118fec11118d6f2293ea3c25426ec5ba7c7e0fe14d8349dbb8fa940e2f04ea83e26694d933696",
+"size": 55073212,
+"digest": "10560463c0804186fc59a84ecab4d5ccd1ffdf298336d3b91065c38888698f4cfab4bad743d6170e73f9bc0538f47a96baf5f1381e8b4ab484d8721301bea31e",
 "algorithm": "sha512",
 "filename": "backup-hamachi.tar.xz"
 },
 {
 "size": 1570553,
 "digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
 "algorithm": "sha512",
 "filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
--- a/b2g/config/helix/releng-helix.tt
+++ b/b2g/config/helix/releng-helix.tt
@@ -1,12 +1,12 @@
 [
 {
-"size": 60589756,
-"digest": "29f6a7f09edbcc777ab155de64b4c7ff8c79ea25021bacc95a44d2ee8b7b13caa72991294b05dac1d841128a90eced3f52bcc3399ead4452f6170742e0e52fc1",
+"size": 58958768,
+"digest": "a1c7727075b481259ee1835d0f016834f52b8a20dd18be6e0dbf265421671e2fc5203ff01891588ab712f5033103350574528dae866ea795460518afa78b0c4b",
 "algorithm": "sha512",
 "filename": "helix-ics.tar.xz"
 },
 {
 "size": 1570553,
 "digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
 "algorithm": "sha512",
 "filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
deleted file mode 100644
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ /dev/null
@@ -1,1587 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "base/basictypes.h"
-#include "BluetoothOppManager.h"
-
-#include "BluetoothService.h"
-#include "BluetoothSocket.h"
-#include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
-#include "ObexBase.h"
-
-#include "mozilla/dom/bluetooth/BluetoothTypes.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
-#include "nsAutoPtr.h"
-#include "nsCExternalHandlerService.h"
-#include "nsIObserver.h"
-#include "nsIObserverService.h"
-#include "nsIDOMFile.h"
-#include "nsIFile.h"
-#include "nsIInputStream.h"
-#include "nsIMIMEService.h"
-#include "nsIOutputStream.h"
-#include "nsIVolumeService.h"
-#include "nsNetUtil.h"
-#include "nsServiceManagerUtils.h"
-
-#define TARGET_SUBDIR "Download/Bluetooth/"
-
-USING_BLUETOOTH_NAMESPACE
-using namespace mozilla;
-using namespace mozilla::ipc;
-
-namespace {
-// Sending system message "bluetooth-opp-update-progress" every 50kb
-static const uint32_t kUpdateProgressBase = 50 * 1024;
-
-/*
- * The format of the header of an PUT request is
- * [opcode:1][packet length:2][headerId:1][header length:2]
- */
-static const uint32_t kPutRequestHeaderSize = 6;
-
-StaticRefPtr<BluetoothOppManager> sBluetoothOppManager;
-static bool sInShutdown = false;
-}
-
-class mozilla::dom::bluetooth::SendFileBatch {
-public:
-  SendFileBatch(const nsAString& aDeviceAddress, BlobParent* aActor)
-    : mDeviceAddress(aDeviceAddress)
-  {
-    mBlobs.AppendElement(aActor->GetBlob().get());
-  }
-
-  nsString mDeviceAddress;
-  nsCOMArray<nsIDOMBlob> mBlobs;
-};
-
-NS_IMETHODIMP
-BluetoothOppManager::Observe(nsISupports* aSubject,
-                             const char* aTopic,
-                             const PRUnichar* aData)
-{
-  MOZ_ASSERT(sBluetoothOppManager);
-
-  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
-    HandleShutdown();
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(false, "BluetoothOppManager got unexpected topic!");
-  return NS_ERROR_UNEXPECTED;
-}
-
-class SendSocketDataTask : public nsRunnable
-{
-public:
-  SendSocketDataTask(uint8_t* aStream, uint32_t aSize)
-    : mStream(aStream)
-    , mSize(aSize)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  NS_IMETHOD Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    sBluetoothOppManager->SendPutRequest(mStream, mSize);
-
-    return NS_OK;
-  }
-
-private:
-  nsAutoArrayPtr<uint8_t> mStream;
-  uint32_t mSize;
-};
-
-class ReadFileTask : public nsRunnable
-{
-public:
-  ReadFileTask(nsIInputStream* aInputStream,
-               uint32_t aRemoteMaxPacketSize) : mInputStream(aInputStream)
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    mAvailablePacketSize = aRemoteMaxPacketSize - kPutRequestHeaderSize;
-  }
-
-  NS_IMETHOD Run()
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-
-    uint32_t numRead;
-    nsAutoArrayPtr<char> buf(new char[mAvailablePacketSize]);
-
-    // function inputstream->Read() only works on non-main thread
-    nsresult rv = mInputStream->Read(buf, mAvailablePacketSize, &numRead);
-    if (NS_FAILED(rv)) {
-      // Needs error handling here
-      BT_WARNING("Failed to read from input stream");
-      return NS_ERROR_FAILURE;
-    }
-
-    if (numRead > 0) {
-      sBluetoothOppManager->CheckPutFinal(numRead);
-
-      nsRefPtr<SendSocketDataTask> task =
-        new SendSocketDataTask((uint8_t*)buf.forget(), numRead);
-      if (NS_FAILED(NS_DispatchToMainThread(task))) {
-        BT_WARNING("Failed to dispatch to main thread!");
-        return NS_ERROR_FAILURE;
-      }
-    }
-
-    return NS_OK;
-  };
-
-private:
-  nsCOMPtr<nsIInputStream> mInputStream;
-  uint32_t mAvailablePacketSize;
-};
-
-class CloseSocketTask : public Task
-{
-public:
-  CloseSocketTask(BluetoothSocket* aSocket) : mSocket(aSocket)
-  {
-    MOZ_ASSERT(aSocket);
-  }
-
-  void Run() MOZ_OVERRIDE
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (mSocket->GetConnectionStatus() ==
-        SocketConnectionStatus::SOCKET_CONNECTED) {
-      mSocket->Disconnect();
-    }
-  }
-
-private:
-  nsRefPtr<BluetoothSocket> mSocket;
-};
-
-BluetoothOppManager::BluetoothOppManager() : mConnected(false)
-                                           , mRemoteObexVersion(0)
-                                           , mRemoteConnectionFlags(0)
-                                           , mRemoteMaxPacketLength(0)
-                                           , mLastCommand(0)
-                                           , mPacketLength(0)
-                                           , mPacketReceivedLength(0)
-                                           , mBodySegmentLength(0)
-                                           , mAbortFlag(false)
-                                           , mNewFileFlag(false)
-                                           , mPutFinalFlag(false)
-                                           , mSendTransferCompleteFlag(false)
-                                           , mSuccessFlag(false)
-                                           , mIsServer(true)
-                                           , mWaitingForConfirmationFlag(false)
-                                           , mFileLength(0)
-                                           , mSentFileLength(0)
-                                           , mWaitingToSendPutFinal(false)
-                                           , mCurrentBlobIndex(-1)
-{
-  mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
-}
-
-BluetoothOppManager::~BluetoothOppManager()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE_VOID(obs);
-  if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
-    BT_WARNING("Failed to remove shutdown observer!");
-  }
-}
-
-bool
-BluetoothOppManager::Init()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE(obs, false);
-  if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
-    BT_WARNING("Failed to add shutdown observer!");
-    return false;
-  }
-
-  Listen();
-
-  return true;
-}
-
-//static
-BluetoothOppManager*
-BluetoothOppManager::Get()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // If sBluetoothOppManager already exists, exit early
-  if (sBluetoothOppManager) {
-    return sBluetoothOppManager;
-  }
-
-  // If we're in shutdown, don't create a new instance
-  NS_ENSURE_FALSE(sInShutdown, nullptr);
-
-  // Create a new instance, register, and return
-  BluetoothOppManager *manager = new BluetoothOppManager();
-  NS_ENSURE_TRUE(manager->Init(), nullptr);
-
-  sBluetoothOppManager = manager;
-  return sBluetoothOppManager;
-}
-
-void
-BluetoothOppManager::ConnectInternal(const nsAString& aDeviceAddress)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Stop listening because currently we only support one connection at a time.
-  if (mRfcommSocket) {
-    mRfcommSocket->Disconnect();
-    mRfcommSocket = nullptr;
-  }
-
-  if (mL2capSocket) {
-    mL2capSocket->Disconnect();
-    mL2capSocket = nullptr;
-  }
-
-  mIsServer = false;
-
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs || sInShutdown || mSocket) {
-    OnSocketConnectError(mSocket);
-    return;
-  }
-
-  mNeedsUpdatingSdpRecords = true;
-
-  nsString uuid;
-  BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid);
-
-  if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
-    OnSocketConnectError(mSocket);
-    return;
-  }
-
-  mSocket =
-    new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
-}
-
-void
-BluetoothOppManager::HandleShutdown()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  sInShutdown = true;
-
-  if (mSocket) {
-    mSocket->Disconnect();
-    mSocket = nullptr;
-  }
-  if (mRfcommSocket) {
-    mRfcommSocket->Disconnect();
-    mRfcommSocket = nullptr;
-  }
-  if (mL2capSocket) {
-    mL2capSocket->Disconnect();
-    mL2capSocket = nullptr;
-  }
-  sBluetoothOppManager = nullptr;
-}
-
-bool
-BluetoothOppManager::Listen()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mSocket) {
-    BT_WARNING("mSocket exists. Failed to listen.");
-    return false;
-  }
-
-  if (!mRfcommSocket) {
-    mRfcommSocket =
-      new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
-
-    if (!mRfcommSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
-      BT_WARNING("[OPP] Can't listen on RFCOMM socket!");
-      mRfcommSocket = nullptr;
-      return false;
-    }
-  }
-
-  if (!mL2capSocket) {
-    mL2capSocket =
-      new BluetoothSocket(this, BluetoothSocketType::EL2CAP, true, true);
-
-    if (!mL2capSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) {
-      BT_WARNING("[OPP] Can't listen on L2CAP socket!");
-      mRfcommSocket->Disconnect();
-      mRfcommSocket = nullptr;
-      mL2capSocket = nullptr;
-      return false;
-    }
-  }
-
-  mIsServer = true;
-
-  return true;
-}
-
-void
-BluetoothOppManager::StartSendingNextFile()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!IsConnected());
-  MOZ_ASSERT(!mBatches.IsEmpty());
-  MOZ_ASSERT(mBatches[0].mBlobs.Length() > mCurrentBlobIndex + 1);
-
-  mBlob = mBatches[0].mBlobs[++mCurrentBlobIndex];
-
-  // Before sending content, we have to send a header including
-  // information such as file name, file length and content type.
-  ExtractBlobHeaders();
-  StartFileTransfer();
-
-  if (mCurrentBlobIndex == 0) {
-    // We may have more than one file waiting for transferring, but only one
-    // CONNECT request would be sent. Therefore check if this is the very first
-    // file at the head of queue.
-    SendConnectRequest();
-  } else {
-    SendPutHeaderRequest(mFileName, mFileLength);
-    AfterFirstPut();
-  }
-}
-
-bool
-BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
-                              BlobParent* aActor)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  AppendBlobToSend(aDeviceAddress, aActor);
-  if (!mSocket) {
-    ProcessNextBatch();
-  }
-
-  return true;
-}
-
-void
-BluetoothOppManager::AppendBlobToSend(const nsAString& aDeviceAddress,
-                                      BlobParent* aActor)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  int indexTail = mBatches.Length() - 1;
-
-  /**
-   * Create a new batch if
-   * - mBatches is empty, or
-   * - aDeviceAddress differs from mDeviceAddress of the last batch
-   */
-  if (mBatches.IsEmpty() ||
-      aDeviceAddress != mBatches[indexTail].mDeviceAddress) {
-    SendFileBatch batch(aDeviceAddress, aActor);
-    mBatches.AppendElement(batch);
-  } else {
-    mBatches[indexTail].mBlobs.AppendElement(aActor->GetBlob().get());
-  }
-}
-
-void
-BluetoothOppManager::DiscardBlobsToSend()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!mBatches.IsEmpty());
-  MOZ_ASSERT(!mIsServer);
-
-  int length = (int) mBatches[0].mBlobs.Length();
-  while (length > mCurrentBlobIndex + 1) {
-    mBlob = mBatches[0].mBlobs[++mCurrentBlobIndex];
-
-    BT_LOGR("%s: idx %d", __FUNCTION__, mCurrentBlobIndex);
-    ExtractBlobHeaders();
-    StartFileTransfer();
-    FileTransferComplete();
-  }
-}
-
-bool
-BluetoothOppManager::ProcessNextBatch()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Remove the processed batch.
-  // A batch is processed if we've incremented mCurrentBlobIndex for it.
-  if (mCurrentBlobIndex >= 0) {
-    ClearQueue();
-    mBatches.RemoveElementAt(0);
-    BT_LOGR("%s: REMOVE. %d remaining", __FUNCTION__, mBatches.Length());
-  }
-
-  // Process the next batch
-  if (!mBatches.IsEmpty()) {
-    ConnectInternal(mBatches[0].mDeviceAddress);
-    return true;
-  }
-
-  // No more batch to process
-  return false;
-}
-
-void
-BluetoothOppManager::ClearQueue()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!mIsServer);
-  MOZ_ASSERT(!mBatches.IsEmpty());
-  MOZ_ASSERT(!mBatches[0].mBlobs.IsEmpty());
-
-  mCurrentBlobIndex = -1;
-  mBlob = nullptr;
-  mBatches[0].mBlobs.Clear();
-}
-
-bool
-BluetoothOppManager::StopSendingFile()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mIsServer) {
-    mAbortFlag = true;
-  } else if (mSocket) {
-    mSocket->Disconnect();
-  } else {
-    BT_WARNING("%s: No ongoing file transfer to stop", __FUNCTION__);
-  }
-
-  return true;
-}
-
-bool
-BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
-{
-  NS_ENSURE_TRUE(mConnected, false);
-  NS_ENSURE_TRUE(mWaitingForConfirmationFlag, false);
-
-  MOZ_ASSERT(mPacketReceivedLength == 0);
-
-  mWaitingForConfirmationFlag = false;
-
-  // For the first packet of first file
-  bool success = false;
-  if (aConfirm) {
-    StartFileTransfer();
-    if (CreateFile()) {
-      success = WriteToFile(mBodySegment.get(), mBodySegmentLength);
-    }
-  }
-
-  if (success && mPutFinalFlag) {
-    mSuccessFlag = true;
-    FileTransferComplete();
-    NotifyAboutFileChange();
-  }
-
-  ReplyToPut(mPutFinalFlag, success);
-  return true;
-}
-
-void
-BluetoothOppManager::AfterFirstPut()
-{
-  mUpdateProgressCounter = 1;
-  mPutFinalFlag = false;
-  mPacketReceivedLength = 0;
-  mSentFileLength = 0;
-  mWaitingToSendPutFinal = false;
-  mSuccessFlag = false;
-  mBodySegmentLength = 0;
-}
-
-void
-BluetoothOppManager::AfterOppConnected()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  mConnected = true;
-  mAbortFlag = false;
-  mWaitingForConfirmationFlag = true;
-  AfterFirstPut();
-  // Get a mount lock to prevent the sdcard from being shared with
-  // the PC while we're doing a OPP file transfer. After OPP transaction
-  // were done, the mount lock will be freed.
-  if (!AcquireSdcardMountLock()) {
-    // If we fail to get a mount lock, abort this transaction
-    // Directly sending disconnect-request is better than abort-request
-    BT_WARNING("BluetoothOPPManager couldn't get a mount lock!");
-
-    MOZ_ASSERT(mSocket);
-    mSocket->Disconnect();
-  }
-}
-
-void
-BluetoothOppManager::AfterOppDisconnected()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  mConnected = false;
-  mLastCommand = 0;
-  mPacketReceivedLength = 0;
-  mDsFile = nullptr;
-
-  // We can't reset mSuccessFlag here since this function may be called
-  // before we send system message of transfer complete
-  // mSuccessFlag = false;
-
-  if (mInputStream) {
-    mInputStream->Close();
-    mInputStream = nullptr;
-  }
-
-  if (mOutputStream) {
-    mOutputStream->Close();
-    mOutputStream = nullptr;
-  }
-
-  if (mReadFileThread) {
-    mReadFileThread->Shutdown();
-    mReadFileThread = nullptr;
-  }
-  // Release the Mount lock if file transfer completed
-  if (mMountLock) {
-    // The mount lock will be implicitly unlocked
-    mMountLock = nullptr;
-  }
-}
-
-void
-BluetoothOppManager::DeleteReceivedFile()
-{
-  if (mOutputStream) {
-    mOutputStream->Close();
-    mOutputStream = nullptr;
-  }
-
-  if (mDsFile && mDsFile->mFile) {
-    mDsFile->mFile->Remove(false);
-    mDsFile = nullptr;
-  }
-}
-
-bool
-BluetoothOppManager::CreateFile()
-{
-  MOZ_ASSERT(mPacketReceivedLength == mPacketLength);
-
-  nsString path;
-  path.AssignLiteral(TARGET_SUBDIR);
-  path.Append(mFileName);
-
-  mDsFile = DeviceStorageFile::CreateUnique(path, nsIFile::NORMAL_FILE_TYPE, 0644);
-  NS_ENSURE_TRUE(mDsFile, false);
-
-  nsCOMPtr<nsIFile> f;
-  mDsFile->mFile->Clone(getter_AddRefs(f));
-
-  /*
-   * The function CreateUnique() may create a file with a different file
-   * name from the original mFileName. Therefore we have to retrieve
-   * the file name again.
-   */
-  f->GetLeafName(mFileName);
-
-  NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
-  NS_ENSURE_TRUE(mOutputStream, false);
-
-  return true;
-}
-
-bool
-BluetoothOppManager::WriteToFile(const uint8_t* aData, int aDataLength)
-{
-  NS_ENSURE_TRUE(mOutputStream, false);
-
-  uint32_t wrote = 0;
-  mOutputStream->Write((const char*)aData, aDataLength, &wrote);
-  NS_ENSURE_TRUE(aDataLength == (int) wrote, false);
-
-  return true;
-}
-
-// Virtual function of class SocketConsumer
-void
-BluetoothOppManager::ExtractPacketHeaders(const ObexHeaderSet& aHeader)
-{
-  if (aHeader.Has(ObexHeaderId::Name)) {
-    aHeader.GetName(mFileName);
-  }
-
-  if (aHeader.Has(ObexHeaderId::Type)) {
-    aHeader.GetContentType(mContentType);
-  }
-
-  if (aHeader.Has(ObexHeaderId::Length)) {
-    aHeader.GetLength(&mFileLength);
-  }
-
-  if (aHeader.Has(ObexHeaderId::Body) ||
-      aHeader.Has(ObexHeaderId::EndOfBody)) {
-    uint8_t* bodyPtr;
-    aHeader.GetBody(&bodyPtr);
-    mBodySegment = bodyPtr;
-
-    aHeader.GetBodyLength(&mBodySegmentLength);
-  }
-}
-
-bool
-BluetoothOppManager::ExtractBlobHeaders()
-{
-  RetrieveSentFileName();
-
-  nsresult rv = mBlob->GetType(mContentType);
-  if (NS_FAILED(rv)) {
-    BT_WARNING("Can't get content type");
-    SendDisconnectRequest();
-    return false;
-  }
-
-  uint64_t fileLength;
-  rv = mBlob->GetSize(&fileLength);
-  if (NS_FAILED(rv)) {
-    BT_WARNING("Can't get file size");
-    SendDisconnectRequest();
-    return false;
-  }
-
-  // Currently we keep the size of files which were sent/received via
-  // Bluetooth not exceed UINT32_MAX because the Length header in OBEX
-  // is only 4-byte long. Although it is possible to transfer a file
-  // larger than UINT32_MAX, it needs to parse another OBEX Header
-  // and I would like to leave it as a feature.
-  if (fileLength > (uint64_t)UINT32_MAX) {
-    BT_WARNING("The file size is too large for now");
-    SendDisconnectRequest();
-    return false;
-  }
-
-  mFileLength = fileLength;
-  rv = NS_NewThread(getter_AddRefs(mReadFileThread));
-  if (NS_FAILED(rv)) {
-    BT_WARNING("Can't create thread");
-    SendDisconnectRequest();
-    return false;
-  }
-
-  return true;
-}
-
-void
-BluetoothOppManager::RetrieveSentFileName()
-{
-  mFileName.Truncate();
-
-  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
-  if (file) {
-    file->GetName(mFileName);
-  }
-
-  /**
-   * We try our best to get the file extention to avoid interoperability issues.
-   * However, once we found that we are unable to get suitable extension or
-   * information about the content type, sending a pre-defined file name without
-   * extension would be fine.
-   */
-  if (mFileName.IsEmpty()) {
-    mFileName.AssignLiteral("Unknown");
-  }
-
-  int32_t offset = mFileName.RFindChar('/');
-  if (offset != kNotFound) {
-    mFileName = Substring(mFileName, offset + 1);
-  }
-
-  offset = mFileName.RFindChar('.');
-  if (offset == kNotFound) {
-    nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
-
-    if (mimeSvc) {
-      nsString mimeType;
-      mBlob->GetType(mimeType);
-
-      nsCString extension;
-      nsresult rv =
-        mimeSvc->GetPrimaryExtension(NS_LossyConvertUTF16toASCII(mimeType),
-                                     EmptyCString(),
-                                     extension);
-      if (NS_SUCCEEDED(rv)) {
-        mFileName.AppendLiteral(".");
-        AppendUTF8toUTF16(extension, mFileName);
-      }
-    }
-  }
-}
-
-bool
-BluetoothOppManager::IsReservedChar(PRUnichar c)
-{
-  return (c < 0x0020 ||
-          c == PRUnichar('?') || c == PRUnichar('|') || c == PRUnichar('<') ||
-          c == PRUnichar('>') || c == PRUnichar('"') || c == PRUnichar(':') ||
-          c == PRUnichar('/') || c == PRUnichar('*') || c == PRUnichar('\\'));
-}
-
-void
-BluetoothOppManager::ValidateFileName()
-{
-  int length = mFileName.Length();
-
-  for (int i = 0; i < length; ++i) {
-    // Replace reserved char of fat file system with '_'
-    if (IsReservedChar(mFileName.CharAt(i))) {
-      mFileName.Replace(i, 1, PRUnichar('_'));
-    }
-  }
-}
-
-bool
-BluetoothOppManager::ComposePacket(uint8_t aOpCode, UnixSocketRawData* aMessage)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aMessage);
-
-  int frameHeaderLength = 0;
-
-  // See if this is the first part of each Put packet
-  if (mPacketReceivedLength == 0) {
-    // Section 3.3.3 "Put", IrOBEX 1.2
-    // [opcode:1][length:2][Headers:var]
-    frameHeaderLength = 3;
-
-    mPacketLength = ((((int)aMessage->mData[1]) << 8) | aMessage->mData[2]) -
-                      frameHeaderLength;
-    /**
-     * A PUT request from remote devices may be divided into multiple parts.
-     * In other words, one request may need to be received multiple times,
-     * so here we keep a variable mPacketLeftLength to indicate if current
-     * PUT request is done.
-     */
-    mReceivedDataBuffer = new uint8_t[mPacketLength];
-    mPutFinalFlag = (aOpCode == ObexRequestCode::PutFinal);
-  }
-
-  int dataLength = aMessage->mSize - frameHeaderLength;
-
-  // Check length before memcpy to prevent from memory pollution
-  if (dataLength < 0 ||
-      mPacketReceivedLength + dataLength > mPacketLength) {
-    BT_LOGR("%s: Received packet size is unreasonable", __FUNCTION__);
-
-    ReplyToPut(mPutFinalFlag, false);
-    DeleteReceivedFile();
-    FileTransferComplete();
-
-    return false;
-  }
-
-  memcpy(mReceivedDataBuffer.get() + mPacketReceivedLength,
-         &aMessage->mData[frameHeaderLength], dataLength);
-
-  mPacketReceivedLength += dataLength;
-
-  return (mPacketReceivedLength == mPacketLength);
-}
-
-void
-BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  uint8_t opCode;
-  int receivedLength = aMessage->mSize;
-
-  if (mPacketReceivedLength > 0) {
-    opCode = mPutFinalFlag ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
-  } else {
-    opCode = aMessage->mData[0];
-
-    // When there's a Put packet right after a PutFinal packet,
-    // which means it's the start point of a new file.
-    if (mPutFinalFlag &&
-        (opCode == ObexRequestCode::Put ||
-         opCode == ObexRequestCode::PutFinal)) {
-      mNewFileFlag = true;
-      AfterFirstPut();
-    }
-  }
-
-  ObexHeaderSet pktHeaders(opCode);
-  if (opCode == ObexRequestCode::Connect) {
-    // Section 3.3.1 "Connect", IrOBEX 1.2
-    // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
-    // [Headers:var]
-    ParseHeaders(&aMessage->mData[7],
-                 receivedLength - 7,
-                 &pktHeaders);
-    ReplyToConnect();
-    AfterOppConnected();
-  } else if (opCode == ObexRequestCode::Abort) {
-    // Section 3.3.5 "Abort", IrOBEX 1.2
-    // [opcode:1][length:2][Headers:var]
-    ParseHeaders(&aMessage->mData[3],
-                receivedLength - 3,
-                &pktHeaders);
-    ReplyToDisconnectOrAbort();
-    DeleteReceivedFile();
-  } else if (opCode == ObexRequestCode::Disconnect) {
-    // Section 3.3.2 "Disconnect", IrOBEX 1.2
-    // [opcode:1][length:2][Headers:var]
-    ParseHeaders(&aMessage->mData[3],
-                receivedLength - 3,
-                &pktHeaders);
-    ReplyToDisconnectOrAbort();
-    AfterOppDisconnected();
-    FileTransferComplete();
-  } else if (opCode == ObexRequestCode::Put ||
-             opCode == ObexRequestCode::PutFinal) {
-    if (!ComposePacket(opCode, aMessage)) {
-      return;
-    }
-
-    // A Put packet is received completely
-    ParseHeaders(mReceivedDataBuffer.get(), mPacketReceivedLength, &pktHeaders);
-    ExtractPacketHeaders(pktHeaders);
-    ValidateFileName();
-
-    mPacketReceivedLength = 0;
-
-    // When we cancel the transfer, delete the file and notify completion
-    if (mAbortFlag) {
-      ReplyToPut(mPutFinalFlag, false);
-      mSentFileLength += mBodySegmentLength;
-      DeleteReceivedFile();
-      FileTransferComplete();
-      return;
-    }
-
-    // Wait until get confirmation from user, then create file and write to it
-    if (mWaitingForConfirmationFlag) {
-      ReceivingFileConfirmation();
-      mSentFileLength += mBodySegmentLength;
-      return;
-    }
-
-    // Already get confirmation from user, create a new file if needed and
-    // write to output stream
-    if (mNewFileFlag) {
-      StartFileTransfer();
-      if (!CreateFile()) {
-        ReplyToPut(mPutFinalFlag, false);
-        return;
-      }
-      mNewFileFlag = false;
-    }
-
-    if (!WriteToFile(mBodySegment.get(), mBodySegmentLength)) {
-      ReplyToPut(mPutFinalFlag, false);
-      return;
-    }
-
-    ReplyToPut(mPutFinalFlag, true);
-
-    // Send progress update
-    mSentFileLength += mBodySegmentLength;
-    if (mSentFileLength > kUpdateProgressBase * mUpdateProgressCounter) {
-      UpdateProgress();
-      mUpdateProgressCounter = mSentFileLength / kUpdateProgressBase + 1;
-    }
-
-    // Success to receive a file and notify completion
-    if (mPutFinalFlag) {
-      mSuccessFlag = true;
-      FileTransferComplete();
-      NotifyAboutFileChange();
-    }
-  } else if (opCode == ObexRequestCode::Get ||
-             opCode == ObexRequestCode::GetFinal ||
-             opCode == ObexRequestCode::SetPath) {
-    ReplyError(ObexResponseCode::BadRequest);
-    BT_WARNING("Unsupported ObexRequestCode");
-  } else {
-    ReplyError(ObexResponseCode::NotImplemented);
-    BT_WARNING("Unrecognized ObexRequestCode");
-  }
-}
-
-void
-BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  uint8_t opCode = aMessage->mData[0];
-
-  // Check response code and send out system message as finished if the response
-  // code is somehow incorrect.
-  uint8_t expectedOpCode = ObexResponseCode::Success;
-  if (mLastCommand == ObexRequestCode::Put) {
-    expectedOpCode = ObexResponseCode::Continue;
-  }
-
-  if (opCode != expectedOpCode) {
-    if (mLastCommand == ObexRequestCode::Put ||
-        mLastCommand == ObexRequestCode::Abort ||
-        mLastCommand == ObexRequestCode::PutFinal) {
-      SendDisconnectRequest();
-    }
-    nsAutoCString str;
-    str += "[OPP] 0x";
-    str.AppendInt(mLastCommand, 16);
-    str += " failed";
-    BT_WARNING(str.get());
-    FileTransferComplete();
-    return;
-  }
-
-  if (mLastCommand == ObexRequestCode::PutFinal) {
-    mSuccessFlag = true;
-    FileTransferComplete();
-
-    if (mInputStream) {
-      mInputStream->Close();
-      mInputStream = nullptr;
-    }
-
-    if (mCurrentBlobIndex + 1 == (int) mBatches[0].mBlobs.Length()) {
-      SendDisconnectRequest();
-    } else {
-      StartSendingNextFile();
-    }
-  } else if (mLastCommand == ObexRequestCode::Abort) {
-    SendDisconnectRequest();
-    FileTransferComplete();
-  } else if (mLastCommand == ObexRequestCode::Disconnect) {
-    AfterOppDisconnected();
-    // Most devices will directly terminate connection after receiving
-    // Disconnect request, so we make a delay here. If the socket hasn't been
-    // disconnected, we will close it.
-    if (mSocket) {
-      MessageLoop::current()->
-        PostDelayedTask(FROM_HERE, new CloseSocketTask(mSocket), 1000);
-    }
-  } else if (mLastCommand == ObexRequestCode::Connect) {
-    MOZ_ASSERT(!mFileName.IsEmpty());
-    MOZ_ASSERT(mBlob);
-
-    AfterOppConnected();
-
-    // Keep remote information
-    mRemoteObexVersion = aMessage->mData[3];
-    mRemoteConnectionFlags = aMessage->mData[4];
-    mRemoteMaxPacketLength =
-      (((int)(aMessage->mData[5]) << 8) | aMessage->mData[6]);
-
-    SendPutHeaderRequest(mFileName, mFileLength);
-  } else if (mLastCommand == ObexRequestCode::Put) {
-    if (mWaitingToSendPutFinal) {
-      SendPutFinalRequest();
-      return;
-    }
-
-    if (kUpdateProgressBase * mUpdateProgressCounter < mSentFileLength) {
-      UpdateProgress();
-      mUpdateProgressCounter = mSentFileLength / kUpdateProgressBase + 1;
-    }
-
-    nsresult rv;
-    if (!mInputStream) {
-      rv = mBlob->GetInternalStream(getter_AddRefs(mInputStream));
-      if (NS_FAILED(rv)) {
-        BT_WARNING("Can't get internal stream of blob");
-        SendDisconnectRequest();
-        return;
-      }
-    }
-
-    nsRefPtr<ReadFileTask> task = new ReadFileTask(mInputStream,
-                                                   mRemoteMaxPacketLength);
-    rv = mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL);
-    if (NS_FAILED(rv)) {
-      BT_WARNING("Cannot dispatch read file task!");
-      SendDisconnectRequest();
-    }
-  } else {
-    BT_WARNING("Unhandled ObexRequestCode");
-  }
-}
-
-// Virtual function of class SocketConsumer
-void
-BluetoothOppManager::ReceiveSocketData(BluetoothSocket* aSocket,
-                                       nsAutoPtr<UnixSocketRawData>& aMessage)
-{
-  if (mIsServer) {
-    ServerDataHandler(aMessage);
-  } else {
-    ClientDataHandler(aMessage);
-  }
-}
-
-void
-BluetoothOppManager::SendConnectRequest()
-{
-  if (mConnected) return;
-
-  // Section 3.3.1 "Connect", IrOBEX 1.2
-  // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
-  // [Headers:var]
-  uint8_t req[255];
-  int index = 7;
-
-  req[3] = 0x10; // version=1.0
-  req[4] = 0x00; // flag=0x00
-  req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
-  req[6] = (uint8_t)BluetoothOppManager::MAX_PACKET_LENGTH;
-
-  SendObexData(req, ObexRequestCode::Connect, index);
-}
-
-void
-BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName,
-                                          int aFileSize)
-{
-  if (!mConnected) return;
-
-  uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
-
-  int len = aFileName.Length();
-  uint8_t* fileName = new uint8_t[(len + 1) * 2];
-  const PRUnichar* fileNamePtr = aFileName.BeginReading();
-
-  for (int i = 0; i < len; i++) {
-    fileName[i * 2] = (uint8_t)(fileNamePtr[i] >> 8);
-    fileName[i * 2 + 1] = (uint8_t)fileNamePtr[i];
-  }
-
-  fileName[len * 2] = 0x00;
-  fileName[len * 2 + 1] = 0x00;
-
-  int index = 3;
-  index += AppendHeaderName(&req[index], (char*)fileName, (len + 1) * 2);
-  index += AppendHeaderLength(&req[index], aFileSize);
-
-  SendObexData(req, ObexRequestCode::Put, index);
-
-  delete [] fileName;
-  delete [] req;
-}
-
-void
-BluetoothOppManager::SendPutRequest(uint8_t* aFileBody,
-                                    int aFileBodyLength)
-{
-  int packetLeftSpace = mRemoteMaxPacketLength - kPutRequestHeaderSize;
-
-  if (!mConnected) return;
-  if (aFileBodyLength > packetLeftSpace) {
-    BT_WARNING("Not allowed such a small MaxPacketLength value");
-    return;
-  }
-
-  // Section 3.3.3 "Put", IrOBEX 1.2
-  // [opcode:1][length:2][Headers:var]
-  uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
-
-  int index = 3;
-  index += AppendHeaderBody(&req[index], aFileBody, aFileBodyLength);
-
-  SendObexData(req, ObexRequestCode::Put, index);
-  delete [] req;
-
-  mSentFileLength += aFileBodyLength;
-}
-
-void
-BluetoothOppManager::SendPutFinalRequest()
-{
-  if (!mConnected) return;
-
-  /**
-   * Section 2.2.9, "End-of-Body", IrObex 1.2
-   * End-of-Body is used to identify the last chunk of the object body.
-   * For most platforms, a PutFinal packet is sent with an zero length
-   * End-of-Body header.
-   */
-
-  // [opcode:1][length:2]
-  int index = 3;
-  uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
-  index += AppendHeaderEndOfBody(&req[index]);
-
-  SendObexData(req, ObexRequestCode::PutFinal, index);
-  delete [] req;
-
-  mWaitingToSendPutFinal = false;
-}
-
-void
-BluetoothOppManager::SendDisconnectRequest()
-{
-  if (!mConnected) return;
-
-  // Section 3.3.2 "Disconnect", IrOBEX 1.2
-  // [opcode:1][length:2][Headers:var]
-  uint8_t req[255];
-  int index = 3;
-
-  SendObexData(req, ObexRequestCode::Disconnect, index);
-}
-
-void
-BluetoothOppManager::CheckPutFinal(uint32_t aNumRead)
-{
-  if (mSentFileLength + aNumRead >= mFileLength) {
-    mWaitingToSendPutFinal = true;
-  }
-}
-
-bool
-BluetoothOppManager::IsConnected()
-{
-  return (mConnected && !mSendTransferCompleteFlag);
-}
-
-void
-BluetoothOppManager::GetAddress(nsAString& aDeviceAddress)
-{
-  return mSocket->GetAddress(aDeviceAddress);
-}
-
-void
-BluetoothOppManager::ReplyToConnect()
-{
-  if (mConnected) return;
-
-  // Section 3.3.1 "Connect", IrOBEX 1.2
-  // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
-  // [Headers:var]
-  uint8_t req[255];
-  int index = 7;
-
-  req[3] = 0x10; // version=1.0
-  req[4] = 0x00; // flag=0x00
-  req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
-  req[6] = (uint8_t)BluetoothOppManager::MAX_PACKET_LENGTH;
-
-  SendObexData(req, ObexResponseCode::Success, index);
-}
-
-void
-BluetoothOppManager::ReplyToDisconnectOrAbort()
-{
-  if (!mConnected) return;
-
-  // Section 3.3.2 "Disconnect" and Section 3.3.5 "Abort", IrOBEX 1.2
-  // The format of response packet of "Disconnect" and "Abort" are the same
-  // [opcode:1][length:2][Headers:var]
-  uint8_t req[255];
-  int index = 3;
-
-  SendObexData(req, ObexResponseCode::Success, index);
-}
-
-void
-BluetoothOppManager::ReplyToPut(bool aFinal, bool aContinue)
-{
-  if (!mConnected) return;
-
-  // Section 3.3.2 "Disconnect", IrOBEX 1.2
-  // [opcode:1][length:2][Headers:var]
-  uint8_t req[255];
-  int index = 3;
-  uint8_t opcode;
-
-  if (aContinue) {
-    opcode = (aFinal)? ObexResponseCode::Success :
-                       ObexResponseCode::Continue;
-  } else {
-    opcode = (aFinal)? ObexResponseCode::Unauthorized :
-                       ObexResponseCode::Unauthorized & (~FINAL_BIT);
-  }
-
-  SendObexData(req, opcode, index);
-}
-
-void
-BluetoothOppManager::ReplyError(uint8_t aError)
-{
-  if (!mConnected) return;
-
-  // Section 3.2 "Response Format", IrOBEX 1.2
-  // [opcode:1][length:2][Headers:var]
-  uint8_t req[255];
-  int index = 3;
-
-  SendObexData(req, aError, index);
-}
-
-void
-BluetoothOppManager::SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize)
-{
-  SetObexPacketInfo(aData, aOpcode, aSize);
-
-  if (!mIsServer) {
-    mLastCommand = aOpcode;
-  }
-
-  UnixSocketRawData* s = new UnixSocketRawData(aSize);
-  memcpy(s->mData, aData, s->mSize);
-  mSocket->SendSocketData(s);
-}
-
-void
-BluetoothOppManager::FileTransferComplete()
-{
-  if (mSendTransferCompleteFlag) {
-    return;
-  }
-
-  nsString type, name;
-  BluetoothValue v;
-  InfallibleTArray<BluetoothNamedValue> parameters;
-  type.AssignLiteral("bluetooth-opp-transfer-complete");
-
-  name.AssignLiteral("address");
-  v = mConnectedDeviceAddress;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("success");
-  v = mSuccessFlag;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("received");
-  v = mIsServer;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileName");
-  v = mFileName;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileLength");
-  v = mSentFileLength;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("contentType");
-  v = mContentType;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  if (!BroadcastSystemMessage(type, parameters)) {
-    BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
-    return;
-  }
-
-  mSendTransferCompleteFlag = true;
-}
-
-void
-BluetoothOppManager::StartFileTransfer()
-{
-  nsString type, name;
-  BluetoothValue v;
-  InfallibleTArray<BluetoothNamedValue> parameters;
-  type.AssignLiteral("bluetooth-opp-transfer-start");
-
-  name.AssignLiteral("address");
-  v = mConnectedDeviceAddress;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("received");
-  v = mIsServer;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileName");
-  v = mFileName;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileLength");
-  v = mFileLength;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("contentType");
-  v = mContentType;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  if (!BroadcastSystemMessage(type, parameters)) {
-    BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
-    return;
-  }
-
-  mSendTransferCompleteFlag = false;
-}
-
-void
-BluetoothOppManager::UpdateProgress()
-{
-  nsString type, name;
-  BluetoothValue v;
-  InfallibleTArray<BluetoothNamedValue> parameters;
-  type.AssignLiteral("bluetooth-opp-update-progress");
-
-  name.AssignLiteral("address");
-  v = mConnectedDeviceAddress;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("received");
-  v = mIsServer;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("processedLength");
-  v = mSentFileLength;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileLength");
-  v = mFileLength;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  if (!BroadcastSystemMessage(type, parameters)) {
-    BT_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
-    return;
-  }
-}
-
-void
-BluetoothOppManager::ReceivingFileConfirmation()
-{
-  nsString type, name;
-  BluetoothValue v;
-  InfallibleTArray<BluetoothNamedValue> parameters;
-  type.AssignLiteral("bluetooth-opp-receiving-file-confirmation");
-
-  name.AssignLiteral("address");
-  v = mConnectedDeviceAddress;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileName");
-  v = mFileName;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("fileLength");
-  v = mFileLength;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  name.AssignLiteral("contentType");
-  v = mContentType;
-  parameters.AppendElement(BluetoothNamedValue(name, v));
-
-  if (!BroadcastSystemMessage(type, parameters)) {
-    BT_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
-    return;
-  }
-}
-
-void
-BluetoothOppManager::NotifyAboutFileChange()
-{
-  NS_NAMED_LITERAL_STRING(data, "modified");
-
-  nsCOMPtr<nsIObserverService> obs =
-    mozilla::services::GetObserverService();
-  NS_ENSURE_TRUE_VOID(obs);
-
-  obs->NotifyObservers(mDsFile, "file-watcher-notify", data.get());
-}
-
-void
-BluetoothOppManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
-{
-  BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer)? "server" : "client");
-  MOZ_ASSERT(aSocket);
-
-  /**
-   * If the created connection is an inbound connection, close another server
-   * socket because currently only one file-transfer session is allowed. After
-   * that, we need to make sure that both server socket would be nulled out.
-   * As for outbound connections, we just notify the controller that it's done.
-   */
-  if (aSocket == mRfcommSocket) {
-    MOZ_ASSERT(!mSocket);
-    mRfcommSocket.swap(mSocket);
-
-    mL2capSocket->Disconnect();
-    mL2capSocket = nullptr;
-  } else if (aSocket == mL2capSocket) {
-    MOZ_ASSERT(!mSocket);
-    mL2capSocket.swap(mSocket);
-
-    mRfcommSocket->Disconnect();
-    mRfcommSocket = nullptr;
-  }
-
-  // Cache device address since we can't get socket address when a remote
-  // device disconnect with us.
-  mSocket->GetAddress(mConnectedDeviceAddress);
-
-  // Start sending file if we connect as a client
-  if (!mIsServer) {
-    StartSendingNextFile();
-  }
-}
-
-void
-BluetoothOppManager::OnSocketConnectError(BluetoothSocket* aSocket)
-{
-  BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer)? "server" : "client");
-
-  mRfcommSocket = nullptr;
-  mL2capSocket = nullptr;
-  mSocket = nullptr;
-
-  if (!mIsServer) {
-    // Inform gaia of remaining blobs' sending failure
-    DiscardBlobsToSend();
-  }
-
-  // Listen as a server if there's no more batch to process
-  if (!ProcessNextBatch()) {
-    Listen();
-  }
-}
-
-void
-BluetoothOppManager::OnSocketDisconnect(BluetoothSocket* aSocket)
-{
-  BT_LOGR("%s: [%s]", __FUNCTION__, (mIsServer)? "server" : "client");
-  MOZ_ASSERT(aSocket);
-
-  if (aSocket != mSocket) {
-    // Do nothing when a listening server socket is closed.
-    return;
-  }
-
-  /**
-   * It is valid for a bluetooth device which is transfering file via OPP
-   * closing socket without sending OBEX disconnect request first. So we
-   * delete the broken file when we failed to receive a file from the remote,
-   * and notify the transfer has been completed (but failed). We also call
-   * AfterOppDisconnected here to ensure all variables will be cleaned.
-   */
-  if (!mSuccessFlag) {
-    if (mIsServer) {
-      DeleteReceivedFile();
-    }
-
-    FileTransferComplete();
-    if (!mIsServer) {
-      // Inform gaia of remaining blobs' sending failure
-      DiscardBlobsToSend();
-    }
-  }
-
-  AfterOppDisconnected();
-  mConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
-  mSuccessFlag = false;
-
-  mSocket = nullptr;
-  // Listen as a server if there's no more batch to process
-  if (!ProcessNextBatch()) {
-    Listen();
-  }
-}
-
-void
-BluetoothOppManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
-                                         const nsAString& aServiceUuid,
-                                         int aChannel)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsEmpty());
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE_VOID(bs);
-
-  if (aChannel < 0) {
-    if (mNeedsUpdatingSdpRecords) {
-      mNeedsUpdatingSdpRecords = false;
-      bs->UpdateSdpRecords(aDeviceAddress, this);
-    } else {
-      OnSocketConnectError(mSocket);
-    }
-
-    return;
-  }
-
-  if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) {
-    OnSocketConnectError(mSocket);
-  }
-}
-
-void
-BluetoothOppManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsEmpty());
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE_VOID(bs);
-
-  nsString uuid;
-  BluetoothUuidHelper::GetString(BluetoothServiceClass::OBJECT_PUSH, uuid);
-
-  if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress, uuid, this))) {
-    OnSocketConnectError(mSocket);
-  }
-}
-
-NS_IMPL_ISUPPORTS1(BluetoothOppManager, nsIObserver)
-
-bool
-BluetoothOppManager::AcquireSdcardMountLock()
-{
-  nsCOMPtr<nsIVolumeService> volumeSrv =
-    do_GetService(NS_VOLUMESERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(volumeSrv, false);
-  nsresult rv;
-  rv = volumeSrv->CreateMountLock(NS_LITERAL_STRING("sdcard"),
-                                  getter_AddRefs(mMountLock));
-  NS_ENSURE_SUCCESS(rv, false);
-  return true;
-}
-
-void
-BluetoothOppManager::Connect(const nsAString& aDeviceAddress,
-                             BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(false);
-}
-
-void
-BluetoothOppManager::Disconnect(BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(false);
-}
-
-void
-BluetoothOppManager::OnConnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(false);
-}
-
-void
-BluetoothOppManager::OnDisconnect(const nsAString& aErrorStr)
-{
-  MOZ_ASSERT(false);
-}
deleted file mode 100644
--- a/dom/bluetooth/BluetoothOppManager.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothoppmanager_h__
-#define mozilla_dom_bluetooth_bluetoothoppmanager_h__
-
-#include "BluetoothCommon.h"
-#include "BluetoothProfileManagerBase.h"
-#include "BluetoothSocketObserver.h"
-#include "DeviceStorage.h"
-#include "mozilla/dom/ipc/Blob.h"
-#include "mozilla/ipc/UnixSocket.h"
-#include "nsCOMArray.h"
-
-class nsIOutputStream;
-class nsIInputStream;
-class nsIVolumeMountLock;
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class BluetoothSocket;
-class ObexHeaderSet;
-class SendFileBatch;
-
-class BluetoothOppManager : public BluetoothSocketObserver
-                          , public BluetoothProfileManagerBase
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-  BT_DECL_PROFILE_MGR_BASE
-  virtual void GetName(nsACString& aName)
-  {
-    aName.AssignLiteral("OPP");
-  }
-
-  /*
-   * Channel of reserved services are fixed values, please check
-   * function add_reserved_service_records() in
-   * external/bluetooth/bluez/src/adapter.c for more information.
-   */
-  static const int DEFAULT_OPP_CHANNEL = 10;
-  static const int MAX_PACKET_LENGTH = 0xFFFE;
-
-  ~BluetoothOppManager();
-  static BluetoothOppManager* Get();
-  void ClientDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
-  void ServerDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
-
-  bool Listen();
-
-  bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor);
-  bool StopSendingFile();
-  bool ConfirmReceivingFile(bool aConfirm);
-
-  void SendConnectRequest();
-  void SendPutHeaderRequest(const nsAString& aFileName, int aFileSize);
-  void SendPutRequest(uint8_t* aFileBody, int aFileBodyLength);
-  void SendPutFinalRequest();
-  void SendDisconnectRequest();
-
-  void ExtractPacketHeaders(const ObexHeaderSet& aHeader);
-  bool ExtractBlobHeaders();
-  void CheckPutFinal(uint32_t aNumRead);
-
-  // The following functions are inherited from BluetoothSocketObserver
-  void ReceiveSocketData(
-    BluetoothSocket* aSocket,
-    nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) MOZ_OVERRIDE;
-  virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE;
-  virtual void OnSocketConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE;
-  virtual void OnSocketDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE;
-
-private:
-  BluetoothOppManager();
-  bool Init();
-  void HandleShutdown();
-
-  void StartFileTransfer();
-  void StartSendingNextFile();
-  void FileTransferComplete();
-  void UpdateProgress();
-  void ReceivingFileConfirmation();
-  bool CreateFile();
-  bool WriteToFile(const uint8_t* aData, int aDataLength);
-  void DeleteReceivedFile();
-  void ReplyToConnect();
-  void ReplyToDisconnectOrAbort();
-  void ReplyToPut(bool aFinal, bool aContinue);
-  void ReplyError(uint8_t aError);
-  void AfterOppConnected();
-  void AfterFirstPut();
-  void AfterOppDisconnected();
-  void ValidateFileName();
-  bool IsReservedChar(PRUnichar c);
-  void ClearQueue();
-  void RetrieveSentFileName();
-  void NotifyAboutFileChange();
-  bool AcquireSdcardMountLock();
-  void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize);
-  void AppendBlobToSend(const nsAString& aDeviceAddress, BlobParent* aActor);
-  void DiscardBlobsToSend();
-  bool ProcessNextBatch();
-  void ConnectInternal(const nsAString& aDeviceAddress);
-
-  /**
-   * Usually we won't get a full PUT packet in one operation, which means that
-   * a packet may be devided into several parts and BluetoothOppManager should
-   * be in charge of assembling.
-   *
-   * @return true if a packet has been fully received.
-   *         false if the received length exceeds/not reaches the expected
-   *         length.
-   */
-  bool ComposePacket(uint8_t aOpCode, UnixSocketRawData* aMessage);
-
-  /**
-   * OBEX session status.
-   * Set when OBEX session is established.
-   */
-  bool mConnected;
-  nsString mConnectedDeviceAddress;
-
-  /**
-   * Remote information
-   */
-  uint8_t mRemoteObexVersion;
-  uint8_t mRemoteConnectionFlags;
-  int mRemoteMaxPacketLength;
-
-  /**
-   * For sending files, we decide our next action based on current command and
-   * previous one.
-   * For receiving files, we don't need previous command and it is set to 0
-   * as a default value.
-   */
-  int mLastCommand;
-
-  int mPacketLength;
-  int mPacketReceivedLength;
-  int mBodySegmentLength;
-  int mUpdateProgressCounter;
-
-  /**
-   * When it is true and the target service on target device couldn't be found,
-   * refreshing SDP records is necessary.
-   */
-  bool mNeedsUpdatingSdpRecords;
-
-  /**
-   * Set when StopSendingFile() is called.
-   */
-  bool mAbortFlag;
-
-  /**
-   * Set when receiving the first PUT packet of a new file
-   */
-  bool mNewFileFlag;
-
-  /**
-   * Set when receiving a PutFinal packet
-   */
-  bool mPutFinalFlag;
-
-  /**
-   * Set when FileTransferComplete() is called
-   */
-  bool mSendTransferCompleteFlag;
-
-  /**
-   * Set when a transfer is successfully completed.
-   */
-  bool mSuccessFlag;
-
-  /**
-   * True: Receive file (Server)
-   * False: Send file (Client)
-   */
-  bool mIsServer;
-
-  /**
-   * Set when receiving the first PUT packet and wait for
-   * ConfirmReceivingFile() to be called.
-   */
-  bool mWaitingForConfirmationFlag;
-
-  nsString mFileName;
-  nsString mContentType;
-  uint32_t mFileLength;
-  uint32_t mSentFileLength;
-  bool mWaitingToSendPutFinal;
-
-  nsAutoArrayPtr<uint8_t> mBodySegment;
-  nsAutoArrayPtr<uint8_t> mReceivedDataBuffer;
-
-  int mCurrentBlobIndex;
-  nsCOMPtr<nsIDOMBlob> mBlob;
-  nsTArray<SendFileBatch> mBatches;
-
-  /**
-   * A seperate member thread is required because our read calls can block
-   * execution, which is not allowed to happen on the IOThread.
-   */
-  nsCOMPtr<nsIThread> mReadFileThread;
-  nsCOMPtr<nsIOutputStream> mOutputStream;
-  nsCOMPtr<nsIInputStream> mInputStream;
-  nsCOMPtr<nsIVolumeMountLock> mMountLock;
-  nsRefPtr<DeviceStorageFile> mDsFile;
-
-  // If a connection has been established, mSocket will be the socket
-  // communicating with the remote socket. We maintain the invariant that if
-  // mSocket is non-null, mRfcommSocket and mL2capSocket must be null (and vice
-  // versa).
-  nsRefPtr<BluetoothSocket> mSocket;
-
-  // Server sockets. Once an inbound connection is established, it will hand
-  // over the ownership to mSocket, and get a new server socket while Listen()
-  // is called.
-  nsRefPtr<BluetoothSocket> mRfcommSocket;
-  nsRefPtr<BluetoothSocket> mL2capSocket;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothSocket.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothSocket.h"
-
-#include "BluetoothSocketObserver.h"
-#include "BluetoothUnixSocketConnector.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla::ipc;
-USING_BLUETOOTH_NAMESPACE
-
-BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
-                                 BluetoothSocketType aType,
-                                 bool aAuth,
-                                 bool aEncrypt)
-  : mObserver(aObserver)
-  , mType(aType)
-  , mAuth(aAuth)
-  , mEncrypt(aEncrypt)
-{
-  MOZ_ASSERT(aObserver);
-}
-
-bool
-BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!aDeviceAddress.IsEmpty());
-
-  nsAutoPtr<BluetoothUnixSocketConnector> c(
-    new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
-
-  if (!ConnectSocket(c.forget(), aDeviceAddress.BeginReading())) {
-    nsAutoString addr;
-    GetAddress(addr);
-    BT_LOGD("%s failed. Current connected device address: %s",
-           __FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
-    return false;
-  }
-
-  return true;
-}
-
-bool
-BluetoothSocket::Listen(int aChannel)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsAutoPtr<BluetoothUnixSocketConnector> c(
-    new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
-
-  if (!ListenSocket(c.forget())) {
-    nsAutoString addr;
-    GetAddress(addr);
-    BT_LOGD("%s failed. Current connected device address: %s",
-           __FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
-    return false;
-  }
-
-  return true;
-}
-
-void
-BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mObserver);
-  mObserver->ReceiveSocketData(this, aMessage);
-}
-
-void
-BluetoothSocket::OnConnectSuccess()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mObserver);
-  mObserver->OnSocketConnectSuccess(this);
-}
-
-void
-BluetoothSocket::OnConnectError()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mObserver);
-  mObserver->OnSocketConnectError(this);
-}
-
-void
-BluetoothSocket::OnDisconnect()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mObserver);
-  mObserver->OnSocketDisconnect(this);
-}
-
deleted file mode 100644
--- a/dom/bluetooth/BluetoothUnixSocketConnector.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * NOTE: Due to being based on the dbus compatibility layer for
- * android's bluetooth implementation, this file is licensed under the
- * apache license instead of MPL.
- *
- */
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <sys/socket.h>
-#ifdef MOZ_B2G_BT_BLUEZ
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-#endif
-#include "BluetoothUnixSocketConnector.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla::ipc;
-USING_BLUETOOTH_NAMESPACE
-
-static const int RFCOMM_SO_SNDBUF = 70 * 1024;  // 70 KB send buffer
-static const int L2CAP_SO_SNDBUF = 400 * 1024;  // 400 KB send buffer
-static const int L2CAP_SO_RCVBUF = 400 * 1024;  // 400 KB receive buffer
-static const int L2CAP_MAX_MTU = 65000;
-
-#ifdef MOZ_B2G_BT_BLUEZ
-static
-int get_bdaddr(const char *str, bdaddr_t *ba)
-{
-  char *d = ((char*)ba) + 5, *endp;
-  for (int i = 0; i < 6; i++) {
-    *d-- = strtol(str, &endp, 16);
-    MOZ_ASSERT(!(*endp != ':' && i != 5));
-    str = endp + 1;
-  }
-  return 0;
-}
-
-static
-void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
-    const uint8_t *b = (const uint8_t *)ba;
-    sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-            b[5], b[4], b[3], b[2], b[1], b[0]);
-}
-
-#endif
-
-BluetoothUnixSocketConnector::BluetoothUnixSocketConnector(
-  BluetoothSocketType aType,
-  int aChannel,
-  bool aAuth,
-  bool aEncrypt) : mType(aType)
-                 , mChannel(aChannel)
-                 , mAuth(aAuth)
-                 , mEncrypt(aEncrypt)
-{
-}
-
-bool
-BluetoothUnixSocketConnector::SetUp(int aFd)
-{
-#ifdef MOZ_B2G_BT_BLUEZ
-  int lm = 0;
-  int sndbuf, rcvbuf;
-
-  /* kernel does not yet support LM for SCO */
-  switch (mType) {
-  case BluetoothSocketType::RFCOMM:
-    lm |= mAuth ? RFCOMM_LM_AUTH : 0;
-    lm |= mEncrypt ? RFCOMM_LM_ENCRYPT : 0;
-    break;
-  case BluetoothSocketType::L2CAP:
-  case BluetoothSocketType::EL2CAP:
-    lm |= mAuth ? L2CAP_LM_AUTH : 0;
-    lm |= mEncrypt ? L2CAP_LM_ENCRYPT : 0;
-    break;
-  case BluetoothSocketType::SCO:
-    break;
-  default:
-    MOZ_CRASH("Unknown socket type!");
-  }
-
-  if (lm) {
-    if (mType == BluetoothSocketType::RFCOMM) {
-      if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
-        BT_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
-        return false;
-      }
-    } else if (mType == BluetoothSocketType::L2CAP ||
-               mType == BluetoothSocketType::EL2CAP) {
-      if (setsockopt(aFd, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm))) {
-        BT_WARNING("setsockopt(L2CAP_LM) failed, throwing");
-        return false;
-      }
-    }
-  }
-
-  if (mType == BluetoothSocketType::RFCOMM) {
-    sndbuf = RFCOMM_SO_SNDBUF;
-    if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
-      BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
-      return false;
-    }
-  }
-
-  /* Setting L2CAP socket options */
-  if (mType == BluetoothSocketType::L2CAP ||
-      mType == BluetoothSocketType::EL2CAP) {
-    struct l2cap_options opts;
-    socklen_t optlen = sizeof(opts);
-    int err;
-    err = getsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
-    if (!err) {
-      /* setting MTU for [E]L2CAP */
-      opts.omtu = opts.imtu = L2CAP_MAX_MTU;
-
-      /* Enable ERTM for [E]L2CAP */
-      if (mType == BluetoothSocketType::EL2CAP) {
-        opts.flush_to = 0xffff; /* infinite */
-        opts.mode = L2CAP_MODE_ERTM;
-        opts.fcs = 1;
-        opts.txwin_size = 64;
-        opts.max_tx = 10;
-      }
-
-      err = setsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen);
-    }
-
-    /* Set larger SNDBUF & RCVBUF for EL2CAP connections */
-    if (mType == BluetoothSocketType::EL2CAP) {
-      sndbuf = L2CAP_SO_SNDBUF;
-      if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
-        BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
-        return false;
-      }
-
-      rcvbuf = L2CAP_SO_RCVBUF;
-      if (setsockopt(aFd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) {
-        BT_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
-        return false;
-      }
-    }
-  }
-#endif
-  return true;
-}
-
-bool
-BluetoothUnixSocketConnector::SetUpListenSocket(int aFd)
-{
-  // Nothing to do here.
-  return true;
-}
-
-int
-BluetoothUnixSocketConnector::Create()
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  int fd = -1;
-
-#ifdef MOZ_B2G_BT_BLUEZ
-  switch (mType) {
-  case BluetoothSocketType::RFCOMM:
-    fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-    break;
-  case BluetoothSocketType::SCO:
-    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
-    break;
-  case BluetoothSocketType::L2CAP:
-    fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-    break;
-  case BluetoothSocketType::EL2CAP:
-    fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
-    break;
-  default:
-    MOZ_CRASH();
-  }
-
-  if (fd < 0) {
-    BT_WARNING("Could not open bluetooth socket!");
-    return -1;
-  }
-
-  if (!SetUp(fd)) {
-    BT_WARNING("Could not set up socket!");
-    return -1;
-  }
-#endif
-  return fd;
-}
-
-bool
-BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
-                                         socklen_t& aAddrSize,
-                                         sockaddr_any& aAddr,
-                                         const char* aAddress)
-{
-#ifdef MOZ_B2G_BT_BLUEZ
-  // Set to BDADDR_ANY, if it's not a server, we'll reset.
-  bdaddr_t bd_address_obj = {{0, 0, 0, 0, 0, 0}};
-
-  if (!aIsServer && aAddress && strlen(aAddress) > 0) {
-    if (get_bdaddr(aAddress, &bd_address_obj)) {
-      BT_WARNING("Can't get bluetooth address!");
-      return false;
-    }
-  }
-
-  // Initialize
-  memset(&aAddr, 0, sizeof(aAddr));
-
-  switch (mType) {
-  case BluetoothSocketType::RFCOMM:
-    struct sockaddr_rc addr_rc;
-    aAddrSize = sizeof(addr_rc);
-    aAddr.rc.rc_family = AF_BLUETOOTH;
-    aAddr.rc.rc_channel = mChannel;
-    memcpy(&aAddr.rc.rc_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
-    break;
-  case BluetoothSocketType::L2CAP:
-  case BluetoothSocketType::EL2CAP:
-    struct sockaddr_l2 addr_l2;
-    aAddrSize = sizeof(addr_l2);
-    aAddr.l2.l2_family = AF_BLUETOOTH;
-    aAddr.l2.l2_psm = mChannel;
-    memcpy(&aAddr.l2.l2_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
-    break;
-  case BluetoothSocketType::SCO:
-    struct sockaddr_sco addr_sco;
-    aAddrSize = sizeof(addr_sco);
-    aAddr.sco.sco_family = AF_BLUETOOTH;
-    memcpy(&aAddr.sco.sco_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
-    break;
-  default:
-    BT_WARNING("Socket type unknown!");
-    return false;
-  }
-#endif
-  return true;
-}
-
-void
-BluetoothUnixSocketConnector::GetSocketAddr(const sockaddr_any& aAddr,
-                                            nsAString& aAddrStr)
-{
-#ifdef MOZ_B2G_BT_BLUEZ
-  char addr[18];
-  switch (mType) {
-  case BluetoothSocketType::RFCOMM:
-    get_bdaddr_as_string((bdaddr_t*)(&aAddr.rc.rc_bdaddr), addr);
-    break;
-  case BluetoothSocketType::SCO:
-    get_bdaddr_as_string((bdaddr_t*)(&aAddr.sco.sco_bdaddr), addr);
-    break;
-  case BluetoothSocketType::L2CAP:
-  case BluetoothSocketType::EL2CAP:
-    get_bdaddr_as_string((bdaddr_t*)(&aAddr.l2.l2_bdaddr), addr);
-    break;
-  default:
-    MOZ_CRASH("Socket should be either RFCOMM or SCO!");
-  }
-  aAddrStr.AssignASCII(addr);
-#endif
-}
deleted file mode 100644
--- a/dom/bluetooth/BluetoothUnixSocketConnector.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_BluetoothUnixSocketConnector_h
-#define mozilla_dom_bluetooth_BluetoothUnixSocketConnector_h
-
-#include "BluetoothCommon.h"
-#include <sys/socket.h>
-#include <mozilla/ipc/UnixSocket.h>
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class BluetoothUnixSocketConnector : public mozilla::ipc::UnixSocketConnector
-{
-public:
-  BluetoothUnixSocketConnector(BluetoothSocketType aType, int aChannel,
-                               bool aAuth, bool aEncrypt);
-  virtual ~BluetoothUnixSocketConnector()
-  {}
-  virtual int Create() MOZ_OVERRIDE;
-  virtual bool CreateAddr(bool aIsServer,
-                          socklen_t& aAddrSize,
-                          mozilla::ipc::sockaddr_any& aAddr,
-                          const char* aAddress) MOZ_OVERRIDE;
-  virtual bool SetUp(int aFd) MOZ_OVERRIDE;
-  virtual bool SetUpListenSocket(int aFd) MOZ_OVERRIDE;
-  virtual void GetSocketAddr(const mozilla::ipc::sockaddr_any& aAddr,
-                             nsAString& aAddrStr) MOZ_OVERRIDE;
-
-private:
-  BluetoothSocketType mType;
-  int mChannel;
-  bool mAuth;
-  bool mEncrypt;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
--- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
@@ -265,25 +265,17 @@ BluetoothOppManager::ConnectInternal(con
   mSocket->Connect(aDeviceAddress, -1);
 }
 
 void
 BluetoothOppManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   sInShutdown = true;
-
-  if (mSocket) {
-    mSocket->Disconnect();
-    mSocket = nullptr;
-  }
-  if (mServerSocket) {
-    mServerSocket->Disconnect();
-    mServerSocket = nullptr;
-  }
+  Disconnect(nullptr);
   sBluetoothOppManager = nullptr;
 }
 
 bool
 BluetoothOppManager::Listen()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -437,20 +429,18 @@ BluetoothOppManager::ClearQueue()
 
 bool
 BluetoothOppManager::StopSendingFile()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mIsServer) {
     mAbortFlag = true;
-  } else if (mSocket) {
-    mSocket->Disconnect();
   } else {
-    BT_WARNING("%s: No ongoing file transfer to stop", __FUNCTION__);
+    Disconnect(nullptr);
   }
 
   return true;
 }
 
 bool
 BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
 {
@@ -503,19 +493,17 @@ BluetoothOppManager::AfterOppConnected()
   AfterFirstPut();
   // Get a mount lock to prevent the sdcard from being shared with
   // the PC while we're doing a OPP file transfer. After OPP transaction
   // were done, the mount lock will be freed.
   if (!AcquireSdcardMountLock()) {
     // If we fail to get a mount lock, abort this transaction
     // Directly sending disconnect-request is better than abort-request
     BT_WARNING("BluetoothOPPManager couldn't get a mount lock!");
-
-    MOZ_ASSERT(mSocket);
-    mSocket->Disconnect();
+    Disconnect(nullptr);
   }
 }
 
 void
 BluetoothOppManager::AfterOppDisconnected()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -1466,16 +1454,26 @@ BluetoothOppManager::OnSocketDisconnect(
 
   mSocket = nullptr;
   // Listen as a server if there's no more batch to process
   if (!ProcessNextBatch()) {
     Listen();
   }
 }
 
+void
+BluetoothOppManager::Disconnect(BluetoothProfileController* aController)
+{
+  if (mSocket) {
+    mSocket->Disconnect();
+  } else {
+    BT_WARNING("%s: No ongoing file transfer to stop", __FUNCTION__);
+  }
+}
+
 NS_IMPL_ISUPPORTS1(BluetoothOppManager, nsIObserver)
 
 bool
 BluetoothOppManager::AcquireSdcardMountLock()
 {
   nsCOMPtr<nsIVolumeService> volumeSrv =
     do_GetService(NS_VOLUMESERVICE_CONTRACTID);
   NS_ENSURE_TRUE(volumeSrv, false);
@@ -1503,22 +1501,16 @@ BluetoothOppManager::OnUpdateSdpRecords(
 void
 BluetoothOppManager::Connect(const nsAString& aDeviceAddress,
                              BluetoothProfileController* aController)
 {
   MOZ_ASSERT(false);
 }
 
 void
-BluetoothOppManager::Disconnect(BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(false);
-}
-
-void
 BluetoothOppManager::OnConnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(false);
 }
 
 void
 BluetoothOppManager::OnDisconnect(const nsAString& aErrorStr)
 {
--- a/dom/bluetooth/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp
@@ -276,29 +276,17 @@ BluetoothOppManager::ConnectInternal(con
     new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
 }
 
 void
 BluetoothOppManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   sInShutdown = true;
-
-  if (mSocket) {
-    mSocket->Disconnect();
-    mSocket = nullptr;
-  }
-  if (mRfcommSocket) {
-    mRfcommSocket->Disconnect();
-    mRfcommSocket = nullptr;
-  }
-  if (mL2capSocket) {
-    mL2capSocket->Disconnect();
-    mL2capSocket = nullptr;
-  }
+  Disconnect(nullptr);
   sBluetoothOppManager = nullptr;
 }
 
 bool
 BluetoothOppManager::Listen()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -457,20 +445,18 @@ BluetoothOppManager::ClearQueue()
 
 bool
 BluetoothOppManager::StopSendingFile()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mIsServer) {
     mAbortFlag = true;
-  } else if (mSocket) {
-    mSocket->Disconnect();
   } else {
-    BT_WARNING("%s: No ongoing file transfer to stop", __FUNCTION__);
+    Disconnect(nullptr);
   }
 
   return true;
 }
 
 bool
 BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
 {
@@ -523,19 +509,17 @@ BluetoothOppManager::AfterOppConnected()
   AfterFirstPut();
   // Get a mount lock to prevent the sdcard from being shared with
   // the PC while we're doing a OPP file transfer. After OPP transaction
   // were done, the mount lock will be freed.
   if (!AcquireSdcardMountLock()) {
     // If we fail to get a mount lock, abort this transaction
     // Directly sending disconnect-request is better than abort-request
     BT_WARNING("BluetoothOPPManager couldn't get a mount lock!");
-
-    MOZ_ASSERT(mSocket);
-    mSocket->Disconnect();
+    Disconnect(nullptr);
   }
 }
 
 void
 BluetoothOppManager::AfterOppDisconnected()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -1498,16 +1482,26 @@ BluetoothOppManager::OnSocketDisconnect(
   mSocket = nullptr;
   // Listen as a server if there's no more batch to process
   if (!ProcessNextBatch()) {
     Listen();
   }
 }
 
 void
+BluetoothOppManager::Disconnect(BluetoothProfileController* aController)
+{
+  if (mSocket) {
+    mSocket->Disconnect();
+  } else {
+    BT_WARNING("%s: No ongoing file transfer to stop", __FUNCTION__);
+  }
+}
+
+void
 BluetoothOppManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
                                          const nsAString& aServiceUuid,
                                          int aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
 
   BluetoothService* bs = BluetoothService::Get();
@@ -1564,22 +1558,16 @@ BluetoothOppManager::AcquireSdcardMountL
 void
 BluetoothOppManager::Connect(const nsAString& aDeviceAddress,
                              BluetoothProfileController* aController)
 {
   MOZ_ASSERT(false);
 }
 
 void
-BluetoothOppManager::Disconnect(BluetoothProfileController* aController)
-{
-  MOZ_ASSERT(false);
-}
-
-void
 BluetoothOppManager::OnConnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(false);
 }
 
 void
 BluetoothOppManager::OnDisconnect(const nsAString& aErrorStr)
 {
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -5,16 +5,17 @@
 #include "base/basictypes.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfo.h"
 #include "nsHashPropertyBag.h"
 #include "nsThread.h"
 #include "DeviceStorage.h"
 #include "mozilla/dom/CameraControlBinding.h"
 #include "mozilla/dom/TabChild.h"
+#include "mozilla/MediaManager.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "nsIAppsService.h"
 #include "nsIObserverService.h"
 #include "nsIDOMDeviceStorage.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsXULAppAPI.h"
 #include "DOMCameraManager.h"
@@ -346,34 +347,17 @@ nsDOMCameraControl::StartRecording(JSCon
   options.rotation = 0;
   options.maxFileSizeBytes = 0;
   options.maxVideoLengthMs = 0;
   aRv = options.Init(aCx, aOptions.address());
   if (aRv.Failed()) {
     return;
   }
 
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (!obs) {
-    NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  nsRefPtr<nsHashPropertyBag> props = CreateRecordingDeviceEventsSubject();
-  obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
-                       "recording-device-events",
-                       NS_LITERAL_STRING("starting").get());
-  // Forward recording events to parent process.
-  // The events are gathered in chrome process and used for recording indicator
-  if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    unused << TabChild::GetFrom(mWindow)->SendRecordingDeviceEvents(NS_LITERAL_STRING("starting"),
-                                                                    true /* isAudio */,
-                                                                    true /* isVideo */);
-  }
+  aRv = NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));
 
   #ifdef MOZ_B2G
   if (!mAudioChannelAgent) {
     mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
     if (mAudioChannelAgent) {
       // Camera app will stop recording when it falls to the background, so no callback is necessary.
       mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, nullptr);
       // Video recording doesn't output any sound, so it's not necessary to check canPlay.
@@ -390,33 +374,17 @@ nsDOMCameraControl::StartRecording(JSCon
   }
   aRv = mCameraControl->StartRecording(&options, folder, filename, onSuccess,
                                        onError.WasPassed() ? onError.Value() : nullptr);
 }
 
 void
 nsDOMCameraControl::StopRecording(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (!obs) {
-    NS_WARNING("Could not get the Observer service for CameraControl::StopRecording.");
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
-
-  nsRefPtr<nsHashPropertyBag> props = CreateRecordingDeviceEventsSubject();
-  obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props) ,
-                       "recording-device-events",
-                       NS_LITERAL_STRING("shutdown").get());
-  // Forward recording events to parent process.
-  // The events are gathered in chrome process and used for recording indicator
-  if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    unused << TabChild::GetFrom(mWindow)->SendRecordingDeviceEvents(NS_LITERAL_STRING("shutdown"),
-                                                                    true /* isAudio */,
-                                                                    true /* isVideo */);
-  }
+  aRv = NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown"));
 
   #ifdef MOZ_B2G
   if (mAudioChannelAgent) {
     mAudioChannelAgent->StopPlaying();
     mAudioChannelAgent = nullptr;
   }
   #endif
 
@@ -606,43 +574,19 @@ nsDOMCameraControl::Shutdown()
 }
 
 nsRefPtr<ICameraControl>
 nsDOMCameraControl::GetNativeCameraControl()
 {
   return mCameraControl;
 }
 
-already_AddRefed<nsHashPropertyBag>
-nsDOMCameraControl::CreateRecordingDeviceEventsSubject()
+nsresult
+nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
 {
-  MOZ_ASSERT(mWindow);
-
-  nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
-  props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), true);
-  props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), true);
-
-  nsCOMPtr<nsIDocShell> docShell = mWindow->GetDocShell();
-  if (docShell) {
-    bool isApp;
-    DebugOnly<nsresult> rv = docShell->GetIsApp(&isApp);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
+  NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
 
-    nsString requestURL;
-    if (isApp) {
-      rv = docShell->GetAppManifestURL(requestURL);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-    } else {
-      nsCString pageURL;
-      nsCOMPtr<nsIURI> docURI = mWindow->GetDocumentURI();
-      MOZ_ASSERT(docURI);
+  return MediaManager::NotifyRecordingStatusChange(mWindow,
+                                                   aMsg,
+                                                   true /* aIsAudio */,
+                                                   true /* aIsVideo */);
+}
 
-      rv = docURI->GetSpec(pageURL);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-      requestURL = NS_ConvertUTF8toUTF16(pageURL);
-    }
-    props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), isApp);
-    props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
-  }
-
-  return props.forget();
-}
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -99,17 +99,17 @@ public:
 protected:
   virtual ~nsDOMCameraControl();
 
 private:
   nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
   nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
-  already_AddRefed<nsHashPropertyBag> CreateRecordingDeviceEventsSubject();
+  nsresult NotifyRecordingStatusChange(const nsString& aMsg);
 
 protected:
   /* additional members */
   nsRefPtr<ICameraControl>        mCameraControl; // non-DOM camera control
   nsCOMPtr<nsICameraCapabilities> mDOMCapabilities;
   // An agent used to join audio channel service.
   nsCOMPtr<nsIAudioChannelAgent>  mAudioChannelAgent;
   nsCOMPtr<nsPIDOMWindow> mWindow;
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -278,27 +278,28 @@ let FormAssistant = {
         this._editor.addEditorObserver(this);
       }
 
       // If our focusedElement is removed from DOM we want to handle it properly
       let MutationObserver = element.ownerDocument.defaultView.MutationObserver;
       this._observer = new MutationObserver(function(mutations) {
         var del = [].some.call(mutations, function(m) {
           return [].some.call(m.removedNodes, function(n) {
-            return n === element;
+            return n.contains(element);
           });
         });
         if (del && element === self.focusedElement) {
           // item was deleted, fake a blur so all state gets set correctly
           self.handleEvent({ target: element, type: "blur" });
         }
       });
 
-      this._observer.observe(element.parentNode, {
-        childList: true
+      this._observer.observe(element.ownerDocument.body, {
+        childList: true,
+        subtree: true
       });
     }
 
     this.focusedElement = element;
   },
 
   get documentEncoder() {
     return this._documentEncoder;
@@ -512,20 +513,26 @@ let FormAssistant = {
         event.initEvent('input', true, false);
         target.dispatchEvent(event);
         break;
       }
 
       case "Forms:Input:SendKey":
         CompositionManager.endComposition('');
 
-        ["keydown", "keypress", "keyup"].forEach(function(type) {
-          domWindowUtils.sendKeyEvent(type, json.keyCode, json.charCode,
-            json.modifiers);
-        });
+        this._editing = true;
+        let doKeypress = domWindowUtils.sendKeyEvent('keydown', json.keyCode,
+                                  json.charCode, json.modifiers);
+        if (doKeypress) {
+          domWindowUtils.sendKeyEvent('keypress', json.keyCode,
+                                  json.charCode, json.modifiers);
+        }
+        domWindowUtils.sendKeyEvent('keyup', json.keyCode,
+                                  json.charCode, json.modifiers);
+        this._editing = false;
 
         if (json.requestId) {
           sendAsyncMessage("Forms:SendKey:Result:OK", {
             requestId: json.requestId
           });
         }
         break;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3099,10 +3099,37 @@ ContentParent::ShouldSandboxContentProce
 {
 #ifdef MOZ_CONTENT_SANDBOX
   return !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
 #else
   return true;
 #endif
 }
 
+bool
+ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
+                                         const nsString& aPageURL,
+                                         const bool& aIsAudio,
+                                         const bool& aIsVideo)
+{
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+        // recording-device-ipc-events needs to gather more information from content process
+        nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
+        props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), ChildID());
+        props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), IsForApp());
+        props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
+        props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
+
+        nsString requestURL = IsForApp() ? AppManifestURL() : aPageURL;
+        props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
+
+        obs->NotifyObservers((nsIPropertyBag2*) props,
+                             "recording-device-ipc-events",
+                             aRecordingStatus.get());
+    } else {
+        NS_WARNING("Could not get the Observer service for ContentParent::RecvRecordingDeviceEvents.");
+    }
+    return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -204,16 +204,20 @@ public:
 
     virtual PJavaScriptParent*
     AllocPJavaScriptParent() MOZ_OVERRIDE;
     virtual bool
     RecvPJavaScriptConstructor(PJavaScriptParent* aActor) MOZ_OVERRIDE {
         return PContentParent::RecvPJavaScriptConstructor(aActor);
     }
 
+    virtual bool RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
+                                           const nsString& aPageURL,
+                                           const bool& aIsAudio,
+                                           const bool& aIsVideo) MOZ_OVERRIDE;
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why);
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
     bool ShouldSandboxContentProcesses();
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -298,24 +298,16 @@ parent:
 
     /**
      * Notifies the parent about a scroll event. The pres shell ID and
      * view ID identify which scrollable (sub-)frame was scrolled, and
      * the new scroll offset for that frame is sent.
      */
     UpdateScrollOffset(uint32_t aPresShellId, ViewID aViewId, CSSIntPoint aScrollOffset);
 
-    /**
-     * Notifies the parent about a recording device is starting or shutdown.
-     * @param recordingStatus starting or shutdown
-     * @param isAudio recording start with microphone
-     * @param isVideo recording start with camera
-     */
-    async RecordingDeviceEvents(nsString recordingStatus, bool isAudio, bool isVideo);
-
     __delete__();
 
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -485,15 +485,27 @@ parent:
     sync KeywordToURI(nsCString keyword)
         returns (OptionalInputStreamParams postData, OptionalURIParams uri);
 
     sync SpeakerManagerForceSpeaker(bool aEnable);
 
     sync SpeakerManagerGetSpeakerStatus()
         returns (bool value);
 
+    /**
+     * Notifies the parent about a recording device is starting or shutdown.
+     * @param recordingStatus starting or shutdown
+     * @param pageURL URL that request that changing the recording status
+     * @param isAudio recording start with microphone
+     * @param isVideo recording start with camera
+     */
+    async RecordingDeviceEvents(nsString recordingStatus,
+                                nsString pageURL,
+                                bool isAudio,
+                                bool isVideo);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -26,17 +26,16 @@
 #include "mozilla/unused.h"
 #include "nsCOMPtr.h"
 #include "nsContentPermissionHelper.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsEventStateManager.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
-#include "nsHashPropertyBag.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
 #include "nsIDialogCreator.h"
 #include "nsIInterfaceRequestorUtils.h"
@@ -1658,44 +1657,10 @@ TabParent::RecvContentReceivedTouch(cons
                                     const bool& aPreventDefault)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->ContentReceivedTouch(aGuid, aPreventDefault);
   }
   return true;
 }
 
-bool
-TabParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
-                                     const bool& aIsAudio,
-                                     const bool& aIsVideo)
-{
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-        // recording-device-ipc-events needs to gather more information from content process
-        nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
-        props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), Manager()->ChildID());
-        props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), Manager()->IsForApp());
-        props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
-        props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
-
-        nsString requestURL;
-        if (Manager()->IsForApp()) {
-          requestURL = Manager()->AppManifestURL();
-        } else {
-          nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-          NS_ENSURE_TRUE(frameLoader, true);
-
-          frameLoader->GetURL(requestURL);
-        }
-        props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
-
-        obs->NotifyObservers((nsIPropertyBag2*) props,
-                             "recording-device-ipc-events",
-                             aRecordingStatus.get());
-    } else {
-        NS_WARNING("Could not get the Observer service for ContentParent::RecvRecordingDeviceEvents.");
-    }
-    return true;
-}
-
 } // namespace tabs
 } // namespace mozilla
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -169,19 +169,16 @@ public:
                                            const ViewID& aViewId,
                                            const bool& aIsRoot,
                                            const bool& aAllowZoom,
                                            const CSSToScreenScale& aMinZoom,
                                            const CSSToScreenScale& aMaxZoom);
     virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset);
     virtual bool RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid,
                                           const bool& aPreventDefault);
-    virtual bool RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
-                                           const bool& aIsAudio,
-                                           const bool& aIsVideo);
     virtual PContentDialogParent* AllocPContentDialogParent(const uint32_t& aType,
                                                             const nsCString& aName,
                                                             const nsCString& aFeatures,
                                                             const InfallibleTArray<int>& aIntParams,
                                                             const InfallibleTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialogParent(PContentDialogParent* aDialog)
     {
       delete aDialog;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -5,29 +5,27 @@
 #include "MediaManager.h"
 
 #include "MediaStreamGraph.h"
 #include "GetUserMediaRequest.h"
 #include "nsHashPropertyBag.h"
 #ifdef MOZ_WIDGET_GONK
 #include "nsIAudioManager.h"
 #endif
-#include "nsIAppsService.h"
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPopupWindowManager.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsIScriptSecurityManager.h"
-#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/GetUserMediaRequestBinding.h"
 
 #include "Latency.h"
 
 // For PR_snprintf
 #include "prprf.h"
 
@@ -138,55 +136,16 @@ static nsresult ValidateTrackConstraints
     nsresult rv = CompareDictionaries(aCx, track.mMandatory.Value(),
                                       aNormalized.mMandatory,
                                       aOutUnknownConstraint);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
-static already_AddRefed<nsHashPropertyBag>
-CreateRecordingDeviceEventsSubject(nsPIDOMWindow* aWindow,
-                                   const bool aIsAudio,
-                                   const bool aIsVideo)
-{
-  MOZ_ASSERT(aWindow);
-
-  nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
-  props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
-  props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
-
-  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
-  if (docShell) {
-    bool isApp;
-    DebugOnly<nsresult> rv = docShell->GetIsApp(&isApp);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-    nsString requestURL;
-    if (isApp) {
-      rv = docShell->GetAppManifestURL(requestURL);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-    } else {
-      nsCString pageURL;
-      nsCOMPtr<nsIURI> docURI = aWindow->GetDocumentURI();
-      MOZ_ASSERT(docURI);
-
-      rv = docURI->GetSpec(pageURL);
-      MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-      requestURL = NS_ConvertUTF8toUTF16(pageURL);
-    }
-
-    props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
-    props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), isApp);
-  }
-
-  return props.forget();
-}
-
 /**
  * Send an error back to content. The error is the form a string.
  * Do this only on the main thread. The success callback is also passed here
  * so it can be released correctly.
  */
 class ErrorCallbackRunnable : public nsRunnable
 {
 public:
@@ -1150,16 +1109,78 @@ MediaManager::Get() {
 /* static */ already_AddRefed<MediaManager>
 MediaManager::GetInstance()
 {
   // so we can have non-refcounted getters
   nsRefPtr<MediaManager> service = MediaManager::Get();
   return service.forget();
 }
 
+/* static */ nsresult
+MediaManager::NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
+                                          const nsString& aMsg,
+                                          const bool& aIsAudio,
+                                          const bool& aIsVideo)
+{
+  NS_ENSURE_ARG(aWindow);
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (!obs) {
+    NS_WARNING("Could not get the Observer service for GetUserMedia recording notification.");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
+  props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio);
+  props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo);
+
+  bool isApp = false;
+  nsString requestURL;
+
+  if (nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell()) {
+    nsresult rv = docShell->GetIsApp(&isApp);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (isApp) {
+      rv = docShell->GetAppManifestURL(requestURL);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
+  if (!isApp) {
+    nsCString pageURL;
+    nsCOMPtr<nsIURI> docURI = aWindow->GetDocumentURI();
+    NS_ENSURE_TRUE(docURI, NS_ERROR_FAILURE);
+
+    nsresult rv = docURI->GetSpec(pageURL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    requestURL = NS_ConvertUTF8toUTF16(pageURL);
+  }
+
+  props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), isApp);
+  props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
+
+  obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
+		       "recording-device-events",
+		       aMsg.get());
+
+  // Forward recording events to parent process.
+  // The events are gathered in chrome process and used for recording indicator
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    unused <<
+      dom::ContentChild::GetSingleton()->SendRecordingDeviceEvents(aMsg,
+                                                                   requestURL,
+                                                                   aIsAudio,
+                                                                   aIsVideo);
+  }
+
+  return NS_OK;
+}
+
 /**
  * The entry point for this file. A call from Navigator::mozGetUserMedia
  * will end up here. MediaManager is a singleton that is responsible
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
 MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
   nsPIDOMWindow* aWindow, const MediaStreamConstraints& aRawConstraints,
@@ -1816,45 +1837,29 @@ GetUserMediaNotificationEvent::Run()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   // Make sure mStream is cleared and our reference to the DOMMediaStream
   // is dropped on the main thread, no matter what happens in this method.
   // Otherwise this object might be destroyed off the main thread,
   // releasing DOMMediaStream off the main thread, which is not allowed.
   nsRefPtr<DOMMediaStream> stream = mStream.forget();
 
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (!obs) {
-    NS_WARNING("Could not get the Observer service for GetUserMedia recording notification.");
-    return NS_ERROR_FAILURE;
-  }
   nsString msg;
   switch (mStatus) {
   case STARTING:
     msg = NS_LITERAL_STRING("starting");
     stream->OnTracksAvailable(mOnTracksAvailableCallback.forget());
     break;
   case STOPPING:
     msg = NS_LITERAL_STRING("shutdown");
     if (mListener) {
       mListener->SetStopped();
     }
     break;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
-  MOZ_ASSERT(window);
-
-  nsRefPtr<nsHashPropertyBag> props = 
-    CreateRecordingDeviceEventsSubject(window, mIsAudio, mIsVideo);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
-		       "recording-device-events",
-		       msg.get());
-  // Forward recording events to parent process.
-  // The events are gathered in chrome process and used for recording indicator
-  if (XRE_GetProcessType() != GeckoProcessType_Default) {
-    unused << dom::TabChild::GetFrom(window)->SendRecordingDeviceEvents(msg, mIsAudio, mIsVideo);
-  }
-  return NS_OK;
+  return MediaManager::NotifyRecordingStatusChange(window, msg, mIsAudio, mIsVideo);
 }
 
 } // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -396,16 +396,21 @@ public:
   // thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
   // from MediaManager thread.
   static MediaManager* Get();
 
   static nsIThread* GetThread() {
     return Get()->mMediaThread;
   }
 
+  static nsresult NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
+                                              const nsString& aMsg,
+                                              const bool& aIsAudio,
+                                              const bool& aIsVideo);
+
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEDIAMANAGERSERVICE
 
   MediaEngine* GetBackend(uint64_t aWindowId = 0);
   StreamListeners *GetWindowListeners(uint64_t aWindowId) {
     NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
 
--- a/dom/system/gonk/OpenFileFinder.cpp
+++ b/dom/system/gonk/OpenFileFinder.cpp
@@ -8,21 +8,24 @@
 #include "nsPrintfCString.h"
 
 #include <sys/stat.h>
 #include <errno.h>
 
 namespace mozilla {
 namespace system {
 
-OpenFileFinder::OpenFileFinder(const nsACString& aPath)
+OpenFileFinder::OpenFileFinder(const nsACString& aPath,
+                               bool aCheckIsB2gOrDescendant /* = true */)
   : mPath(aPath),
     mProcDir(nullptr),
     mFdDir(nullptr),
-    mPid(0)
+    mPid(0),
+    mMyPid(-1),
+    mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant)
 {
 }
 
 OpenFileFinder::~OpenFileFinder()
 {
   Close();
 }
 
@@ -81,17 +84,24 @@ OpenFileFinder::Next(OpenFileFinder::Inf
             continue;
           }
           nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name);
           nsCString resolvedPath;
           if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) {
             // We found an open file contained within the directory tree passed
             // into the constructor.
             FillInfo(aInfo, resolvedPath);
-            return true;
+            // If sCheckIsB2gOrDescendant is set false, the caller cares about
+            // all processes which have open files. If sCheckIsB2gOrDescendant
+            // is set false, we only care about the b2g proccess or its descendants.
+            if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) {
+              return true;
+            }
+            LOG("Ignore process(%d), not a b2g process or its descendant.",
+                aInfo->mPid);
           }
         }
         // We've checked all of the files for this pid, move onto the next one.
         mState = NEXT_PID;
         continue;
       }
       case DONE:
       default:
@@ -148,19 +158,51 @@ 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 (ppid != getpid()) {
+  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
+  // it is a descendant of b2g or not. See bug 931456.
+  while (ppid != mMyPid && ppid != 1) {
+    DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking",
+        ppid, mMyPid);
+    nsPrintfCString ppStatPath("/proc/%d/stat", ppid);
+    ReadSysFile(ppStatPath.get(), stat, statString.Length());
+    closeParen = strrchr(stat, ')');
+    if (!closeParen) {
+      return;
+    }
+    ppid = atoi(&closeParen[4]);
+  }
+  if (ppid == 1) {
+    // This is a not a b2g process.
+    DBG("Non-b2g process has open file(s)");
+    aInfo->mIsB2gOrDescendant = false;
+    return;
+  }
+  if (ppid == mMyPid) {
+    // This is a descendant of b2g.
+    DBG("Child process of chrome process has open file(s)");
+    aInfo->mIsB2gOrDescendant = true;
+  }
+
   // This looks like a content process. The comm field will be the
   // app name.
   aInfo->mAppName = aInfo->mComm;
 }
 
 bool
 OpenFileFinder::ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath)
 {
--- a/dom/system/gonk/OpenFileFinder.h
+++ b/dom/system/gonk/OpenFileFinder.h
@@ -4,16 +4,29 @@
 
 #ifndef mozilla_system_openfilefinder_h__
 #define mozilla_system_openfilefinder_h__
 
 #include "nsString.h"
 
 #include <dirent.h>
 
+#define USE_DEBUG 0
+
+#undef LOG
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "OpenFileFinder", ## args)
+#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "OpenFileFinder", ## args)
+#define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
+
+#if USE_DEBUG
+#define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
+#else
+#define DBG(args...)
+#endif
+
 namespace mozilla {
 namespace system {
 
 class OpenFileFinder
 {
 public:
   enum State
   {
@@ -24,19 +37,20 @@ public:
   class Info
   {
   public:
     nsCString mFileName;  // name of the the open file
     nsCString mAppName;   // App which has the file open (if it's a b2g app)
     pid_t     mPid;       // pid of the process which has the file open
     nsCString mComm;      // comm associated with pid
     nsCString mExe;       // executable name associated with pid
+    bool      mIsB2gOrDescendant; // this is b2g/its descendant or not
   };
 
-  OpenFileFinder(const nsACString& aPath);
+  OpenFileFinder(const nsACString& aPath, bool aCheckIsB2gOrDescendant = true);
   ~OpenFileFinder();
 
   bool First(Info* aInfo);  // Return the first open file
   bool Next(Info* aInfo);   // Return the next open file
   void Close();
 
 private:
 
@@ -47,14 +61,16 @@ private:
     return Substring(aPath, 0, mPath.Length()).Equals(mPath);
   }
 
   State     mState;   // Keeps track of what we're doing.
   nsCString mPath;    // Only report files contained within this directory tree
   DIR*      mProcDir; // Used for scanning /proc
   DIR*      mFdDir;   // Used for scanning /proc/PID/fd
   int       mPid;     // PID currently being processed
+  pid_t     mMyPid;   // PID of parent process, we assume we're running on it.
+  bool      mCheckIsB2gOrDescendant; // Do we care about non-b2g process?
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_nsvolume_h__
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2329,17 +2329,22 @@ RadioInterface.prototype = {
     if (DEBUG) this.debug("handleUSSDReceived " + JSON.stringify(ussd));
     gSystemMessenger.broadcastMessage("ussd-received", ussd);
     gMessageManager.sendMobileConnectionMessage("RIL:USSDReceived",
                                                 this.clientId, ussd);
   },
 
   handleStkProactiveCommand: function handleStkProactiveCommand(message) {
     if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
-    gSystemMessenger.broadcastMessage("icc-stkcommand", message);
+    let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
+    if (iccId) {
+      gSystemMessenger.broadcastMessage("icc-stkcommand",
+                                        {iccId: iccId,
+                                         command: message});
+    }
     gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
   },
 
   handleExitEmergencyCbMode: function handleExitEmergencyCbMode(message) {
     if (DEBUG) this.debug("handleExitEmergencyCbMode: " + JSON.stringify(message));
     gMessageManager.sendRequestResults("RIL:ExitEmergencyCbMode", message);
   },
 
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -22,16 +22,17 @@
 this.EXPORTED_SYMBOLS = ["OS"];
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
 let SharedAll = {};
 Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
 Cu.import("resource://gre/modules/Deprecated.jsm", this);
+Cu.import("resource://gre/modules/Timer.jsm", this);
 
 // Boilerplate, to simplify the transition to require()
 let LOG = SharedAll.LOG.bind(SharedAll, "Controller");
 let isTypedArray = SharedAll.isTypedArray;
 
 // The constructor for file errors.
 let SysAll = {};
 if (SharedAll.Constants.Win) {
@@ -112,16 +113,36 @@ let Scheduler = {
    */
   shutdown: false,
 
   /**
    * The latest promise returned.
    */
   latestPromise: Promise.resolve("OS.File scheduler hasn't been launched yet"),
 
+  /**
+   * A timer used to automatically shut down the worker after some time.
+   */
+  resetTimer: null,
+
+  restartTimer: function(arg) {
+    let delay;
+    try {
+      delay = Services.prefs.getIntPref("osfile.reset_worker_delay");
+    } catch(e) {
+      // Don't auto-shutdown if we don't have a delay preference set.
+      return;
+    }
+
+    if (this.resetTimer) {
+      clearTimeout(this.resetTimer);
+    }
+    this.resetTimer = setTimeout(File.resetWorker, delay);
+  },
+
   post: function post(...args) {
     if (this.shutdown) {
       LOG("OS.File is not available anymore. The following request has been rejected.", args);
       return Promise.reject(new Error("OS.File has been shut down."));
     }
     if (!worker) {
       // Either the worker has never been created or it has been reset
       worker = new PromiseWorker(
@@ -134,16 +155,22 @@ let Scheduler = {
     this.launched = true;
 
     // By convention, the last argument of any message may be an |options| object.
     let methodArgs = args[1];
     let options = methodArgs ? methodArgs[methodArgs.length - 1] : null;
     let promise = worker.post.apply(worker, args);
     return this.latestPromise = promise.then(
       function onSuccess(data) {
+        // Don't restart the timer when reseting the worker, since that will
+        // lead to an endless "resetWorker()" loop.
+        if (args[0] != "Meta_reset") {
+          Scheduler.restartTimer();
+        }
+
         // Check for duration and return result.
         if (!options) {
           return data.ok;
         }
         // Check for options.outExecutionDuration.
         if (typeof options !== "object" ||
           !("outExecutionDuration" in options)) {
           return data.ok;
@@ -162,16 +189,22 @@ let Scheduler = {
         if (typeof options.outExecutionDuration == "number") {
           options.outExecutionDuration += durationMs;
         } else {
           options.outExecutionDuration = durationMs;
         }
         return data.ok;
       },
       function onError(error) {
+        // Don't restart the timer when reseting the worker, since that will
+        // lead to an endless "resetWorker()" loop.
+        if (args[0] != "Meta_reset") {
+          Scheduler.restartTimer();
+        }
+
         // Decode any serialized error
         if (error instanceof PromiseWorker.WorkerError) {
           throw OS.File.Error.fromMsg(error.data);
         }
         // Extract something meaningful from ErrorEvent
         if (error instanceof ErrorEvent) {
           let message = error.message;
           if (message == "uncaught exception: [object StopIteration]") {