diff --git a/dom/bluetooth2/BluetoothAdapter.cpp b/dom/bluetooth2/BluetoothAdapter.cpp index 87a7e584ff6..16ffb395c6d 100644 --- a/dom/bluetooth2/BluetoothAdapter.cpp +++ b/dom/bluetooth2/BluetoothAdapter.cpp @@ -6,8 +6,9 @@ #include "BluetoothReplyRunnable.h" #include "BluetoothService.h" -#include "BluetoothUtils.h" #include "DOMRequest.h" +#include "nsIDocument.h" +#include "nsIPrincipal.h" #include "nsTArrayHelpers.h" #include "mozilla/dom/BluetoothAdapter2Binding.h" @@ -193,11 +194,15 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow, , mState(BluetoothAdapterState::Disabled) , mDiscoverable(false) , mDiscovering(false) + , mPairingReqs(nullptr) , mDiscoveryHandleInUse(nullptr) { MOZ_ASSERT(aWindow); - mPairingReqs = BluetoothPairingListener::Create(aWindow); + // Only allow certified bluetooth application to receive pairing requests + if (IsBluetoothCertifiedApp()) { + mPairingReqs = BluetoothPairingListener::Create(aWindow); + } const InfallibleTArray& values = aValue.get_ArrayOfBluetoothNamedValue(); @@ -329,8 +334,6 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData) if (mDiscoveryHandleInUse) { HandleDeviceFound(v); } - } else if (aData.name().EqualsLiteral("PairingRequest")) { - HandlePairingRequest(v); } else if (aData.name().EqualsLiteral(DEVICE_PAIRED_ID)) { HandleDevicePaired(aData.value()); } else if (aData.name().EqualsLiteral(DEVICE_UNPAIRED_ID)) { @@ -762,6 +765,23 @@ BluetoothAdapter::IsAdapterAttributeChanged(BluetoothAdapterAttribute aType, } } +bool +BluetoothAdapter::IsBluetoothCertifiedApp() +{ + // Retrieve the app status and origin for permission checking + nsCOMPtr doc = GetOwner()->GetExtantDoc(); + NS_ENSURE_TRUE(doc, false); + + uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED; + nsAutoCString appOrigin; + + doc->NodePrincipal()->GetAppStatus(&appStatus); + doc->NodePrincipal()->GetOrigin(getter_Copies(appOrigin)); + + return appStatus == nsIPrincipal::APP_STATUS_CERTIFIED && + appOrigin.EqualsLiteral(BLUETOOTH_APP_ORIGIN); +} + void BluetoothAdapter::SetAdapterState(BluetoothAdapterState aState) { @@ -831,42 +851,6 @@ BluetoothAdapter::HandleDeviceFound(const BluetoothValue& aValue) mDiscoveryHandleInUse->DispatchDeviceEvent(discoveredDevice); } -void -BluetoothAdapter::HandlePairingRequest(const BluetoothValue& aValue) -{ - MOZ_ASSERT(mPairingReqs); - MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue); - - const InfallibleTArray& arr = - aValue.get_ArrayOfBluetoothNamedValue(); - - MOZ_ASSERT(arr.Length() == 3 && - arr[0].value().type() == BluetoothValue::TnsString && // address - arr[1].value().type() == BluetoothValue::TnsString && // passkey - arr[2].value().type() == BluetoothValue::TnsString); // type - - nsString deviceAddress = arr[0].value().get_nsString(); - nsString passkey = arr[1].value().get_nsString(); - nsString type = arr[2].value().get_nsString(); - - // Create a temporary device with deviceAddress for searching - InfallibleTArray props; - BT_APPEND_NAMED_VALUE(props, "Address", deviceAddress); - nsRefPtr device = - BluetoothDevice::Create(GetOwner(), props); - - // Find the remote device by address - size_t index = mDevices.IndexOf(device); - if (index == mDevices.NoIndex) { - BT_WARNING("Cannot find the remote device with address %s", - NS_ConvertUTF16toUTF8(deviceAddress).get()); - return; - } - - // Notify application of pairing requests - mPairingReqs->DispatchPairingEvent(mDevices[index], passkey, type); -} - void BluetoothAdapter::DispatchAttributeEvent(const nsTArray& aTypes) { diff --git a/dom/bluetooth2/BluetoothAdapter.h b/dom/bluetooth2/BluetoothAdapter.h index 063fa0b069d..5c65ede7702 100644 --- a/dom/bluetooth2/BluetoothAdapter.h +++ b/dom/bluetooth2/BluetoothAdapter.h @@ -248,13 +248,6 @@ private: */ void HandleDeviceFound(const BluetoothValue& aValue); - /** - * Handle "PairingRequest" bluetooth signal. - * - * @param aValue [in] Array of information about the pairing request. - */ - void HandlePairingRequest(const BluetoothValue& aValue); - /** * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. */ @@ -287,6 +280,13 @@ private: bool IsAdapterAttributeChanged(BluetoothAdapterAttribute aType, const BluetoothValue& aValue); + /** + * Check whether this adapter is owned by Bluetooth certified app. + * + * @return a boolean value to indicate whether it's owned by Bluetooth app. + */ + bool IsBluetoothCertifiedApp(); + /**************************************************************************** * Variables ***************************************************************************/ diff --git a/dom/bluetooth2/BluetoothCommon.h b/dom/bluetooth2/BluetoothCommon.h index d70cb0d1589..e7ddb7c28e4 100644 --- a/dom/bluetooth2/BluetoothCommon.h +++ b/dom/bluetooth2/BluetoothCommon.h @@ -143,6 +143,7 @@ extern bool gBluetoothDebugFlag; #define KEY_REMOTE_AGENT "/B2G/bluetooth/remote_device_agent" #define KEY_MANAGER "/B2G/bluetooth/manager" #define KEY_ADAPTER "/B2G/bluetooth/adapter" +#define KEY_PAIRING_LISTENER "/B2G/bluetooth/pairing_listener" /** * When the connection status of a Bluetooth profile is changed, we'll notify @@ -170,6 +171,18 @@ extern bool gBluetoothDebugFlag; #define PAIRING_REQ_TYPE_CONFIRMATION "pairingconfirmationreq" #define PAIRING_REQ_TYPE_CONSENT "pairingconsentreq" +/** + * System message to launch bluetooth app if no pairing listener is ready to + * receive pairing requests. + */ +#define SYS_MSG_BT_PAIRING_REQ "bluetooth-pairing-request" + +/** + * The app origin of bluetooth app, which is responsible for listening pairing + * requests. + */ +#define BLUETOOTH_APP_ORIGIN "app://bluetooth.gaiamobile.org" + /** * When a remote device gets paired / unpaired with local bluetooth adapter, * we'll dispatch an event. diff --git a/dom/bluetooth2/BluetoothPairingListener.cpp b/dom/bluetooth2/BluetoothPairingListener.cpp index 305cf9fe292..b0d31aad1c4 100644 --- a/dom/bluetooth2/BluetoothPairingListener.cpp +++ b/dom/bluetooth2/BluetoothPairingListener.cpp @@ -6,8 +6,10 @@ #include "mozilla/dom/bluetooth/BluetoothPairingListener.h" #include "mozilla/dom/bluetooth/BluetoothPairingHandle.h" +#include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/dom/BluetoothPairingEvent.h" #include "mozilla/dom/BluetoothPairingListenerBinding.h" +#include "BluetoothService.h" USING_BLUETOOTH_NAMESPACE @@ -21,6 +23,11 @@ BluetoothPairingListener::BluetoothPairingListener(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) { MOZ_ASSERT(aWindow); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER), + this); } already_AddRefed @@ -37,6 +44,11 @@ BluetoothPairingListener::Create(nsPIDOMWindow* aWindow) BluetoothPairingListener::~BluetoothPairingListener() { + BluetoothService* bs = BluetoothService::Get(); + // It can be nullptr on shutdown. + NS_ENSURE_TRUE_VOID(bs); + bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER), + this); } void @@ -67,8 +79,55 @@ BluetoothPairingListener::DispatchPairingEvent(BluetoothDevice* aDevice, DispatchTrustedEvent(event); } +void +BluetoothPairingListener::Notify(const BluetoothSignal& aData) +{ + InfallibleTArray arr; + + BluetoothValue value = aData.value(); + if (aData.name().EqualsLiteral("PairingRequest")) { + + MOZ_ASSERT(value.type() == BluetoothValue::TArrayOfBluetoothNamedValue); + + const InfallibleTArray& arr = + value.get_ArrayOfBluetoothNamedValue(); + + MOZ_ASSERT(arr.Length() == 3 && + arr[0].value().type() == BluetoothValue::TnsString && // address + arr[1].value().type() == BluetoothValue::TnsString && // passkey + arr[2].value().type() == BluetoothValue::TnsString); // type + + nsString deviceAddress = arr[0].value().get_nsString(); + nsString passkey = arr[1].value().get_nsString(); + nsString type = arr[2].value().get_nsString(); + + // Create a temporary device with deviceAddress for searching + InfallibleTArray props; + BT_APPEND_NAMED_VALUE(props, "Address", deviceAddress); + nsRefPtr device = + BluetoothDevice::Create(GetOwner(), props); + + // Notify pairing listener of pairing requests + DispatchPairingEvent(device, passkey, type); + } else { + BT_WARNING("Not handling pairing listener signal: %s", + NS_ConvertUTF16toUTF8(aData.name()).get()); + } +} + JSObject* BluetoothPairingListener::WrapObject(JSContext* aCx) { return BluetoothPairingListenerBinding::Wrap(aCx, this); } + +void +BluetoothPairingListener::DisconnectFromOwner() +{ + DOMEventTargetHelper::DisconnectFromOwner(); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER), + this); +} diff --git a/dom/bluetooth2/BluetoothPairingListener.h b/dom/bluetooth2/BluetoothPairingListener.h index 9958d2fc7b7..909fbc0e695 100644 --- a/dom/bluetooth2/BluetoothPairingListener.h +++ b/dom/bluetooth2/BluetoothPairingListener.h @@ -14,8 +14,10 @@ BEGIN_BLUETOOTH_NAMESPACE class BluetoothDevice; +class BluetoothSignal; class BluetoothPairingListener MOZ_FINAL : public DOMEventTargetHelper + , public BluetoothSignalObserver { public: NS_DECL_ISUPPORTS_INHERITED @@ -27,12 +29,15 @@ public: const nsAString& aPasskey, const nsAString& aType); + void Notify(const BluetoothSignal& aParam); // BluetoothSignalObserver + nsPIDOMWindow* GetParentObject() const { return GetOwner(); } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + virtual void DisconnectFromOwner() MOZ_OVERRIDE; IMPL_EVENT_HANDLER(displaypasskeyreq); IMPL_EVENT_HANDLER(enterpincodereq); diff --git a/dom/bluetooth2/BluetoothService.cpp b/dom/bluetooth2/BluetoothService.cpp index 1a95101cd14..e422d7cdd72 100644 --- a/dom/bluetooth2/BluetoothService.cpp +++ b/dom/bluetooth2/BluetoothService.cpp @@ -273,6 +273,17 @@ BluetoothService::RegisterBluetoothSignalHandler( } ol->AddObserver(aHandler); + + // Distribute pending pairing requests when pairing listener has been added + // to signal observer table. + if (IsMainProcess() && + !mPendingPairReqSignals.IsEmpty() && + aNodeName.EqualsLiteral(KEY_PAIRING_LISTENER)) { + for (uint32_t i = 0; i < mPendingPairReqSignals.Length(); ++i) { + DistributeSignal(mPendingPairReqSignals[i]); + } + mPendingPairReqSignals.Clear(); + } } void @@ -331,8 +342,19 @@ BluetoothService::DistributeSignal(const BluetoothSignal& aSignal) BluetoothSignalObserverList* ol; if (!mBluetoothSignalObserverTable.Get(aSignal.path(), &ol)) { - BT_WARNING("No observer registered for path %s", - NS_ConvertUTF16toUTF8(aSignal.path()).get()); + // If there is no BluetoohPairingListener in observer table, put the signal + // into a pending queue of pairing requests and send a system message to + // launch bluetooth certified app. + if (aSignal.path().EqualsLiteral(KEY_PAIRING_LISTENER)) { + mPendingPairReqSignals.AppendElement(aSignal); + + BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG( + NS_LITERAL_STRING(SYS_MSG_BT_PAIRING_REQ), + BluetoothValue(EmptyString())); + } else { + BT_WARNING("No observer registered for path %s", + NS_ConvertUTF16toUTF8(aSignal.path()).get()); + } return; } diff --git a/dom/bluetooth2/BluetoothService.h b/dom/bluetooth2/BluetoothService.h index 56092a43286..8879ea3f819 100644 --- a/dom/bluetooth2/BluetoothService.h +++ b/dom/bluetooth2/BluetoothService.h @@ -8,6 +8,7 @@ #define mozilla_dom_bluetooth_bluetootheventservice_h__ #include "BluetoothCommon.h" +#include "BluetoothInterface.h" #include "BluetoothProfileManagerBase.h" #include "nsAutoPtr.h" #include "nsClassHashtable.h" @@ -401,6 +402,8 @@ protected: BluetoothSignalObserverTable mBluetoothSignalObserverTable; + nsTArray mPendingPairReqSignals; + bool mEnabled; }; diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp index c734833400b..8a17df692d4 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp @@ -1473,7 +1473,7 @@ BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr NS_LITERAL_STRING(PAIRING_REQ_TYPE_ENTERPINCODE)); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PairingRequest"), - NS_LITERAL_STRING(KEY_ADAPTER), + NS_LITERAL_STRING(KEY_PAIRING_LISTENER), BluetoothValue(propertiesArray))); } @@ -1518,7 +1518,7 @@ BluetoothServiceBluedroid::SspRequestNotification( BT_APPEND_NAMED_VALUE(propertiesArray, "type", pairingType); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PairingRequest"), - NS_LITERAL_STRING(KEY_ADAPTER), + NS_LITERAL_STRING(KEY_PAIRING_LISTENER), BluetoothValue(propertiesArray))); }