Merge B2g-inbound to Mozilla-Central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 28 Oct 2013 11:34:11 +0100
changeset 167229 085c6286911f5a0537c96ccb7206ad9fedb5fa29
parent 167210 4646259ab62d9afb1aca0d51aabf1c55b48388e3 (current diff)
parent 167228 4aacf3bcff3cb396aa80467ffa09d4aface30183 (diff)
child 167230 c5e4bb7db0b9d9ccddeb6088014500b65933094b
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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 Mozilla-Central
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "c09f78f6bdd9c8c3cea3943f8a6fe96c760d7de7", 
+    "revision": "d2632e2be46de3f4fa9106ada595e33e317aaaa2", 
     "repo_path": "/integration/gaia-central"
 }
--- a/dom/bluetooth/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/BluetoothA2dpManager.cpp
@@ -202,33 +202,33 @@ BluetoothA2dpManager::OnConnect(const ns
   MOZ_ASSERT(NS_IsMainThread());
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnConnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnConnect(aErrorStr);
 }
 
 void
 BluetoothA2dpManager::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnDisconnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnDisconnect(aErrorStr);
 }
 
 /* HandleSinkPropertyChanged update sink state in A2dp
  *
  * Possible values: "disconnected", "disconnecting",
  *                  "connecting", "connected",
  *                  "playing"
  *
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -318,17 +318,17 @@ bool
 Call::IsActive()
 {
   return (mState == nsITelephonyProvider::CALL_STATE_CONNECTED);
 }
 
 /**
  *  BluetoothHfpManager
  */
-BluetoothHfpManager::BluetoothHfpManager()
+BluetoothHfpManager::BluetoothHfpManager() : mController(nullptr)
 {
   Reset();
 }
 
 void
 BluetoothHfpManager::ResetCallArray()
 {
   mCurrentCallArray.Clear();
@@ -362,18 +362,16 @@ BluetoothHfpManager::Reset()
 
   // We disable BSIR by default as it requires OEM implement BT SCO + SPEAKER
   // output audio path in audio driver. OEM can enable BSIR by setting
   // mBSIR=true here.
   //
   // Please see Bug 878728 for more information.
   mBSIR = false;
 
-  mController = nullptr;
-
   ResetCallArray();
 }
 
 bool
 BluetoothHfpManager::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -1091,17 +1089,16 @@ BluetoothHfpManager::Disconnect(Bluetoot
     }
     return;
   }
 
   MOZ_ASSERT(!mController);
 
   mController = aController;
   mSocket->Disconnect();
-  mSocket = nullptr;
 }
 
 void
 BluetoothHfpManager::SendCCWA(const nsAString& aNumber, int aType)
 {
   if (mCCWA) {
     nsAutoCString ccwaMsg("+CCWA: \"");
     ccwaMsg.Append(NS_ConvertUTF16toUTF8(aNumber));
@@ -1648,16 +1645,18 @@ BluetoothHfpManager::OnGetServiceChannel
     } else if (NS_FAILED(bs->GetServiceChannel(aDeviceAddress,
                                                hspUuid, this))) {
       OnConnect(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     }
 
     return;
   }
 
+  MOZ_ASSERT(mSocket);
+
   if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) {
     OnConnect(NS_LITERAL_STRING("SocketConnectionError"));
   }
 }
 
 void
 BluetoothHfpManager::OnScoConnectSuccess()
 {
@@ -1810,18 +1809,18 @@ BluetoothHfpManager::OnConnect(const nsA
   }
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnConnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnConnect(aErrorStr);
 }
 
 void
 BluetoothHfpManager::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Start listening
@@ -1829,13 +1828,13 @@ BluetoothHfpManager::OnDisconnect(const 
   Listen();
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnDisconnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnDisconnect(aErrorStr);
 }
 
 NS_IMPL_ISUPPORTS1(BluetoothHfpManager, nsIObserver)
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -176,17 +176,16 @@ private:
   bool mReceiveVgsFlag;
   bool mDialingRequestProcessed;
   nsString mDeviceAddress;
   nsString mMsisdn;
   nsString mOperatorName;
 
   nsTArray<Call> mCurrentCallArray;
   nsAutoPtr<BluetoothRilListener> mListener;
-  nsRefPtr<BluetoothReplyRunnable> mRunnable;
   nsRefPtr<BluetoothProfileController> mController;
   nsRefPtr<BluetoothReplyRunnable> mScoRunnable;
 
   // 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, mHandsfreeSocket and mHeadsetSocket must be null (and
   // vice versa).
   nsRefPtr<BluetoothSocket> mSocket;
