Bug 1083708: Handle non-existant Bluetooth profile interfaces correctly, r=shawnjohnjr
authorThomas Zimmermann <tdz@users.sourceforge.net>
Thu, 16 Oct 2014 16:40:49 +0200
changeset 210723 3dba8eb39239593e0ab089114096d5c51e7f1463
parent 210722 16a6ed2425550ca85aa3d8c6091a7ae9e30a24ca
child 210767 cc7fc5918561b47d77404e4beffa31ede57a9522
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersshawnjohnjr
bugs1083708
milestone36.0a1
Bug 1083708: Handle non-existant Bluetooth profile interfaces correctly, r=shawnjohnjr Bluetooth profile managers just return an error if a profile interface is not available. Doing so breaks the initialization and cleanup routines. This patch changes the profile managers to still report an error, but signal progress to the given result runnable.
dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -188,31 +188,71 @@ public:
     BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
     sBtAvrcpInterface->Init(a2dpManager, new InitAvrcpResultHandler(mRes));
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
 
+class OnErrorProfileResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                      nsresult aRv)
+  : mRes(aRes)
+  , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->OnError(mRv);
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
 /*
  * This function will be only called when Bluetooth is turning on.
  * It is important to register a2dp callbacks before enable() gets called.
  * It is required to register a2dp callbacks before a2dp media task
  * starts up.
  */
 // static
 void
 BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
-  NS_ENSURE_TRUE_VOID(btInf);
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no HFP interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
+    }
+    return;
+  }
 
   sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
-  NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
+  if (NS_WARN_IF(!sBtA2dpInterface)) {
+    // If there's no HFP interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
+    }
+    return;
+  }
 
   BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
   sBtA2dpInterface->Init(a2dpManager, new InitA2dpResultHandler(aRes));
 }
 
 BluetoothA2dpManager::~BluetoothA2dpManager()
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
@@ -336,16 +376,21 @@ public:
     }
   }
 
   void Cleanup() MOZ_OVERRIDE
   {
     sBtA2dpInterface = nullptr;
     if (sBtAvrcpInterface) {
       sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else if (mRes) {
+      /* Not all backends support AVRCP. If it's not available
+       * we signal success from here.
+       */
+      mRes->Deinit();
     }
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
 
 class CleanupA2dpResultHandlerRunnable MOZ_FINAL : public nsRunnable
@@ -355,16 +400,21 @@ public:
   : mRes(aRes)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
   {
     sBtA2dpInterface = nullptr;
     if (sBtAvrcpInterface) {
       sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else if (mRes) {
+      /* Not all backends support AVRCP. If it's not available
+       * we signal success from here.
+       */
+      mRes->Deinit();
     }
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -324,26 +324,66 @@ public:
     mRes->RunInit();
     return NS_OK;
   }
 
 private:
   nsRefPtr<CleanupInitResultHandler> mRes;
 };
 
+class OnErrorProfileResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                      nsresult aRv)
+  : mRes(aRes)
+  , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->OnError(mRv);
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
 // static
 void
 BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
-  NS_ENSURE_TRUE_VOID(btInf);
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no backend interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
+    }
+    return;
+  }
 
   BluetoothHandsfreeInterface *interface =
     btInf->GetBluetoothHandsfreeInterface();
-  NS_ENSURE_TRUE_VOID(interface);
+  if (NS_WARN_IF(!interface)) {
+    // If there's no HFP interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
+    }
+    return;
+  }
 
   nsRefPtr<CleanupInitResultHandler> res =
     new CleanupInitResultHandler(interface, aRes);
 
   if (sBluetoothHfpInterface) {
     // Cleanup an initialized HFP before initializing again.
     sBluetoothHfpInterface->Cleanup(res);
   } else {
--- a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp
@@ -192,40 +192,68 @@ public:
     BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
     sBtAvrcpInterface->Init(a2dpManager, new InitAvrcpResultHandler(mRes));
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
 
+class OnErrorProfileResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                      nsresult aRv)
+  : mRes(aRes)
+  , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->OnError(mRv);
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
 /*
  * This function will be only called when Bluetooth is turning on.
  * It is important to register a2dp callbacks before enable() gets called.
  * It is required to register a2dp callbacks before a2dp media task
  * starts up.
  */
 // static
 void
 BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
-  if (!btInf) {
-    BT_LOGR("Error: Bluetooth interface not available");
-    if (aRes) {
-      aRes->OnError(NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no backend interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
     }
     return;
   }
 
   sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
-  if (!sBtA2dpInterface) {
-    BT_LOGR("Error: Bluetooth A2DP interface not available");
-    if (aRes) {
-      aRes->OnError(NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!sBtA2dpInterface)) {
+    // If there's no A2DP interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
     }
     return;
   }
 
   BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
   sBtA2dpInterface->Init(a2dpManager, new InitA2dpResultHandler(aRes));
 }
 
@@ -352,16 +380,21 @@ public:
     }
   }
 
   void Cleanup() MOZ_OVERRIDE
   {
     sBtA2dpInterface = nullptr;
     if (sBtAvrcpInterface) {
       sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else if (mRes) {
+      /* Not all backends support AVRCP. If it's not available
+       * we signal success from here.
+       */
+      mRes->Deinit();
     }
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
 
 class CleanupA2dpResultHandlerRunnable MOZ_FINAL : public nsRunnable
@@ -371,16 +404,21 @@ public:
   : mRes(aRes)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
   {
     sBtA2dpInterface = nullptr;
     if (sBtAvrcpInterface) {
       sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else if (mRes) {
+      /* Not all backends support AVRCP. If it's not available
+       * we signal success from here.
+       */
+      mRes->Deinit();
     }
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
--- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -315,35 +315,63 @@ public:
     mRes->RunInit();
     return NS_OK;
   }
 
 private:
   nsRefPtr<CleanupInitResultHandler> mRes;
 };
 
+class OnErrorProfileResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                      nsresult aRv)
+  : mRes(aRes)
+  , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    mRes->OnError(mRv);
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
 // static
 void
 BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
-  if (!btInf) {
-    BT_LOGR("Error: Bluetooth interface not available");
-    if (aRes) {
-      aRes->OnError(NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no backend interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
     }
     return;
   }
 
   BluetoothHandsfreeInterface *interface =
     btInf->GetBluetoothHandsfreeInterface();
-  if (!interface) {
-    BT_LOGR("Error: Bluetooth Handsfree interface not available");
-    if (aRes) {
-      aRes->OnError(NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!interface)) {
+    // If there's no HFP interface, we dispatch a runnable
+    // that calls the profile result handler.
+    nsRefPtr<nsRunnable> r =
+      new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HFP OnError runnable");
     }
     return;
   }
 
   nsRefPtr<CleanupInitResultHandler> res =
     new CleanupInitResultHandler(interface, aRes);
 
   if (sBluetoothHfpInterface) {