--- a/dom/bluetooth/BluetoothHidManager.cpp
+++ b/dom/bluetooth/BluetoothHidManager.cpp
@@ -162,33 +162,33 @@ BluetoothHidManager::OnConnect(const nsA
   MOZ_ASSERT(NS_IsMainThread());
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnConnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnConnect(aErrorStr);
 }
 
 void
 BluetoothHidManager::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnDisconnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnDisconnect(aErrorStr);
 }
 
 bool
 BluetoothHidManager::IsConnected()
 {
   return mConnected;
 }
 
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ b/dom/bluetooth/BluetoothOppManager.cpp
@@ -286,17 +286,16 @@ BluetoothOppManager::Disconnect(Bluetoot
     }
     return;
   }
 
   MOZ_ASSERT(!mController);
 
   mController = aController;
   mSocket->Disconnect();
-  mSocket = nullptr;
 }
 
 void
 BluetoothOppManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   sInShutdown = true;
   Disconnect(nullptr);
@@ -1478,29 +1477,29 @@ BluetoothOppManager::OnConnect(const nsA
   }
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnConnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnConnect(aErrorStr);
 }
 
 void
 BluetoothOppManager::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mSocket = nullptr;
   Listen();
 
   /**
    * On the one hand, notify the controller that we've done for outbound
    * connections. On the other hand, we do nothing for inbound connections.
    */
   NS_ENSURE_TRUE_VOID(mController);
 
-  mController->OnDisconnect(aErrorStr);
-  mController = nullptr;
+  nsRefPtr<BluetoothProfileController> controller = mController.forget();
+  controller->OnDisconnect(aErrorStr);
 }
--- a/dom/bluetooth/BluetoothOppManager.h
+++ b/dom/bluetooth/BluetoothOppManager.h
@@ -16,17 +16,16 @@
 #include "nsCOMArray.h"
 
 class nsIOutputStream;
 class nsIInputStream;
 class nsIVolumeMountLock;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
-class BluetoothReplyRunnable;
 class BluetoothSocket;
 class ObexHeaderSet;
 
 class BluetoothOppManager : public BluetoothSocketObserver
                           , public BluetoothProfileManagerBase
 {
 public:
   NS_DECL_ISUPPORTS
@@ -213,17 +212,16 @@ private:
   /**
    * 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<BluetoothReplyRunnable> mRunnable;
   nsRefPtr<BluetoothProfileController> mController;
   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;
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -21,40 +21,58 @@ USING_BLUETOOTH_NAMESPACE
   do {                                                \
     nsCString name;                                   \
     mgr->GetName(name);                               \
     BT_LOGR("%s: [%s] %s", __FUNCTION__, name.get(),  \
       nsPrintfCString(args).get());                   \
   } while(0)
 
 BluetoothProfileController::BluetoothProfileController(
+                                   bool aConnect,
                                    const nsAString& aDeviceAddress,
                                    BluetoothReplyRunnable* aRunnable,
-                                   BluetoothProfileControllerCallback aCallback)
-  : mCallback(aCallback)
+                                   BluetoothProfileControllerCallback aCallback,
+                                   uint16_t aServiceUuid,
+                                   uint32_t aCod)
+  : mConnect(aConnect)
   , mDeviceAddress(aDeviceAddress)
   , mRunnable(aRunnable)
+  , mCallback(aCallback)
   , mSuccess(false)
+  , mProfilesIndex(-1)
 {
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
   MOZ_ASSERT(aRunnable);
   MOZ_ASSERT(aCallback);
 
-  mProfilesIndex = -1;
   mProfiles.Clear();
+
+  /**
+   * If the service uuid is not specified, either connect multiple profiles
+   * based on Cod, or disconnect all connected profiles.
+   */
+  if (!aServiceUuid) {
+    mTarget.cod = aCod;
+    SetupProfiles(false);
+  } else {
+    BluetoothServiceClass serviceClass =
+      BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
+    mTarget.service = serviceClass;
+    SetupProfiles(true);
+  }
 }
 
 BluetoothProfileController::~BluetoothProfileController()
 {
   mProfiles.Clear();
   mRunnable = nullptr;
   mCallback = nullptr;
 }
 
-bool
+void
 BluetoothProfileController::AddProfileWithServiceClass(
                                                    BluetoothServiceClass aClass)
 {
   BluetoothProfileManagerBase* profile;
   switch (aClass) {
     case BluetoothServiceClass::HANDSFREE:
     case BluetoothServiceClass::HEADSET:
       profile = BluetoothHfpManager::Get();
@@ -67,67 +85,76 @@ BluetoothProfileController::AddProfileWi
       break;
     case BluetoothServiceClass::HID:
       profile = BluetoothHidManager::Get();
       break;
     default:
       DispatchBluetoothReply(mRunnable, BluetoothValue(),
                              NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
       mCallback();
-      return false;
+      return;
   }
 
-  return AddProfile(profile);
+  AddProfile(profile);
 }
 
-bool
+void
 BluetoothProfileController::AddProfile(BluetoothProfileManagerBase* aProfile,
                                        bool aCheckConnected)
 {
   if (!aProfile) {
     DispatchBluetoothReply(mRunnable, BluetoothValue(),
                            NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
     mCallback();
-    return false;
+    return;
   }
 
   if (aCheckConnected && !aProfile->IsConnected()) {
-    return false;
+    BT_WARNING("The profile is not connected.");
+    return;
   }
 
   mProfiles.AppendElement(aProfile);
-  return true;
 }
 
 void
-BluetoothProfileController::Connect(BluetoothServiceClass aClass)
+BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  NS_ENSURE_TRUE_VOID(AddProfileWithServiceClass(aClass));
-
-  ConnectNext();
-}
+  /**
+   * When a service class is assigned, only its corresponding profile is put
+   * into array.
+   */
+  if (aAssignServiceClass) {
+    AddProfileWithServiceClass(mTarget.service);
+    return;
+  }
 
-void
-BluetoothProfileController::Connect(uint32_t aCod)
-{
-  MOZ_ASSERT(NS_IsMainThread());
+  // For a disconnect request, all connected profiles are put into array.
+  if (!mConnect) {
+    AddProfile(BluetoothHidManager::Get(), true);
+    AddProfile(BluetoothOppManager::Get(), true);
+    AddProfile(BluetoothA2dpManager::Get(), true);
+    AddProfile(BluetoothHfpManager::Get(), true);
+    return;
+  }
 
-  // Put multiple profiles into array and connect to all of them sequencely
-  bool hasAudio = HAS_AUDIO(aCod);
-  bool hasObjectTransfer = HAS_OBJECT_TRANSFER(aCod);
-  bool hasRendering = HAS_RENDERING(aCod);
-  bool isPeripheral = IS_PERIPHERAL(aCod);
+  /**
+   * For a connect request, put multiple profiles into array and connect to
+   * all of them sequencely.
+   */
+  bool hasAudio = HAS_AUDIO(mTarget.cod);
+  bool hasObjectTransfer = HAS_OBJECT_TRANSFER(mTarget.cod);
+  bool hasRendering = HAS_RENDERING(mTarget.cod);
+  bool isPeripheral = IS_PERIPHERAL(mTarget.cod);
 
   NS_ENSURE_TRUE_VOID(hasAudio || hasObjectTransfer ||
                       hasRendering || isPeripheral);
 
-  mCod = aCod;
-
   /**
    * Connect to HFP/HSP first. Then, connect A2DP if Rendering bit is set.
    * It's almost impossible to send file to a remote device which is an Audio
    * device or a Rendering device, so we won't connect OPP in that case.
    */
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
   }
@@ -135,30 +162,50 @@ BluetoothProfileController::Connect(uint
     AddProfile(BluetoothA2dpManager::Get());
   }
   if (hasObjectTransfer && !hasAudio && !hasRendering) {
     AddProfile(BluetoothOppManager::Get());
   }
   if (isPeripheral) {
     AddProfile(BluetoothHidManager::Get());
   }
-
-  ConnectNext();
 }
 
 void
-BluetoothProfileController::ConnectNext()
+BluetoothProfileController::Start()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mDeviceAddress.IsEmpty());
+  MOZ_ASSERT(mProfilesIndex == -1);
+
+  ++mProfilesIndex;
+  BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
+
+  if (mConnect) {
+    mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+  } else {
+    mProfiles[mProfilesIndex]->Disconnect(this);
+  }
+}
+
+void
+BluetoothProfileController::Next()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mDeviceAddress.IsEmpty());
+  MOZ_ASSERT(mProfilesIndex < mProfiles.Length());
 
   if (++mProfilesIndex < mProfiles.Length()) {
-    MOZ_ASSERT(!mDeviceAddress.IsEmpty());
     BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
 
-    mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+    if (mConnect) {
+      mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
+    } else {
+      mProfiles[mProfilesIndex]->Disconnect(this);
+    }
     return;
   }
 
   MOZ_ASSERT(mRunnable && mCallback);
 
   // The action has been completed, so the dom request is replied and then
   // the callback is invoked
   if (mSuccess) {
@@ -178,72 +225,26 @@ BluetoothProfileController::OnConnect(co
     NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
-  ConnectNext();
-}
-
-void
-BluetoothProfileController::Disconnect(BluetoothServiceClass aClass)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (aClass != BluetoothServiceClass::UNKNOWN) {
-    NS_ENSURE_TRUE_VOID(AddProfileWithServiceClass(aClass));
-
-    DisconnectNext();
-    return;
-  }
-
-  // Put all connected profiles into array and disconnect all of them
-  AddProfile(BluetoothHidManager::Get(), true);
-  AddProfile(BluetoothOppManager::Get(), true);
-  AddProfile(BluetoothA2dpManager::Get(), true);
-  AddProfile(BluetoothHfpManager::Get(), true);
-
-  DisconnectNext();
-}
-
-void
-BluetoothProfileController::DisconnectNext()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (++mProfilesIndex < mProfiles.Length()) {
-    BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
-
-    mProfiles[mProfilesIndex]->Disconnect(this);
-    return;
-  }
-
-  MOZ_ASSERT(mRunnable && mCallback);
-
-  // The action has been completed, so the dom request is replied and then
-  // the callback is invoked
-  if (mSuccess) {
-    DispatchBluetoothReply(mRunnable, BluetoothValue(true), EmptyString());
-  } else {
-    DispatchBluetoothReply(mRunnable, BluetoothValue(),
-                           NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
-  }
-  mCallback();
+  Next();
 }
 
 void
 BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
     NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
-  DisconnectNext();
+  Next();
 }
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -48,54 +48,83 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothProfileManagerBase;
 class BluetoothReplyRunnable;
 typedef void (*BluetoothProfileControllerCallback)();
 
 class BluetoothProfileController : public RefCounted<BluetoothProfileController>
 {
 public:
-  BluetoothProfileController(const nsAString& aDeviceAddress,
+  /**
+   * @param aConnect:       If it's a connect request, the value should be set
+   *                        to true. For disconnect request, set it to false.
+   * @param aDeviceAddress: The address of remote device.
+   * @param aRunnable:      Once the controller has done, the runnable will be
+   *                        replied. When all connection/disconnection attemps
+   *                        have failed, an error is fired. In other words,
+   *                        reply a success if any attemp successes.
+   * @param aCallback:      The callback will be invoked after the runnable is
+   *                        replied.
+   * @param aServiceUuid:   Connect/Disconnect to the specified profile. Please
+   *                        see enum BluetoothServiceClass for valid value.
+   * @param aCod:           If aServiceUuid is not assigned, i.e. the value is
+   *                        0, the controller connect multiple profiles based on
+   *                        aCod or disconnect all connected profiles.
+   */
+  BluetoothProfileController(bool aConnect,
+                             const nsAString& aDeviceAddress,
                              BluetoothReplyRunnable* aRunnable,
-                             BluetoothProfileControllerCallback aCallback);
+                             BluetoothProfileControllerCallback aCallback,
+                             uint16_t aServiceUuid,
+                             uint32_t aCod = 0);
   ~BluetoothProfileController();
 
-  // Connect to a specific service UUID.
-  void Connect(BluetoothServiceClass aClass);
-
-  // Based on the CoD, connect to multiple profiles sequencely.
-  void Connect(uint32_t aCod);
+  /**
+   * The controller starts connecting/disconnecting profiles one by one
+   * according to the order in array mProfiles.
+   */
+  void Start();
 
   /**
-   * If aClass is assigned with specific service class, disconnect its
-   * corresponding profile. Otherwise, disconnect all profiles connected to the
-   * remote device.
+   * It is invoked after a profile has tried to establish the connection.
+   * An error string is returned when it fails.
    */
-  void Disconnect(BluetoothServiceClass aClass = BluetoothServiceClass::UNKNOWN);
+  void OnConnect(const nsAString& aErrorStr);
 
-  void OnConnect(const nsAString& aErrorStr);
+  /**
+   * It is invoked after a profile has tried to drop the connection.
+   * An error string is returned when it fails.
+   */
   void OnDisconnect(const nsAString& aErrorStr);
 
-  uint32_t GetCod() const
-  {
-    return mCod;
-  }
+private:
+  // Setup data member mProfiles
+  void SetupProfiles(bool aAssignServiceClass);
+
+  // Add profiles into array with/without checking connection status
+  void AddProfile(BluetoothProfileManagerBase* aProfile,
+                  bool aCheckConnected = false);
 
-private:
-  void ConnectNext();
-  void DisconnectNext();
-  bool AddProfile(BluetoothProfileManagerBase* aProfile,
-                  bool aCheckConnected = false);
-  bool AddProfileWithServiceClass(BluetoothServiceClass aClass);
+  // Add specified profile into array
+  void AddProfileWithServiceClass(BluetoothServiceClass aClass);
+
+  // Connect/Disconnect next profile in the array
+  void Next();
 
+  const bool mConnect;
+  nsString mDeviceAddress;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+  BluetoothProfileControllerCallback mCallback;
+
+  bool mSuccess;
   int8_t mProfilesIndex;
   nsTArray<BluetoothProfileManagerBase*> mProfiles;
 
-  BluetoothProfileControllerCallback mCallback;
-  uint32_t mCod;
-  nsString mDeviceAddress;
-  nsRefPtr<BluetoothReplyRunnable> mRunnable;
-  bool mSuccess;
+  // Either CoD or BluetoothServiceClass is assigned.
+  union {
+    uint32_t cod;
+    BluetoothServiceClass service;
+  } mTarget;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/BluetoothServiceBluedroid.cpp
@@ -12,42 +12,184 @@
 ** 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.
 */
 
 #include "BluetoothServiceBluedroid.h"
+
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
+
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/UnixSocket.h"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
+/**
+ *  Classes only used in this file
+ */
+class DistributeBluetoothSignalTask : public nsRunnable {
+public:
+  DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
+    mSignal(aSignal)
+  {
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    BluetoothService* bs = BluetoothService::Get();
+    bs->DistributeSignal(mSignal);
+
+    return NS_OK;
+  }
+
+private:
+  BluetoothSignal mSignal;
+};
+
+/**
+ *  Static variables
+ */
+
+static bluetooth_device_t* sBtDevice;
+static const bt_interface_t* sBtInterface;
+static bool sIsBtEnabled = false;
+
+/**
+ *  Static callback functions
+ */
+static void
+AdapterStateChangeCallback(bt_state_t aStatus)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  BT_LOGD("Enter: %s, BT_STATE:%d", __FUNCTION__, aStatus);
+  nsAutoString signalName;
+  if (aStatus == BT_STATE_ON) {
+    sIsBtEnabled = true;
+    signalName = NS_LITERAL_STRING("AdapterAdded");
+  } else {
+    sIsBtEnabled = false;
+    signalName = NS_LITERAL_STRING("Disabled");
+  }
+
+  BluetoothSignal signal(signalName, NS_LITERAL_STRING(KEY_MANAGER), BluetoothValue(true));
+  nsRefPtr<DistributeBluetoothSignalTask>
+    t = new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    NS_WARNING("Failed to dispatch to main thread!");
+  }
+}
+
+bt_callbacks_t sBluetoothCallbacks = {
+  sizeof(sBluetoothCallbacks),
+  AdapterStateChangeCallback
+};
+
+/**
+ *  Static functions
+ */
+static bool
+EnsureBluetoothHalLoad()
+{
+  hw_module_t* module;
+  hw_device_t* device;
+  int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+  if (err != 0) {
+    BT_LOGR("Error: %s ", strerror(err));
+    return false;
+  }
+  module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+  sBtDevice = (bluetooth_device_t *)device;
+  sBtInterface = sBtDevice->get_bluetooth_interface();
+  BT_LOGD("Bluetooth HAL loaded");
+
+  return true;
+}
+
+static nsresult
+StartStopGonkBluetooth(bool aShouldEnable)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  static bool sIsBtInterfaceInitialized = false;
+
+  if (!EnsureBluetoothHalLoad()) {
+    BT_LOGR("Failed to load bluedroid library.\n");
+    return NS_ERROR_FAILURE;
+  }
+
+  if (sIsBtEnabled == aShouldEnable)
+    return NS_OK;
+
+  if (sBtInterface && !sIsBtInterfaceInitialized) {
+    int ret = sBtInterface->init(&sBluetoothCallbacks);
+    if (ret != BT_STATUS_SUCCESS) {
+      BT_LOGR("Error while setting the callbacks %s", __FUNCTION__);
+      sBtInterface = nullptr;
+      return NS_ERROR_FAILURE;
+    }
+    sIsBtInterfaceInitialized = true;
+  }
+  int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable();
+
+  return (ret == BT_STATUS_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+/**
+ *  Member functions
+ */
 nsresult
 BluetoothServiceBluedroid::StartInternal()
 {
-  return NS_OK;
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  nsresult ret = StartStopGonkBluetooth(true);
+  if (NS_FAILED(ret)) {
+    BT_LOGR("Error: %s", __FUNCTION__);
+  }
+
+  return ret;
 }
 
 nsresult
 BluetoothServiceBluedroid::StopInternal()
 {
-  return NS_OK;
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  nsresult ret = StartStopGonkBluetooth(false);
+  if (NS_FAILED(ret)) {
+    BT_LOGR("Error: %s", __FUNCTION__);
+  }
+
+  return ret;
 }
 
 bool
 BluetoothServiceBluedroid::IsEnabledInternal()
 {
-  return true;
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  if (!EnsureBluetoothHalLoad()) {
+    NS_ERROR("Failed to load bluedroid library.\n");
+    return false;
+  }
+
+  return sIsBtEnabled;
 }
 
 nsresult
 BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   return NS_OK;
 }
--- a/dom/bluetooth/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/BluetoothServiceBluedroid.h
@@ -1,9 +1,9 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*-
+/* -*- 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_bluetoothservicebluedroid_h__
 #define mozilla_dom_bluetooth_bluetoothservicebluedroid_h__
 
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -172,17 +172,17 @@ static const char* sBluetoothDBusSignals
  */
 static nsRefPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* >* sPairingReqTable;
 static nsTArray<uint32_t> sAuthorizedServiceClass;
 static nsString sAdapterPath;
 static Atomic<int32_t> sIsPairing(0);
 static int sConnectedDeviceCount = 0;
 static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
-StaticRefPtr<BluetoothProfileController> sController;
+static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
 
 typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 typedef bool (*FilterFunc)(const BluetoothValue&);
 
 BluetoothDBusService::BluetoothDBusService()
 {
   sStopBluetoothMonitor = new Monitor("BluetoothService.sStopBluetoothMonitor");
 }
@@ -1747,16 +1747,17 @@ BluetoothDBusService::StopInternal()
   // unref stored DBusMessages before clear the hashtable
   sPairingReqTable->EnumerateRead(UnrefDBusMessages, nullptr);
   sPairingReqTable->Clear();
 
   sIsPairing = 0;
   sConnectedDeviceCount = 0;
 
   sAuthorizedServiceClass.Clear();
+  sControllerArray.Clear();
 
   StopDBus();
   return NS_OK;
 }
 
 bool
 BluetoothDBusService::IsEnabledInternal()
 {
@@ -2554,74 +2555,65 @@ BluetoothDBusService::SetPairingConfirma
   dbus_message_unref(reply);
 
   sPairingReqTable->Remove(aDeviceAddress);
   DispatchBluetoothReply(aRunnable, v, errorStr);
   return result;
 }
 
 static void
-DestroyBluetoothProfileController()
+NextBluetoothProfileController()
+{
+  sControllerArray[0] = nullptr;
+  sControllerArray.RemoveElementAt(0);
+
+  if (!sControllerArray.IsEmpty()) {
+    sControllerArray[0]->Start();
+  }
+}
+
+static void
+ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress,
+                  BluetoothReplyRunnable* aRunnable,
+                  uint16_t aServiceUuid, uint32_t aCod = 0)
 {
-  sController = nullptr;
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
+
+  BluetoothProfileController* controller =
+    new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable,
+                                   NextBluetoothProfileController,
+                                   aServiceUuid, aCod);
+  sControllerArray.AppendElement(controller);
+
+  /**
+   * If the request is the first element of the quene, start from here. Note
+   * that other request is pushed into the quene and is popped out after the
+   * first one is completed. See NextBluetoothProfileController() for details.
+   */
+  if (sControllerArray.Length() == 1) {
+    sControllerArray[0]->Start();
+  }
 }
 
 void
 BluetoothDBusService::Connect(const nsAString& aDeviceAddress,
                               uint32_t aCod,
                               uint16_t aServiceUuid,
                               BluetoothReplyRunnable* aRunnable)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aRunnable);
-
-  BluetoothServiceClass serviceClass =
-    BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
-
-  if (sController) {
-    DispatchBluetoothReply(aRunnable, BluetoothValue(),
-                           NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    return;
-  }
-
-  sController =
-    new BluetoothProfileController(aDeviceAddress, aRunnable,
-                                   DestroyBluetoothProfileController);
-  if (aServiceUuid) {
-    sController->Connect(serviceClass);
-  } else {
-    sController->Connect(aCod);
-  }
+  ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod);
 }
 
 void
 BluetoothDBusService::Disconnect(const nsAString& aDeviceAddress,
                                  uint16_t aServiceUuid,
                                  BluetoothReplyRunnable* aRunnable)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aRunnable);
-
-  BluetoothServiceClass serviceClass =
-    BluetoothUuidHelper::GetBluetoothServiceClass(aServiceUuid);
-
-  if (sController) {
-    DispatchBluetoothReply(aRunnable, BluetoothValue(),
-                           NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
-    return;
-  }
-
-  sController =
-    new BluetoothProfileController(aDeviceAddress, aRunnable,
-                                   DestroyBluetoothProfileController);
-  if (aServiceUuid) {
-    sController->Disconnect(serviceClass);
-  } else {
-    sController->Disconnect();
-  }
+  ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid);
 }
 
 bool
 BluetoothDBusService::IsConnected(const uint16_t aServiceUuid)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothProfileManagerBase* profile =
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1758,22 +1758,23 @@ RadioInterface.prototype = {
       receiver:       aDomMessage.receiver,
       body:           aDomMessage.body,
       messageClass:   aDomMessage.messageClass,
       timestamp:      aDomMessage.timestamp,
       read:           aDomMessage.read
     });
   },
 
-  // The following attributes/functions are used for acquiring the CPU wake
-  // lock when the RIL handles the received SMS. Note that we need a timer to
-  // bound the lock's life cycle to avoid exhausting the battery.
+  // The following attributes/functions are used for acquiring/releasing the
+  // CPU wake lock when the RIL handles the received SMS. Note that we need
+  // a timer to bound the lock's life cycle to avoid exhausting the battery.
   _smsHandledWakeLock: null,
   _smsHandledWakeLockTimer: null,
-  _cancelSmsHandledWakeLockTimer: function _cancelSmsHandledWakeLockTimer() {
+
+  _releaseSmsHandledWakeLock: function _releaseSmsHandledWakeLock() {
     if (DEBUG) this.debug("Releasing the CPU wake lock for handling SMS.");
     if (this._smsHandledWakeLockTimer) {
       this._smsHandledWakeLockTimer.cancel();
     }
     if (this._smsHandledWakeLock) {
       this._smsHandledWakeLock.unlock();
       this._smsHandledWakeLock = null;
     }
@@ -1791,17 +1792,17 @@ RadioInterface.prototype = {
     }
     if (!this._smsHandledWakeLockTimer) {
       if (DEBUG) this.debug("Creating a timer for releasing the CPU wake lock.");
       this._smsHandledWakeLockTimer =
         Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     }
     if (DEBUG) this.debug("Setting the timer for releasing the CPU wake lock.");
     this._smsHandledWakeLockTimer
-        .initWithCallback(this._cancelSmsHandledWakeLockTimer.bind(this),
+        .initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
                           SMS_HANDLED_WAKELOCK_TIMEOUT,
                           Ci.nsITimer.TYPE_ONE_SHOT);
 
     // FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
     if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
       message.fullData = new Uint8Array(message.fullData);
     }
 
@@ -2169,18 +2170,18 @@ RadioInterface.prototype = {
           try {
             value = Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
           } catch(e) {}
           this.workerMessenger.send("setCellBroadcastDisabled",
                                     { disabled: value });
         }
         break;
       case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
-        // Cancel the timer of the CPU wake lock for handling the received SMS.
-        this._cancelSmsHandledWakeLockTimer();
+        // Release the CPU wake lock for handling the received SMS.
+        this._releaseSmsHandledWakeLock();
 
         // Shutdown all RIL network interfaces
         for each (let apnSetting in this.apnSettings.byAPN) {
           if (apnSetting.iface) {
             apnSetting.iface.shutdown();
           }
         }
         Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ b/dom/telephony/gonk/TelephonyProvider.js
@@ -102,19 +102,40 @@ TelephonyProvider.prototype = {
                                     classDescription: "TelephonyProvider",
                                     interfaces: [Ci.nsITelephonyProvider,
                                                  Ci.nsIGonkTelephonyProvider],
                                     flags: Ci.nsIClassInfo.SINGLETON}),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyProvider,
                                          Ci.nsIGonkTelephonyProvider,
                                          Ci.nsIObserver]),
 
+  // The following attributes/functions are used for acquiring/releasing the
+  // CPU wake lock when the RIL handles the incoming call. Note that we need
+  // a timer to bound the lock's life cycle to avoid exhausting the battery.
   _callRingWakeLock: null,
   _callRingWakeLockTimer: null,
-  _cancelCallRingWakeLockTimer: function _cancelCallRingWakeLockTimer() {
+
+  _acquireCallRingWakeLock: function _acquireCallRingWakeLock() {
+    if (!this._callRingWakeLock) {
+      if (DEBUG) debug("Acquiring a CPU wake lock for handling incoming call.");
+      this._callRingWakeLock = gPowerManagerService.newWakeLock("cpu");
+    }
+    if (!this._callRingWakeLockTimer) {
+      if (DEBUG) debug("Creating a timer for releasing the CPU wake lock.");
+      this._callRingWakeLockTimer =
+        Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    }
+    if (DEBUG) debug("Setting the timer for releasing the CPU wake lock.");
+    this._callRingWakeLockTimer
+        .initWithCallback(this._releaseCallRingWakeLock.bind(this),
+                          CALL_WAKELOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
+  _releaseCallRingWakeLock: function _releaseCallRingWakeLock() {
+    if (DEBUG) debug("Releasing the CPU wake lock for handling incoming call.");
     if (this._callRingWakeLockTimer) {
       this._callRingWakeLockTimer.cancel();
     }
     if (this._callRingWakeLock) {
       this._callRingWakeLock.unlock();
       this._callRingWakeLock = null;
     }
   },
@@ -460,26 +481,19 @@ TelephonyProvider.prototype = {
 
   /**
    * Handle an incoming call.
    *
    * Not much is known about this call at this point, but it's enough
    * to start bringing up the Phone app already.
    */
   notifyCallRing: function notifyCallRing() {
-    if (!this._callRingWakeLock) {
-      this._callRingWakeLock = gPowerManagerService.newWakeLock("cpu");
-    }
-    if (!this._callRingWakeLockTimer) {
-      this._callRingWakeLockTimer =
-        Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    }
-    this._callRingWakeLockTimer
-        .initWithCallback(this._cancelCallRingWakeLockTimer.bind(this),
-                          CALL_WAKELOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
+    // We need to acquire a CPU wake lock to avoid the system falling into
+    // the sleep mode when the RIL handles the incoming call.
+    this._acquireCallRingWakeLock();
 
     gSystemMessenger.broadcastMessage("telephony-new-call", {});
   },
 
   /**
    * Handle call state changes by updating our current state and the audio
    * system.
    */
@@ -498,16 +512,20 @@ TelephonyProvider.prototype = {
                                                   aCall.number,
                                                   aCall.isActive,
                                                   aCall.isOutgoing,
                                                   aCall.isEmergency,
                                                   aCall.isConference]);
   },
 
   notifyCdmaCallWaiting: function notifyCdmaCallWaiting(aNumber) {
+    // We need to acquire a CPU wake lock to avoid the system falling into
+    // the sleep mode when the RIL handles the incoming call.
+    this._acquireCallRingWakeLock();
+
     this._notifyAllListeners("notifyCdmaCallWaiting", [aNumber]);
   },
 
   notifySupplementaryService: function notifySupplementaryService(aCallIndex,
                                                                   aNotification) {
     let notification = this._convertRILSuppSvcNotification(aNotification);
     this._notifyAllListeners("supplementaryServiceNotification",
                              [aCallIndex, notification]);
@@ -531,18 +549,18 @@ TelephonyProvider.prototype = {
         if (aData === kPrefRilDebuggingEnabled) {
           this._updateDebugFlag();
 	} else if (aData === kPrefDefaultServiceId) {
           this.defaultServiceId = this._getDefaultServiceId();
         }
         break;
 
       case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
-        // Cancel the timer for the call-ring wake lock.
-        this._cancelCallRingWakeLockTimer();
+        // Release the CPU wake lock for handling the incoming call.
+        this._releaseCallRingWakeLock();
 
         Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
         break;
     }
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TelephonyProvider]);