mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge m-c to inbound a=merge CLOSED TREE
This commit is contained in:
commit
8794504c9f
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "8eac260ee81a8aca05770d18c5736536d44ee7a7",
|
||||
"git_revision": "efebbafd12fc42ddcd378948b683a51106517660",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "1400d176ecef76d06b012fb082c246eb17d1d30f",
|
||||
"revision": "d8e53e5d917b1ce79aea842e8340ce82799cac3e",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="efebbafd12fc42ddcd378948b683a51106517660"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -59,6 +59,7 @@ support-files =
|
||||
doc_event-listeners-01.html
|
||||
doc_event-listeners-02.html
|
||||
doc_event-listeners-03.html
|
||||
doc_event-listeners-04.html
|
||||
doc_frame-parameters.html
|
||||
doc_function-display-name.html
|
||||
doc_function-search.html
|
||||
@ -134,6 +135,8 @@ skip-if = e10s || true # bug 1113935
|
||||
skip-if = e10s || os == "mac" || e10s # Bug 895426
|
||||
[browser_dbg_break-on-dom-event-02.js]
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_break-on-dom-event-03.js]
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_breakpoints-actual-location.js]
|
||||
[browser_dbg_breakpoints-actual-location2.js]
|
||||
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
|
||||
|
@ -0,0 +1,101 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the break-on-dom-events request works for load event listeners.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_event-listeners-04.html";
|
||||
|
||||
let gClient, gThreadClient;
|
||||
|
||||
function test() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect((aType, aTraits) => {
|
||||
is(aType, "browser",
|
||||
"Root actor should identify itself as a browser.");
|
||||
|
||||
addTab(TAB_URL)
|
||||
.then(() => attachThreadActorForUrl(gClient, TAB_URL))
|
||||
.then(aThreadClient => gThreadClient = aThreadClient)
|
||||
.then(pauseDebuggee)
|
||||
.then(testBreakOnLoad)
|
||||
.then(closeConnection)
|
||||
.then(finish)
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function pauseDebuggee() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {
|
||||
is(aPacket.type, "paused",
|
||||
"We should now be paused.");
|
||||
is(aPacket.why.type, "debuggerStatement",
|
||||
"The debugger statement was hit.");
|
||||
|
||||
gThreadClient.resume(deferred.resolve);
|
||||
});
|
||||
|
||||
// Spin the event loop before causing the debuggee to pause, to allow
|
||||
// this function to return first.
|
||||
executeSoon(() => triggerButtonClick());
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// Test pause on a load event.
|
||||
function testBreakOnLoad() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Test calling pauseOnDOMEvents from a running state.
|
||||
gThreadClient.pauseOnDOMEvents(["load"], (aPacket) => {
|
||||
is(aPacket.error, undefined,
|
||||
"The pause-on-load request completed successfully.");
|
||||
let handlers = ["loadHandler"];
|
||||
|
||||
gClient.addListener("paused", function tester(aEvent, aPacket) {
|
||||
is(aPacket.why.type, "pauseOnDOMEvents",
|
||||
"A hidden breakpoint was hit.");
|
||||
|
||||
is(aPacket.frame.where.line, 15, "Found the load event listener.");
|
||||
gClient.removeListener("paused", tester);
|
||||
deferred.resolve();
|
||||
|
||||
gThreadClient.resume(() => triggerButtonClick(handlers.slice(-1)));
|
||||
});
|
||||
|
||||
getTabActorForUrl(gClient, TAB_URL).then(aGrip => {
|
||||
gClient.attachTab(aGrip.actor, (aResponse, aTabClient) => {
|
||||
aTabClient.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function triggerButtonClick() {
|
||||
let button = content.document.querySelector("button");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, button);
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
let deferred = promise.defer();
|
||||
gClient.close(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gClient = null;
|
||||
gThreadClient = null;
|
||||
});
|
@ -89,11 +89,11 @@ function testSetBreakpoint() {
|
||||
let sourceForm = getSourceForm(gSources, JS_URL);
|
||||
let source = gDebugger.gThreadClient.source(sourceForm);
|
||||
|
||||
source.setBreakpoint({ line: 3, column: 61 }, aResponse => {
|
||||
source.setBreakpoint({ line: 3, column: 18 }, aResponse => {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a js file.");
|
||||
ok(!aResponse.actualLocation,
|
||||
"Should be able to set a breakpoint on line 3 and column 61.");
|
||||
"Should be able to set a breakpoint on line 3 and column 18.");
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
23
browser/devtools/debugger/test/doc_event-listeners-04.html
Normal file
23
browser/devtools/debugger/test/doc_event-listeners-04.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Debugger test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button>Click me!</button>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", function onload() {
|
||||
var button = document.querySelector("button");
|
||||
button.onclick = function () {
|
||||
debugger;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -189,13 +189,17 @@ function Tooltip(doc, options) {
|
||||
// Used for namedTimeouts in the mouseover handling
|
||||
this.uid = "tooltip-" + Date.now();
|
||||
|
||||
// Emit show/hide events
|
||||
for (let event of POPUP_EVENTS) {
|
||||
this["_onPopup" + event] = ((e) => {
|
||||
return () => this.emit(e);
|
||||
})(event);
|
||||
this.panel.addEventListener("popup" + event,
|
||||
this["_onPopup" + event], false);
|
||||
// Emit show/hide events when the panel does.
|
||||
for (let eventName of POPUP_EVENTS) {
|
||||
this["_onPopup" + eventName] = (name => {
|
||||
return e => {
|
||||
if (e.target === this.panel) {
|
||||
this.emit(name);
|
||||
}
|
||||
};
|
||||
})(eventName);
|
||||
this.panel.addEventListener("popup" + eventName,
|
||||
this["_onPopup" + eventName], false);
|
||||
}
|
||||
|
||||
// Listen to keypress events to close the tooltip if configured to do so
|
||||
@ -303,9 +307,9 @@ Tooltip.prototype = {
|
||||
destroy: function () {
|
||||
this.hide();
|
||||
|
||||
for (let event of POPUP_EVENTS) {
|
||||
this.panel.removeEventListener("popup" + event,
|
||||
this["_onPopup" + event], false);
|
||||
for (let eventName of POPUP_EVENTS) {
|
||||
this.panel.removeEventListener("popup" + eventName,
|
||||
this["_onPopup" + eventName], false);
|
||||
}
|
||||
|
||||
let win = this.doc.querySelector("window");
|
||||
|
@ -159,6 +159,18 @@ DOMInterfaces = {
|
||||
'nativeType': 'mozilla::dom::bluetooth::BluetoothGatt',
|
||||
},
|
||||
|
||||
'BluetoothGattCharacteristic': {
|
||||
'nativeType': 'mozilla::dom::bluetooth::BluetoothGattCharacteristic',
|
||||
},
|
||||
|
||||
'BluetoothGattDescriptor': {
|
||||
'nativeType': 'mozilla::dom::bluetooth::BluetoothGattDescriptor',
|
||||
},
|
||||
|
||||
'BluetoothGattService': {
|
||||
'nativeType': 'mozilla::dom::bluetooth::BluetoothGattService',
|
||||
},
|
||||
|
||||
'BluetoothManager': {
|
||||
'nativeType': 'mozilla::dom::bluetooth::BluetoothManager',
|
||||
},
|
||||
|
@ -285,6 +285,16 @@ enum BluetoothSspVariant {
|
||||
|
||||
struct BluetoothUuid {
|
||||
uint8_t mUuid[16];
|
||||
|
||||
bool operator==(const BluetoothUuid& aOther) const
|
||||
{
|
||||
for (uint8_t i = 0; i < sizeof(mUuid); i++) {
|
||||
if (mUuid[i] != aOther.mUuid[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct BluetoothServiceRecord {
|
||||
@ -547,11 +557,21 @@ struct BluetoothGattAdvData {
|
||||
struct BluetoothGattId {
|
||||
BluetoothUuid mUuid;
|
||||
uint8_t mInstanceId;
|
||||
|
||||
bool operator==(const BluetoothGattId& aOther) const
|
||||
{
|
||||
return mUuid == aOther.mUuid && mInstanceId == aOther.mInstanceId;
|
||||
}
|
||||
};
|
||||
|
||||
struct BluetoothGattServiceId {
|
||||
BluetoothGattId mId;
|
||||
uint8_t mIsPrimary;
|
||||
|
||||
bool operator==(const BluetoothGattServiceId& aOther) const
|
||||
{
|
||||
return mId == aOther.mId && mIsPrimary == aOther.mIsPrimary;
|
||||
}
|
||||
};
|
||||
|
||||
struct BluetoothGattReadParam {
|
||||
|
@ -4,10 +4,10 @@
|
||||
* 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 "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGatt.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
#include "mozilla/dom/BluetoothGattBinding.h"
|
||||
@ -20,14 +20,9 @@ using namespace mozilla::dom;
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGatt)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothGatt,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothGatt,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothGatt,
|
||||
DOMEventTargetHelper,
|
||||
mServices)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothGatt)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
@ -42,6 +37,7 @@ BluetoothGatt::BluetoothGatt(nsPIDOMWindow* aWindow,
|
||||
, mClientIf(0)
|
||||
, mConnectionState(BluetoothConnectionState::Disconnected)
|
||||
, mDeviceAddr(aDeviceAddr)
|
||||
, mDiscoveringServices(false)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(!mDeviceAddr.IsEmpty());
|
||||
@ -216,6 +212,36 @@ BluetoothGatt::ReadRemoteRssi(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothGatt::DiscoverServices(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
BT_ENSURE_TRUE_REJECT(
|
||||
mConnectionState == BluetoothConnectionState::Connected &&
|
||||
!mDiscoveringServices,
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
mDiscoveringServices = true;
|
||||
nsRefPtr<BluetoothReplyRunnable> result =
|
||||
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
|
||||
promise,
|
||||
NS_LITERAL_STRING("DiscoverGattServices"));
|
||||
bs->DiscoverGattServicesInternal(mAppUuid, result);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
|
||||
{
|
||||
@ -235,6 +261,22 @@ BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
|
||||
DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGatt::HandleServicesDiscovered(const BluetoothValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattServiceId);
|
||||
|
||||
const InfallibleTArray<BluetoothGattServiceId>& serviceIds =
|
||||
aValue.get_ArrayOfBluetoothGattServiceId();
|
||||
|
||||
for (uint32_t i = 0; i < serviceIds.Length(); i++) {
|
||||
mServices.AppendElement(new BluetoothGattService(
|
||||
GetParentObject(), mAppUuid, serviceIds[i]));
|
||||
}
|
||||
|
||||
BluetoothGattBinding::ClearCachedServicesValue(this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGatt::Notify(const BluetoothSignal& aData)
|
||||
{
|
||||
@ -253,6 +295,18 @@ BluetoothGatt::Notify(const BluetoothSignal& aData)
|
||||
v.get_bool() ? BluetoothConnectionState::Connected
|
||||
: BluetoothConnectionState::Disconnected;
|
||||
UpdateConnectionState(state);
|
||||
} else if (aData.name().EqualsLiteral("ServicesDiscovered")) {
|
||||
HandleServicesDiscovered(v);
|
||||
} else if (aData.name().EqualsLiteral("DiscoverCompleted")) {
|
||||
MOZ_ASSERT(v.type() == BluetoothValue::Tbool);
|
||||
|
||||
bool isDiscoverSuccess = v.get_bool();
|
||||
if (!isDiscoverSuccess) { // Clean all discovered attributes if failed
|
||||
mServices.Clear();
|
||||
BluetoothGattBinding::ClearCachedServicesValue(this);
|
||||
}
|
||||
|
||||
mDiscoveringServices = false;
|
||||
} else {
|
||||
BT_WARNING("Not handling GATT signal: %s",
|
||||
NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/BluetoothGattBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattService.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -41,6 +42,11 @@ public:
|
||||
return mConnectionState;
|
||||
}
|
||||
|
||||
void GetServices(nsTArray<nsRefPtr<BluetoothGattService>>& aServices) const
|
||||
{
|
||||
aServices = mServices;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Event Handlers
|
||||
***************************************************************************/
|
||||
@ -51,6 +57,7 @@ public:
|
||||
***************************************************************************/
|
||||
already_AddRefed<Promise> Connect(ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Disconnect(ErrorResult& aRv);
|
||||
already_AddRefed<Promise> DiscoverServices(ErrorResult& aRv);
|
||||
already_AddRefed<Promise> ReadRemoteRssi(ErrorResult& aRv);
|
||||
|
||||
/****************************************************************************
|
||||
@ -87,6 +94,15 @@ private:
|
||||
*/
|
||||
void GenerateUuid(nsAString &aUuidString);
|
||||
|
||||
/**
|
||||
* Add newly discovered GATT services into mServices and update the cache
|
||||
* value of mServices.
|
||||
*
|
||||
* @param aValue [in] BluetoothValue which contains an array of
|
||||
* BluetoothGattServiceId of all discovered services.
|
||||
*/
|
||||
void HandleServicesDiscovered(const BluetoothValue& aValue);
|
||||
|
||||
/****************************************************************************
|
||||
* Variables
|
||||
***************************************************************************/
|
||||
@ -110,6 +126,16 @@ private:
|
||||
* Address of the remote device.
|
||||
*/
|
||||
nsString mDeviceAddr;
|
||||
|
||||
/**
|
||||
* Array of discovered services from the remote GATT server.
|
||||
*/
|
||||
nsTArray<nsRefPtr<BluetoothGattService>> mServices;
|
||||
|
||||
/**
|
||||
* Indicate whether there is ongoing discoverServices request or not.
|
||||
*/
|
||||
bool mDiscoveringServices;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
97
dom/bluetooth2/BluetoothGattCharacteristic.cpp
Normal file
97
dom/bluetooth2/BluetoothGattCharacteristic.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/* -*- 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 "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "mozilla/dom/BluetoothGattCharacteristicBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattCharacteristic.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattDescriptor.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattService.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
|
||||
BluetoothGattCharacteristic, mOwner, mService, mDescriptors)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattCharacteristic)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattCharacteristic)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattCharacteristic)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
BluetoothGattCharacteristic::BluetoothGattCharacteristic(
|
||||
nsPIDOMWindow* aOwner,
|
||||
BluetoothGattService* aService,
|
||||
const BluetoothGattId& aCharId)
|
||||
: mOwner(aOwner)
|
||||
, mService(aService)
|
||||
, mCharId(aCharId)
|
||||
{
|
||||
MOZ_ASSERT(aOwner);
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
// Generate bluetooth signal path and a string representation to provide uuid
|
||||
// of this characteristic to applications
|
||||
nsString path;
|
||||
GeneratePathFromGattId(mCharId, path, mUuidStr);
|
||||
bs->RegisterBluetoothSignalHandler(path, this);
|
||||
}
|
||||
|
||||
BluetoothGattCharacteristic::~BluetoothGattCharacteristic()
|
||||
{
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
nsString path;
|
||||
GeneratePathFromGattId(mCharId, path);
|
||||
bs->UnregisterBluetoothSignalHandler(path, this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattCharacteristic::HandleDescriptorsDiscovered(
|
||||
const BluetoothValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattId);
|
||||
|
||||
const InfallibleTArray<BluetoothGattId>& descriptorIds =
|
||||
aValue.get_ArrayOfBluetoothGattId();
|
||||
|
||||
for (uint32_t i = 0; i < descriptorIds.Length(); i++) {
|
||||
mDescriptors.AppendElement(new BluetoothGattDescriptor(
|
||||
GetParentObject(), this, descriptorIds[i]));
|
||||
}
|
||||
|
||||
BluetoothGattCharacteristicBinding::ClearCachedDescriptorsValue(this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattCharacteristic::Notify(const BluetoothSignal& aData)
|
||||
{
|
||||
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
|
||||
BluetoothValue v = aData.value();
|
||||
if (aData.name().EqualsLiteral("DescriptorsDiscovered")) {
|
||||
HandleDescriptorsDiscovered(v);
|
||||
} else {
|
||||
BT_WARNING("Not handling GATT Characteristic signal: %s",
|
||||
NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothGattCharacteristic::WrapObject(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothGattCharacteristicBinding::Wrap(aContext, this, aGivenProto);
|
||||
}
|
120
dom/bluetooth2/BluetoothGattCharacteristic.h
Normal file
120
dom/bluetooth2/BluetoothGattCharacteristic.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* -*- 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_bluetoothgattcharacteristic_h__
|
||||
#define mozilla_dom_bluetooth_bluetoothgattcharacteristic_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BluetoothGattCharacteristicBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattDescriptor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothGattService;
|
||||
class BluetoothSignal;
|
||||
class BluetoothValue;
|
||||
|
||||
class BluetoothGattCharacteristic final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattCharacteristic)
|
||||
|
||||
/****************************************************************************
|
||||
* Attribute Getters
|
||||
***************************************************************************/
|
||||
BluetoothGattService* Service() const
|
||||
{
|
||||
return mService;
|
||||
}
|
||||
|
||||
void GetDescriptors(
|
||||
nsTArray<nsRefPtr<BluetoothGattDescriptor>>& aDescriptors) const
|
||||
{
|
||||
aDescriptors = mDescriptors;
|
||||
}
|
||||
|
||||
void GetUuid(nsString& aUuidStr) const
|
||||
{
|
||||
aUuidStr = mUuidStr;
|
||||
}
|
||||
|
||||
int InstanceId() const
|
||||
{
|
||||
return mCharId.mInstanceId;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Others
|
||||
***************************************************************************/
|
||||
const BluetoothGattId& GetCharacteristicId() const
|
||||
{
|
||||
return mCharId;
|
||||
}
|
||||
|
||||
void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
BluetoothGattCharacteristic(nsPIDOMWindow* aOwner,
|
||||
BluetoothGattService* aService,
|
||||
const BluetoothGattId& aCharId);
|
||||
|
||||
private:
|
||||
~BluetoothGattCharacteristic();
|
||||
|
||||
/**
|
||||
* Add newly discovered GATT descriptors into mDescriptors and update the
|
||||
* cache value of mDescriptors.
|
||||
*
|
||||
* @param aValue [in] BluetoothValue which contains an array of
|
||||
* BluetoothGattId of all discovered descriptors.
|
||||
*/
|
||||
void HandleDescriptorsDiscovered(const BluetoothValue& aValue);
|
||||
|
||||
/****************************************************************************
|
||||
* Variables
|
||||
***************************************************************************/
|
||||
nsCOMPtr<nsPIDOMWindow> mOwner;
|
||||
|
||||
/**
|
||||
* Service that this characteristic belongs to.
|
||||
*/
|
||||
nsRefPtr<BluetoothGattService> mService;
|
||||
|
||||
/**
|
||||
* Array of discovered descriptors for this characteristic.
|
||||
*/
|
||||
nsTArray<nsRefPtr<BluetoothGattDescriptor>> mDescriptors;
|
||||
|
||||
/**
|
||||
* GattId of this GATT characteristic which contains
|
||||
* 1) mUuid: UUID of this characteristic in byte array format.
|
||||
* 2) mInstanceId: Instance id of this characteristic.
|
||||
*/
|
||||
BluetoothGattId mCharId;
|
||||
|
||||
/**
|
||||
* UUID string of this GATT characteristic.
|
||||
*/
|
||||
nsString mUuidStr;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif
|
54
dom/bluetooth2/BluetoothGattDescriptor.cpp
Normal file
54
dom/bluetooth2/BluetoothGattDescriptor.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- 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 "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "mozilla/dom/BluetoothGattDescriptorBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattCharacteristic.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattDescriptor.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
|
||||
BluetoothGattDescriptor, mOwner, mCharacteristic)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattDescriptor)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattDescriptor)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattDescriptor)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
BluetoothGattDescriptor::BluetoothGattDescriptor(
|
||||
nsPIDOMWindow* aOwner,
|
||||
BluetoothGattCharacteristic* aCharacteristic,
|
||||
const BluetoothGattId& aDescriptorId)
|
||||
: mOwner(aOwner)
|
||||
, mCharacteristic(aCharacteristic)
|
||||
, mDescriptorId(aDescriptorId)
|
||||
{
|
||||
MOZ_ASSERT(aOwner);
|
||||
MOZ_ASSERT(aCharacteristic);
|
||||
|
||||
// Generate a string representation to provide uuid of this descriptor to
|
||||
// applications
|
||||
ReversedUuidToString(aDescriptorId.mUuid, mUuidStr);
|
||||
}
|
||||
|
||||
BluetoothGattDescriptor::~BluetoothGattDescriptor()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothGattDescriptor::WrapObject(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothGattDescriptorBinding::Wrap(aContext, this, aGivenProto);
|
||||
}
|
88
dom/bluetooth2/BluetoothGattDescriptor.h
Normal file
88
dom/bluetooth2/BluetoothGattDescriptor.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- 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_bluetoothgattdescriptor_h__
|
||||
#define mozilla_dom_bluetooth_bluetoothgattdescriptor_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BluetoothGattDescriptorBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothGattCharacteristic;
|
||||
class BluetoothSignal;
|
||||
class BluetoothValue;
|
||||
|
||||
class BluetoothGattDescriptor final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattDescriptor)
|
||||
|
||||
/****************************************************************************
|
||||
* Attribute Getters
|
||||
***************************************************************************/
|
||||
BluetoothGattCharacteristic* Characteristic() const
|
||||
{
|
||||
return mCharacteristic;
|
||||
}
|
||||
|
||||
void GetUuid(nsString& aUuidStr) const
|
||||
{
|
||||
aUuidStr = mUuidStr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Others
|
||||
***************************************************************************/
|
||||
void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
BluetoothGattDescriptor(nsPIDOMWindow* aOwner,
|
||||
BluetoothGattCharacteristic* aCharacteristic,
|
||||
const BluetoothGattId& aDescriptorId);
|
||||
|
||||
private:
|
||||
~BluetoothGattDescriptor();
|
||||
|
||||
/****************************************************************************
|
||||
* Variables
|
||||
***************************************************************************/
|
||||
nsCOMPtr<nsPIDOMWindow> mOwner;
|
||||
|
||||
/**
|
||||
* Characteristic that this descriptor belongs to.
|
||||
*/
|
||||
nsRefPtr<BluetoothGattCharacteristic> mCharacteristic;
|
||||
|
||||
/**
|
||||
* GattId of this GATT descriptor which contains
|
||||
* 1) mUuid: UUID of this descriptor in byte array format.
|
||||
* 2) mInstanceId: Instance id of this descriptor.
|
||||
*/
|
||||
BluetoothGattId mDescriptorId;
|
||||
|
||||
/**
|
||||
* UUID string of this GATT descriptor.
|
||||
*/
|
||||
nsString mUuidStr;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif
|
114
dom/bluetooth2/BluetoothGattService.cpp
Normal file
114
dom/bluetooth2/BluetoothGattService.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/* -*- 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 "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "mozilla/dom/BluetoothGattServiceBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattCharacteristic.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattService.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
|
||||
BluetoothGattService, mOwner, mIncludedServices, mCharacteristics)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattService)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattService)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattService)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
BluetoothGattService::BluetoothGattService(
|
||||
nsPIDOMWindow* aOwner, const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServiceId)
|
||||
: mOwner(aOwner)
|
||||
, mAppUuid(aAppUuid)
|
||||
, mServiceId(aServiceId)
|
||||
{
|
||||
MOZ_ASSERT(aOwner);
|
||||
MOZ_ASSERT(!mAppUuid.IsEmpty());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
// Generate bluetooth signal path and a string representation to provide
|
||||
// uuid of this service to applications
|
||||
nsString path;
|
||||
GeneratePathFromGattId(mServiceId.mId, path, mUuidStr);
|
||||
bs->RegisterBluetoothSignalHandler(path, this);
|
||||
}
|
||||
|
||||
BluetoothGattService::~BluetoothGattService()
|
||||
{
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
nsString path;
|
||||
GeneratePathFromGattId(mServiceId.mId, path);
|
||||
bs->UnregisterBluetoothSignalHandler(path, this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattService::HandleIncludedServicesDiscovered(
|
||||
const BluetoothValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattServiceId);
|
||||
|
||||
const InfallibleTArray<BluetoothGattServiceId>& includedServIds =
|
||||
aValue.get_ArrayOfBluetoothGattServiceId();
|
||||
|
||||
for (uint32_t i = 0; i < includedServIds.Length(); i++) {
|
||||
mIncludedServices.AppendElement(new BluetoothGattService(
|
||||
GetParentObject(), mAppUuid, includedServIds[i]));
|
||||
}
|
||||
|
||||
BluetoothGattServiceBinding::ClearCachedIncludedServicesValue(this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattService::HandleCharacteristicsDiscovered(
|
||||
const BluetoothValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattId);
|
||||
|
||||
const InfallibleTArray<BluetoothGattId>& characteristicIds =
|
||||
aValue.get_ArrayOfBluetoothGattId();
|
||||
|
||||
for (uint32_t i = 0; i < characteristicIds.Length(); i++) {
|
||||
mCharacteristics.AppendElement(new BluetoothGattCharacteristic(
|
||||
GetParentObject(), this, characteristicIds[i]));
|
||||
}
|
||||
|
||||
BluetoothGattServiceBinding::ClearCachedCharacteristicsValue(this);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattService::Notify(const BluetoothSignal& aData)
|
||||
{
|
||||
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
|
||||
BluetoothValue v = aData.value();
|
||||
if (aData.name().EqualsLiteral("IncludedServicesDiscovered")) {
|
||||
HandleIncludedServicesDiscovered(v);
|
||||
} else if (aData.name().EqualsLiteral("CharacteristicsDiscovered")) {
|
||||
HandleCharacteristicsDiscovered(v);
|
||||
} else {
|
||||
BT_WARNING("Not handling GATT Service signal: %s",
|
||||
NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
BluetoothGattService::WrapObject(JSContext* aContext,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BluetoothGattServiceBinding::Wrap(aContext, this, aGivenProto);
|
||||
}
|
146
dom/bluetooth2/BluetoothGattService.h
Normal file
146
dom/bluetooth2/BluetoothGattService.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* -*- 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_bluetoothgattservice_h__
|
||||
#define mozilla_dom_bluetooth_bluetoothgattservice_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BluetoothGattServiceBinding.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothGattCharacteristic.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothSignal;
|
||||
class BluetoothValue;
|
||||
|
||||
class BluetoothGattService final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
, public BluetoothSignalObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattService)
|
||||
|
||||
/****************************************************************************
|
||||
* Attribute Getters
|
||||
***************************************************************************/
|
||||
bool IsPrimary() const
|
||||
{
|
||||
return mServiceId.mIsPrimary;
|
||||
}
|
||||
|
||||
void GetUuid(nsString& aUuidStr) const
|
||||
{
|
||||
aUuidStr = mUuidStr;
|
||||
}
|
||||
|
||||
int InstanceId() const
|
||||
{
|
||||
return mServiceId.mId.mInstanceId;
|
||||
}
|
||||
|
||||
void GetIncludedServices(
|
||||
nsTArray<nsRefPtr<BluetoothGattService>>& aIncludedServices) const
|
||||
{
|
||||
aIncludedServices = mIncludedServices;
|
||||
}
|
||||
|
||||
void GetCharacteristics(
|
||||
nsTArray<nsRefPtr<BluetoothGattCharacteristic>>& aCharacteristics) const
|
||||
{
|
||||
aCharacteristics = mCharacteristics;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Others
|
||||
***************************************************************************/
|
||||
const nsAString& GetAppUuid() const
|
||||
{
|
||||
return mAppUuid;
|
||||
}
|
||||
|
||||
const BluetoothGattServiceId& GetServiceId() const
|
||||
{
|
||||
return mServiceId;
|
||||
}
|
||||
|
||||
void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
BluetoothGattService(nsPIDOMWindow* aOwner,
|
||||
const nsAString& aAppUuid,
|
||||
const BluetoothGattServiceId& aServiceId);
|
||||
|
||||
private:
|
||||
~BluetoothGattService();
|
||||
|
||||
/**
|
||||
* Add newly discovered GATT included services into mIncludedServices and
|
||||
* update the cache value of mIncludedServices.
|
||||
*
|
||||
* @param aValue [in] BluetoothValue which contains an array of
|
||||
* BluetoothGattServiceId of all discovered included
|
||||
* services.
|
||||
*/
|
||||
void HandleIncludedServicesDiscovered(const BluetoothValue& aValue);
|
||||
|
||||
/**
|
||||
* Add newly discovered GATT characteristics into mCharacteristics and
|
||||
* update the cache value of mCharacteristics.
|
||||
*
|
||||
* @param aValue [in] BluetoothValue which contains an array of
|
||||
* BluetoothGattId of all discovered characteristics.
|
||||
*/
|
||||
void HandleCharacteristicsDiscovered(const BluetoothValue& aValue);
|
||||
|
||||
/****************************************************************************
|
||||
* Variables
|
||||
***************************************************************************/
|
||||
nsCOMPtr<nsPIDOMWindow> mOwner;
|
||||
|
||||
/**
|
||||
* UUID of the GATT client.
|
||||
*/
|
||||
nsString mAppUuid;
|
||||
|
||||
/**
|
||||
* ServiceId of this GATT service which contains
|
||||
* 1) mId.mUuid: UUID of this service in byte array format.
|
||||
* 2) mId.mInstanceId: Instance id of this service.
|
||||
* 3) mIsPrimary: Indicate whether this is a primary service or not.
|
||||
*/
|
||||
BluetoothGattServiceId mServiceId;
|
||||
|
||||
/**
|
||||
* UUID string of this GATT service.
|
||||
*/
|
||||
nsString mUuidStr;
|
||||
|
||||
/**
|
||||
* Array of discovered included services for this service.
|
||||
*/
|
||||
nsTArray<nsRefPtr<BluetoothGattService>> mIncludedServices;
|
||||
|
||||
/**
|
||||
* Array of discovered characteristics for this service.
|
||||
*/
|
||||
nsTArray<nsRefPtr<BluetoothGattCharacteristic>> mCharacteristics;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
#endif
|
@ -691,20 +691,24 @@ public:
|
||||
|
||||
/* Enumerate Attributes */
|
||||
virtual void SearchService(int aConnId,
|
||||
bool aSearchAll,
|
||||
const BluetoothUuid& aUuid,
|
||||
BluetoothGattClientResultHandler* aRes) = 0;
|
||||
virtual void GetIncludedService(
|
||||
int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
bool aFirst,
|
||||
const BluetoothGattServiceId& aStartServiceId,
|
||||
BluetoothGattClientResultHandler* aRes) = 0;
|
||||
virtual void GetCharacteristic(int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
bool aFirst,
|
||||
const BluetoothGattId& aStartCharId,
|
||||
BluetoothGattClientResultHandler* aRes) = 0;
|
||||
virtual void GetDescriptor(int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId,
|
||||
bool aFirst,
|
||||
const BluetoothGattId& aDescriptorId,
|
||||
BluetoothGattClientResultHandler* aRes) = 0;
|
||||
|
||||
|
@ -342,6 +342,14 @@ public:
|
||||
const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Discover GATT services, characteristic, descriptors from a remote GATT
|
||||
* server. (platform specific implementation)
|
||||
*/
|
||||
virtual void
|
||||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Unregister a GATT client. (platform specific implementation)
|
||||
*/
|
||||
|
@ -40,6 +40,17 @@ UuidToString(const BluetoothUuid& aUuid, nsAString& aString)
|
||||
aString.AssignLiteral(uuidStr);
|
||||
}
|
||||
|
||||
void
|
||||
ReversedUuidToString(const BluetoothUuid& aUuid, nsAString& aString)
|
||||
{
|
||||
BluetoothUuid uuid;
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
uuid.mUuid[i] = aUuid.mUuid[15 - i];
|
||||
}
|
||||
|
||||
UuidToString(uuid, aString);
|
||||
}
|
||||
|
||||
void
|
||||
StringToUuid(const char* aString, BluetoothUuid& aUuid)
|
||||
{
|
||||
@ -64,6 +75,26 @@ StringToUuid(const char* aString, BluetoothUuid& aUuid)
|
||||
memcpy(&aUuid.mUuid[14], &uuid5, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void
|
||||
GeneratePathFromGattId(const BluetoothGattId& aId,
|
||||
nsAString& aPath,
|
||||
nsAString& aUuidStr)
|
||||
{
|
||||
ReversedUuidToString(aId.mUuid, aUuidStr);
|
||||
|
||||
aPath.Assign(aUuidStr);
|
||||
aPath.AppendLiteral("_");
|
||||
aPath.AppendInt(aId.mInstanceId);
|
||||
}
|
||||
|
||||
void
|
||||
GeneratePathFromGattId(const BluetoothGattId& aId,
|
||||
nsAString& aPath)
|
||||
{
|
||||
nsString uuidStr;
|
||||
GeneratePathFromGattId(aId, aPath, uuidStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* |SetJsObject| is an internal function used by |BroadcastSystemMessage| only
|
||||
*/
|
||||
|
@ -22,20 +22,61 @@ class BluetoothValue;
|
||||
|
||||
/**
|
||||
* Convert BluetoothUuid object to xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx uuid string.
|
||||
* This utility function is used by gecko internal only to convert BluetoothUuid
|
||||
* created by bluetooth stack to uuid string representation.
|
||||
*
|
||||
* Note: This utility function is used by gecko internal only to convert
|
||||
* BluetoothUuid created by bluetooth stack to uuid string representation.
|
||||
*/
|
||||
void
|
||||
UuidToString(const BluetoothUuid& aUuid, nsAString& aString);
|
||||
|
||||
/**
|
||||
* Convert BluetoothUuid object in a reversed byte order to
|
||||
* xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx uuid string.
|
||||
* Bluedroid stack reports the BluetoothUuid in a reversed byte order for
|
||||
* GATT service, characteristic, descriptor uuids.
|
||||
*
|
||||
* Note: This utility function is used by gecko internal only to convert
|
||||
* BluetoothUuid in a reversed byte order created by bluetooth stack to uuid
|
||||
* string representation.
|
||||
*/
|
||||
void
|
||||
ReversedUuidToString(const BluetoothUuid& aUuid, nsAString& aString);
|
||||
|
||||
/**
|
||||
* Convert xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx uuid string to BluetoothUuid object.
|
||||
* This utility function is used by gecko internal only to convert uuid string
|
||||
* created by gecko back to BluetoothUuid representation.
|
||||
*
|
||||
* Note: This utility function is used by gecko internal only to convert uuid
|
||||
* string created by gecko back to BluetoothUuid representation.
|
||||
*/
|
||||
void
|
||||
StringToUuid(const char* aString, BluetoothUuid& aUuid);
|
||||
|
||||
//
|
||||
// Generate bluetooth signal path from GattId
|
||||
//
|
||||
|
||||
/**
|
||||
* Generate bluetooth signal path and UUID string from a GattId.
|
||||
*
|
||||
* @param aId [in] GattId value to convert.
|
||||
* @param aPath [out] Bluetooth signal path generated from aId.
|
||||
* @param aUuidStr [out] UUID string generated from aId.
|
||||
*/
|
||||
void
|
||||
GeneratePathFromGattId(const BluetoothGattId& aId,
|
||||
nsAString& aPath,
|
||||
nsAString& aUuidStr);
|
||||
|
||||
/**
|
||||
* Generate bluetooth signal path from a GattId.
|
||||
*
|
||||
* @param aId [in] GattId value to convert.
|
||||
* @param aPath [out] Bluetooth signal path generated from aId.
|
||||
*/
|
||||
void
|
||||
GeneratePathFromGattId(const BluetoothGattId& aId,
|
||||
nsAString& aPath);
|
||||
|
||||
//
|
||||
// Broadcast system message
|
||||
//
|
||||
|
@ -621,14 +621,16 @@ BluetoothGattClientHALInterface::Refresh(
|
||||
|
||||
void
|
||||
BluetoothGattClientHALInterface::SearchService(
|
||||
int aConnId, const BluetoothUuid& aUuid,
|
||||
int aConnId, bool aSearchAll, const BluetoothUuid& aUuid,
|
||||
BluetoothGattClientResultHandler* aRes)
|
||||
{
|
||||
bt_status_t status;
|
||||
#if ANDROID_VERSION >= 19
|
||||
bt_uuid_t uuid;
|
||||
|
||||
if (NS_SUCCEEDED(Convert(aUuid, uuid))) {
|
||||
if (aSearchAll) {
|
||||
status = mInterface->search_service(aConnId, 0);
|
||||
} else if (NS_SUCCEEDED(Convert(aUuid, uuid))) {
|
||||
status = mInterface->search_service(aConnId, &uuid);
|
||||
} else {
|
||||
status = BT_STATUS_PARM_INVALID;
|
||||
@ -647,7 +649,7 @@ BluetoothGattClientHALInterface::SearchService(
|
||||
void
|
||||
BluetoothGattClientHALInterface::GetIncludedService(
|
||||
int aConnId, const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattServiceId& aStartServiceId,
|
||||
bool aFirst, const BluetoothGattServiceId& aStartServiceId,
|
||||
BluetoothGattClientResultHandler* aRes)
|
||||
{
|
||||
bt_status_t status;
|
||||
@ -655,8 +657,10 @@ BluetoothGattClientHALInterface::GetIncludedService(
|
||||
btgatt_srvc_id_t serviceId;
|
||||
btgatt_srvc_id_t startServiceId;
|
||||
|
||||
if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aStartServiceId, startServiceId))) {
|
||||
if (aFirst && NS_SUCCEEDED(Convert(aServiceId, serviceId))) {
|
||||
status = mInterface->get_included_service(aConnId, &serviceId, 0);
|
||||
} else if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aStartServiceId, startServiceId))) {
|
||||
status = mInterface->get_included_service(aConnId, &serviceId,
|
||||
&startServiceId);
|
||||
} else {
|
||||
@ -676,7 +680,7 @@ BluetoothGattClientHALInterface::GetIncludedService(
|
||||
void
|
||||
BluetoothGattClientHALInterface::GetCharacteristic(
|
||||
int aConnId, const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aStartCharId,
|
||||
bool aFirst, const BluetoothGattId& aStartCharId,
|
||||
BluetoothGattClientResultHandler* aRes)
|
||||
{
|
||||
bt_status_t status;
|
||||
@ -684,8 +688,10 @@ BluetoothGattClientHALInterface::GetCharacteristic(
|
||||
btgatt_srvc_id_t serviceId;
|
||||
btgatt_gatt_id_t startCharId;
|
||||
|
||||
if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aStartCharId, startCharId))) {
|
||||
if (aFirst && NS_SUCCEEDED(Convert(aServiceId, serviceId))) {
|
||||
status = mInterface->get_characteristic(aConnId, &serviceId, 0);
|
||||
} else if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aStartCharId, startCharId))) {
|
||||
status = mInterface->get_characteristic(aConnId, &serviceId, &startCharId);
|
||||
} else {
|
||||
status = BT_STATUS_PARM_INVALID;
|
||||
@ -704,9 +710,8 @@ BluetoothGattClientHALInterface::GetCharacteristic(
|
||||
void
|
||||
BluetoothGattClientHALInterface::GetDescriptor(
|
||||
int aConnId, const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId,
|
||||
const BluetoothGattId& aDescriptorId,
|
||||
BluetoothGattClientResultHandler* aRes)
|
||||
const BluetoothGattId& aCharId, bool aFirst,
|
||||
const BluetoothGattId& aDescriptorId, BluetoothGattClientResultHandler* aRes)
|
||||
{
|
||||
bt_status_t status;
|
||||
#if ANDROID_VERSION >= 19
|
||||
@ -714,9 +719,13 @@ BluetoothGattClientHALInterface::GetDescriptor(
|
||||
btgatt_gatt_id_t charId;
|
||||
btgatt_gatt_id_t descriptorId;
|
||||
|
||||
if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aCharId, charId)) &&
|
||||
NS_SUCCEEDED(Convert(aDescriptorId, descriptorId))) {
|
||||
if (aFirst &&
|
||||
NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aCharId, charId))) {
|
||||
status = mInterface->get_descriptor(aConnId, &serviceId, &charId, 0);
|
||||
} else if (NS_SUCCEEDED(Convert(aServiceId, serviceId)) &&
|
||||
NS_SUCCEEDED(Convert(aCharId, charId)) &&
|
||||
NS_SUCCEEDED(Convert(aDescriptorId, descriptorId))) {
|
||||
status = mInterface->get_descriptor(aConnId, &serviceId, &charId,
|
||||
&descriptorId);
|
||||
} else {
|
||||
|
@ -56,19 +56,23 @@ public:
|
||||
|
||||
/* Enumerate Attributes */
|
||||
void SearchService(int aConnId,
|
||||
bool aSearchAll,
|
||||
const BluetoothUuid& aUuid,
|
||||
BluetoothGattClientResultHandler* aRes);
|
||||
void GetIncludedService(int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
bool aFirst,
|
||||
const BluetoothGattServiceId& aStartServiceId,
|
||||
BluetoothGattClientResultHandler* aRes);
|
||||
void GetCharacteristic(int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
bool aFirst,
|
||||
const BluetoothGattId& aStartCharId,
|
||||
BluetoothGattClientResultHandler* aRes);
|
||||
void GetDescriptor(int aConnId,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId,
|
||||
bool aFirst,
|
||||
const BluetoothGattId& aDescriptorId,
|
||||
BluetoothGattClientResultHandler* aRes);
|
||||
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
#include "BluetoothGattManager.h"
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "BluetoothInterface.h"
|
||||
#include "BluetoothReplyRunnable.h"
|
||||
#include "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/dom/bluetooth/BluetoothCommon.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -37,10 +37,9 @@ namespace {
|
||||
|
||||
bool BluetoothGattManager::mInShutdown = false;
|
||||
|
||||
class BluetoothGattClient;
|
||||
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
|
||||
|
||||
class BluetoothGattClient final : public nsISupports
|
||||
class mozilla::dom::bluetooth::BluetoothGattClient final : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -56,18 +55,59 @@ public:
|
||||
{
|
||||
mConnectRunnable = nullptr;
|
||||
mDisconnectRunnable = nullptr;
|
||||
mDiscoverRunnable = nullptr;
|
||||
mUnregisterClientRunnable = nullptr;
|
||||
mReadRemoteRssiRunnable = nullptr;
|
||||
}
|
||||
|
||||
void NotifyDiscoverCompleted(bool aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(!mAppUuid.IsEmpty());
|
||||
MOZ_ASSERT(mDiscoverRunnable);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
// Notify application to clear the cache values of
|
||||
// service/characteristic/descriptor.
|
||||
bs->DistributeSignal(NS_LITERAL_STRING("DiscoverCompleted"),
|
||||
mAppUuid,
|
||||
BluetoothValue(aSuccess));
|
||||
|
||||
// Resolve/Reject the Promise.
|
||||
if (aSuccess) {
|
||||
DispatchReplySuccess(mDiscoverRunnable);
|
||||
} else {
|
||||
DispatchReplyError(mDiscoverRunnable,
|
||||
NS_LITERAL_STRING("Discover failed"));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
mServices.Clear();
|
||||
mIncludedServices.Clear();
|
||||
mCharacteristics.Clear();
|
||||
mDescriptors.Clear();
|
||||
mDiscoverRunnable = nullptr;
|
||||
}
|
||||
|
||||
nsString mAppUuid;
|
||||
nsString mDeviceAddr;
|
||||
int mClientIf;
|
||||
int mConnId;
|
||||
nsRefPtr<BluetoothReplyRunnable> mConnectRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mDisconnectRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mUnregisterClientRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mDiscoverRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mReadRemoteRssiRunnable;
|
||||
nsRefPtr<BluetoothReplyRunnable> mUnregisterClientRunnable;
|
||||
|
||||
/**
|
||||
* These temporary arrays are used only during discover operations.
|
||||
* All of them are empty if there are no ongoing discover operations.
|
||||
*/
|
||||
nsTArray<BluetoothGattServiceId> mServices;
|
||||
nsTArray<BluetoothGattServiceId> mIncludedServices;
|
||||
nsTArray<BluetoothGattId> mCharacteristics;
|
||||
nsTArray<BluetoothGattId> mDescriptors;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(BluetoothGattClient)
|
||||
@ -92,6 +132,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ConnIdComparator
|
||||
{
|
||||
public:
|
||||
bool Equals(const nsRefPtr<BluetoothGattClient>& aClient,
|
||||
int aConnId) const
|
||||
{
|
||||
return aClient->mConnId == aConnId;
|
||||
}
|
||||
};
|
||||
|
||||
BluetoothGattManager*
|
||||
BluetoothGattManager::Get()
|
||||
{
|
||||
@ -338,13 +388,7 @@ BluetoothGattManager::UnregisterClient(int aClientIf,
|
||||
|
||||
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||
ClientIfComparator());
|
||||
|
||||
// Reject the unregister request if the client is not found
|
||||
if (index == sClients->NoIndex) {
|
||||
DispatchReplyError(aRunnable,
|
||||
NS_LITERAL_STRING("Unregister GATT client failed"));
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
client->mUnregisterClientRunnable = aRunnable;
|
||||
@ -469,12 +513,7 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid,
|
||||
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
|
||||
|
||||
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
|
||||
|
||||
// Reject the disconnect request if the client is not found
|
||||
if (index == sClients->NoIndex) {
|
||||
DispatchReplyError(aRunnable, NS_LITERAL_STRING("Disconnect failed"));
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
client->mDisconnectRunnable = aRunnable;
|
||||
@ -486,6 +525,66 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid,
|
||||
new DisconnectResultHandler(client));
|
||||
}
|
||||
|
||||
class BluetoothGattManager::DiscoverResultHandler final
|
||||
: public BluetoothGattClientResultHandler
|
||||
{
|
||||
public:
|
||||
DiscoverResultHandler(BluetoothGattClient* aClient)
|
||||
: mClient(aClient)
|
||||
{
|
||||
MOZ_ASSERT(mClient);
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
{
|
||||
BT_WARNING("BluetoothGattClientInterface::Discover failed: %d",
|
||||
(int)aStatus);
|
||||
|
||||
mClient->NotifyDiscoverCompleted(false);
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothGattClient> mClient;
|
||||
};
|
||||
|
||||
void
|
||||
BluetoothGattManager::Discover(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
|
||||
|
||||
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
MOZ_ASSERT(client->mConnId > 0);
|
||||
MOZ_ASSERT(!client->mDiscoverRunnable);
|
||||
|
||||
client->mDiscoverRunnable = aRunnable;
|
||||
|
||||
/**
|
||||
* Discover all services/characteristics/descriptors offered by the remote
|
||||
* GATT server.
|
||||
*
|
||||
* The discover procesure includes following steps.
|
||||
* 1) Discover all services.
|
||||
* 2) After all services are discovered, for each service S, we will do
|
||||
* following actions.
|
||||
* 2-1) Discover all included services of service S.
|
||||
* 2-2) Discover all characteristics of service S.
|
||||
* 2-3) Discover all descriptors of those characteristics discovered in
|
||||
* 2-2).
|
||||
*/
|
||||
sBluetoothGattClientInterface->SearchService(
|
||||
client->mConnId,
|
||||
true, // search all services
|
||||
BluetoothUuid(),
|
||||
new DiscoverResultHandler(client));
|
||||
}
|
||||
|
||||
class BluetoothGattManager::ReadRemoteRssiResultHandler final
|
||||
: public BluetoothGattClientResultHandler
|
||||
{
|
||||
@ -527,13 +626,7 @@ BluetoothGattManager::ReadRemoteRssi(int aClientIf,
|
||||
|
||||
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||
ClientIfComparator());
|
||||
|
||||
// Reject the read remote rssi request if the client is not found
|
||||
if (index == sClients->NoIndex) {
|
||||
DispatchReplyError(aRunnable,
|
||||
NS_LITERAL_STRING("Read remote RSSI failed"));
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
client->mReadRemoteRssiRunnable = aRunnable;
|
||||
@ -558,7 +651,7 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus,
|
||||
UuidToString(aAppUuid, uuid);
|
||||
|
||||
size_t index = sClients->IndexOf(uuid, 0 /* Start */, UuidComparator());
|
||||
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
@ -621,7 +714,7 @@ BluetoothGattManager::ConnectNotification(int aConnId,
|
||||
|
||||
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||
ClientIfComparator());
|
||||
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
|
||||
if (aStatus != GATT_STATUS_SUCCESS) {
|
||||
@ -673,7 +766,7 @@ BluetoothGattManager::DisconnectNotification(int aConnId,
|
||||
|
||||
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
|
||||
ClientIfComparator());
|
||||
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
|
||||
if (aStatus != GATT_STATUS_SUCCESS) {
|
||||
@ -711,12 +804,57 @@ BluetoothGattManager::DisconnectNotification(int aConnId,
|
||||
void
|
||||
BluetoothGattManager::SearchCompleteNotification(int aConnId,
|
||||
BluetoothGattStatus aStatus)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
|
||||
ConnIdComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
MOZ_ASSERT(client->mDiscoverRunnable);
|
||||
|
||||
if (aStatus != GATT_STATUS_SUCCESS) {
|
||||
client->NotifyDiscoverCompleted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify BluetoothGatt to create all services
|
||||
bs->DistributeSignal(NS_LITERAL_STRING("ServicesDiscovered"),
|
||||
client->mAppUuid,
|
||||
BluetoothValue(client->mServices));
|
||||
|
||||
// All services are discovered, continue to search included services of each
|
||||
// service if existed, otherwise, notify application that discover completed
|
||||
if (!client->mServices.IsEmpty()) {
|
||||
sBluetoothGattClientInterface->GetIncludedService(
|
||||
aConnId,
|
||||
client->mServices[0], // start from first service
|
||||
true, // first included service
|
||||
BluetoothGattServiceId(),
|
||||
new DiscoverResultHandler(client));
|
||||
} else {
|
||||
client->NotifyDiscoverCompleted(true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::SearchResultNotification(
|
||||
int aConnId, const BluetoothGattServiceId& aServiceId)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
|
||||
ConnIdComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
// Save to mServices for distributing to application and discovering
|
||||
// included services, characteristics of this service later
|
||||
sClients->ElementAt(index)->mServices.AppendElement(aServiceId);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::GetCharacteristicNotification(
|
||||
@ -724,7 +862,43 @@ BluetoothGattManager::GetCharacteristicNotification(
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId,
|
||||
int aCharProperty)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
|
||||
ConnIdComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
MOZ_ASSERT(client->mDiscoverRunnable);
|
||||
|
||||
if (aStatus == GATT_STATUS_SUCCESS) {
|
||||
// Save to mCharacteristics for distributing to applications and
|
||||
// discovering descriptors of this characteristic later
|
||||
client->mCharacteristics.AppendElement(aCharId);
|
||||
|
||||
// Get next characteristic of this service
|
||||
sBluetoothGattClientInterface->GetCharacteristic(
|
||||
aConnId,
|
||||
aServiceId,
|
||||
false,
|
||||
aCharId,
|
||||
new DiscoverResultHandler(client));
|
||||
} else { // all characteristics of this service are discovered
|
||||
// Notify BluetoothGattService to create characteristics then proceed
|
||||
nsString path;
|
||||
GeneratePathFromGattId(aServiceId.mId, path);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING("CharacteristicsDiscovered"),
|
||||
path,
|
||||
BluetoothValue(client->mCharacteristics));
|
||||
|
||||
ProceedDiscoverProcess(client, aServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::GetDescriptorNotification(
|
||||
@ -732,14 +906,93 @@ BluetoothGattManager::GetDescriptorNotification(
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattId& aCharId,
|
||||
const BluetoothGattId& aDescriptorId)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
|
||||
ConnIdComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
MOZ_ASSERT(client->mDiscoverRunnable);
|
||||
|
||||
if (aStatus == GATT_STATUS_SUCCESS) {
|
||||
// Save to mDescriptors for distributing to applications
|
||||
client->mDescriptors.AppendElement(aDescriptorId);
|
||||
|
||||
// Get next descriptor of this characteristic
|
||||
sBluetoothGattClientInterface->GetDescriptor(
|
||||
aConnId,
|
||||
aServiceId,
|
||||
aCharId,
|
||||
false,
|
||||
aDescriptorId,
|
||||
new DiscoverResultHandler(client));
|
||||
} else { // all descriptors of this characteristic are discovered
|
||||
// Notify BluetoothGattCharacteristic to create descriptors then proceed
|
||||
nsString path;
|
||||
GeneratePathFromGattId(aCharId, path);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING("DescriptorsDiscovered"),
|
||||
path,
|
||||
BluetoothValue(client->mDescriptors));
|
||||
client->mDescriptors.Clear();
|
||||
|
||||
ProceedDiscoverProcess(client, aServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::GetIncludedServiceNotification(
|
||||
int aConnId, BluetoothGattStatus aStatus,
|
||||
const BluetoothGattServiceId& aServiceId,
|
||||
const BluetoothGattServiceId& aIncludedServId)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
|
||||
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
|
||||
ConnIdComparator());
|
||||
MOZ_ASSERT(index != sClients->NoIndex);
|
||||
|
||||
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
|
||||
MOZ_ASSERT(client->mDiscoverRunnable);
|
||||
|
||||
if (aStatus == GATT_STATUS_SUCCESS) {
|
||||
// Save to mIncludedServices for distributing to applications
|
||||
client->mIncludedServices.AppendElement(aIncludedServId);
|
||||
|
||||
// Get next included service of this service
|
||||
sBluetoothGattClientInterface->GetIncludedService(
|
||||
aConnId,
|
||||
aServiceId,
|
||||
false,
|
||||
aIncludedServId,
|
||||
new DiscoverResultHandler(client));
|
||||
} else { // all included services of this service are discovered
|
||||
// Notify BluetoothGattService to create included services
|
||||
nsString path;
|
||||
GeneratePathFromGattId(aServiceId.mId, path);
|
||||
|
||||
bs->DistributeSignal(NS_LITERAL_STRING("IncludedServicesDiscovered"),
|
||||
path,
|
||||
BluetoothValue(client->mIncludedServices));
|
||||
client->mIncludedServices.Clear();
|
||||
|
||||
// Start to discover characteristics of this service
|
||||
sBluetoothGattClientInterface->GetCharacteristic(
|
||||
aConnId,
|
||||
aServiceId,
|
||||
true, // first characteristic
|
||||
BluetoothGattId(),
|
||||
new DiscoverResultHandler(client));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::RegisterNotificationNotification(
|
||||
@ -863,4 +1116,45 @@ BluetoothGattManager::HandleShutdown()
|
||||
sBluetoothGattManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothGattManager::ProceedDiscoverProcess(
|
||||
BluetoothGattClient* aClient,
|
||||
const BluetoothGattServiceId& aServiceId)
|
||||
{
|
||||
/**
|
||||
* This function will be called to decide how to proceed the discover process
|
||||
* after discovering all characteristics of a given service, or after
|
||||
* discovering all descriptors of a given characteristic.
|
||||
*
|
||||
* There are three cases here,
|
||||
* 1) mCharacteristics is not empty:
|
||||
* Proceed to discover descriptors of the first saved characteristic.
|
||||
* 2) mCharacteristics is empty but mServices is not empty:
|
||||
* This service does not have any saved characteristics left, proceed to
|
||||
* discover included services of the next service.
|
||||
* 3) Both arrays are already empty:
|
||||
* Discover is done, notify application.
|
||||
*/
|
||||
if (!aClient->mCharacteristics.IsEmpty()) {
|
||||
sBluetoothGattClientInterface->GetDescriptor(
|
||||
aClient->mConnId,
|
||||
aServiceId,
|
||||
aClient->mCharacteristics[0],
|
||||
true, // first descriptor
|
||||
BluetoothGattId(),
|
||||
new DiscoverResultHandler(aClient));
|
||||
aClient->mCharacteristics.RemoveElementAt(0);
|
||||
} else if (!aClient->mServices.IsEmpty()) {
|
||||
sBluetoothGattClientInterface->GetIncludedService(
|
||||
aClient->mConnId,
|
||||
aClient->mServices[0],
|
||||
true, // first included service
|
||||
BluetoothGattServiceId(),
|
||||
new DiscoverResultHandler(aClient));
|
||||
aClient->mServices.RemoveElementAt(0);
|
||||
} else {
|
||||
aClient->NotifyDiscoverCompleted(true);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BluetoothGattManager, nsIObserver)
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothGattClient;
|
||||
class BluetoothReplyRunnable;
|
||||
|
||||
class BluetoothGattManager final : public nsIObserver
|
||||
@ -35,6 +36,9 @@ public:
|
||||
const nsAString& aDeviceAddr,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
void Discover(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
void UnregisterClient(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
@ -50,6 +54,7 @@ private:
|
||||
class UnregisterClientResultHandler;
|
||||
class ConnectResultHandler;
|
||||
class DisconnectResultHandler;
|
||||
class DiscoverResultHandler;
|
||||
class ReadRemoteRssiResultHandler;
|
||||
|
||||
BluetoothGattManager();
|
||||
@ -137,6 +142,9 @@ private:
|
||||
void ListenNotification(BluetoothGattStatus aStatus,
|
||||
int aServerIf) override;
|
||||
|
||||
void ProceedDiscoverProcess(BluetoothGattClient* aClient,
|
||||
const BluetoothGattServiceId& aServiceId);
|
||||
|
||||
static bool mInShutdown;
|
||||
};
|
||||
|
||||
|
@ -1117,6 +1117,20 @@ BluetoothServiceBluedroid::DisconnectGattClientInternal(
|
||||
gatt->Disconnect(aAppUuid, aDeviceAddress, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::DiscoverGattServicesInternal(
|
||||
const nsAString& aAppUuid, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
|
||||
|
||||
BluetoothGattManager* gatt = BluetoothGattManager::Get();
|
||||
ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
|
||||
|
||||
gatt->Discover(aAppUuid, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -184,6 +184,10 @@ public:
|
||||
const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
@ -4291,6 +4291,12 @@ BluetoothDBusService::DisconnectGattClientInternal(
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::DiscoverGattServicesInternal(
|
||||
const nsAString& aAppUuid, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDBusService::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -194,6 +194,11 @@ public:
|
||||
DisconnectGattClientInternal(const nsAString& aAppUuid,
|
||||
const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
@ -28,6 +28,73 @@ struct ParamTraits<mozilla::dom::bluetooth::BluetoothStatus>
|
||||
mozilla::dom::bluetooth::STATUS_RMT_DEV_DOWN>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::bluetooth::BluetoothUuid>
|
||||
{
|
||||
typedef mozilla::dom::bluetooth::BluetoothUuid paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
WriteParam(aMsg, aParam.mUuid[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mUuid[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::bluetooth::BluetoothGattId>
|
||||
{
|
||||
typedef mozilla::dom::bluetooth::BluetoothGattId paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mUuid);
|
||||
WriteParam(aMsg, aParam.mInstanceId);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mUuid)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mInstanceId))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::bluetooth::BluetoothGattServiceId>
|
||||
{
|
||||
typedef mozilla::dom::bluetooth::BluetoothGattServiceId paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mId);
|
||||
WriteParam(aMsg, aParam.mIsPrimary);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &(aResult->mId)) ||
|
||||
!ReadParam(aMsg, aIter, &(aResult->mIsPrimary))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_dom_bluetooth_ipc_bluetoothmessageutils_h__
|
||||
|
@ -254,6 +254,8 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
||||
return actor->DoRequest(aRequest.get_ConnectGattClientRequest());
|
||||
case Request::TDisconnectGattClientRequest:
|
||||
return actor->DoRequest(aRequest.get_DisconnectGattClientRequest());
|
||||
case Request::TDiscoverGattServicesRequest:
|
||||
return actor->DoRequest(aRequest.get_DiscoverGattServicesRequest());
|
||||
case Request::TUnregisterGattClientRequest:
|
||||
return actor->DoRequest(aRequest.get_UnregisterGattClientRequest());
|
||||
case Request::TGattClientReadRemoteRssiRequest:
|
||||
@ -719,6 +721,18 @@ BluetoothRequestParent::DoRequest(const DisconnectGattClientRequest& aRequest)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const DiscoverGattServicesRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TDiscoverGattServicesRequest);
|
||||
|
||||
mService->DiscoverGattServicesInternal(aRequest.appUuid(),
|
||||
mReplyRunnable.get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const UnregisterGattClientRequest& aRequest)
|
||||
{
|
||||
|
@ -223,6 +223,9 @@ protected:
|
||||
bool
|
||||
DoRequest(const DisconnectGattClientRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const DiscoverGattServicesRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const UnregisterGattClientRequest& aRequest);
|
||||
|
||||
|
@ -397,6 +397,14 @@ BluetoothServiceChildProcess::DisconnectGattClientInternal(
|
||||
DisconnectGattClientRequest(nsString(aAppUuid), nsString(aDeviceAddress)));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::DiscoverGattServicesInternal(
|
||||
const nsAString& aAppUuid, BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable,
|
||||
DiscoverGattServicesRequest(nsString(aAppUuid)));
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothServiceChildProcess::UnregisterGattClientInternal(
|
||||
int aClientIf, BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -202,6 +202,10 @@ public:
|
||||
const nsAString& aDeviceAddress,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
DiscoverGattServicesInternal(const nsAString& aAppUuid,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
UnregisterGattClientInternal(int aClientIf,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
@ -4,7 +4,12 @@
|
||||
* 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/. */
|
||||
|
||||
using mozilla::dom::bluetooth::BluetoothStatus from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothGattId
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothGattServiceId
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
using mozilla::dom::bluetooth::BluetoothStatus
|
||||
from "mozilla/dom/bluetooth/BluetoothCommon.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -23,6 +28,8 @@ union BluetoothValue
|
||||
nsString[];
|
||||
uint8_t[];
|
||||
BluetoothNamedValue[];
|
||||
BluetoothGattId[];
|
||||
BluetoothGattServiceId[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -188,6 +188,11 @@ struct DisconnectGattClientRequest
|
||||
nsString deviceAddress;
|
||||
};
|
||||
|
||||
struct DiscoverGattServicesRequest
|
||||
{
|
||||
nsString appUuid;
|
||||
};
|
||||
|
||||
struct UnregisterGattClientRequest
|
||||
{
|
||||
int clientIf;
|
||||
@ -233,6 +238,7 @@ union Request
|
||||
SendPlayStatusRequest;
|
||||
ConnectGattClientRequest;
|
||||
DisconnectGattClientRequest;
|
||||
DiscoverGattServicesRequest;
|
||||
UnregisterGattClientRequest;
|
||||
GattClientReadRemoteRssiRequest;
|
||||
};
|
||||
|
@ -11,6 +11,9 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
'BluetoothDevice.cpp',
|
||||
'BluetoothDiscoveryHandle.cpp',
|
||||
'BluetoothGatt.cpp',
|
||||
'BluetoothGattCharacteristic.cpp',
|
||||
'BluetoothGattDescriptor.cpp',
|
||||
'BluetoothGattService.cpp',
|
||||
'BluetoothHidManager.cpp',
|
||||
'BluetoothInterface.cpp',
|
||||
'BluetoothManager.cpp',
|
||||
@ -124,6 +127,9 @@ EXPORTS.mozilla.dom.bluetooth += [
|
||||
'BluetoothDevice.h',
|
||||
'BluetoothDiscoveryHandle.h',
|
||||
'BluetoothGatt.h',
|
||||
'BluetoothGattCharacteristic.h',
|
||||
'BluetoothGattDescriptor.h',
|
||||
'BluetoothGattService.h',
|
||||
'BluetoothManager.h',
|
||||
'BluetoothPairingHandle.h',
|
||||
'BluetoothPairingListener.h',
|
||||
|
@ -524,7 +524,6 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||
skip-if = toolkit == 'android' || (toolkit == 'gonk' && debug) #bug 871015, bug 881443
|
||||
[test_input_files_not_nsIFile.html]
|
||||
[test_ignoreuserfocus.html]
|
||||
skip-if = (toolkit == 'gonk' && debug)
|
||||
[test_fragment_form_pointer.html]
|
||||
[test_bug1682.html]
|
||||
[test_bug1823.html]
|
||||
|
@ -7,6 +7,8 @@
|
||||
[CheckPermissions="bluetooth"]
|
||||
interface BluetoothGatt : EventTarget
|
||||
{
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<BluetoothGattService> services;
|
||||
readonly attribute BluetoothConnectionState connectionState;
|
||||
|
||||
// Fired when attribute connectionState changed
|
||||
@ -28,6 +30,14 @@ interface BluetoothGatt : EventTarget
|
||||
[NewObject]
|
||||
Promise<void> disconnect();
|
||||
|
||||
/**
|
||||
* Discover services, characteristics, descriptors offered by the remote GATT
|
||||
* server. The promise will be rejected if the connState is not connected or
|
||||
* operation fails.
|
||||
*/
|
||||
[NewObject]
|
||||
Promise<void> discoverServices();
|
||||
|
||||
/**
|
||||
* Read RSSI for the remote BLE device if the connectState is connected.
|
||||
* Otherwise, the Promise will be rejected directly.
|
||||
|
16
dom/webidl/BluetoothGattCharacteristic.webidl
Normal file
16
dom/webidl/BluetoothGattCharacteristic.webidl
Normal file
@ -0,0 +1,16 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
[CheckPermissions="bluetooth"]
|
||||
interface BluetoothGattCharacteristic
|
||||
{
|
||||
readonly attribute BluetoothGattService service;
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<BluetoothGattDescriptor> descriptors;
|
||||
|
||||
readonly attribute DOMString uuid;
|
||||
readonly attribute unsigned short instanceId;
|
||||
};
|
12
dom/webidl/BluetoothGattDescriptor.webidl
Normal file
12
dom/webidl/BluetoothGattDescriptor.webidl
Normal file
@ -0,0 +1,12 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
[CheckPermissions="bluetooth"]
|
||||
interface BluetoothGattDescriptor
|
||||
{
|
||||
readonly attribute BluetoothGattCharacteristic characteristic;
|
||||
readonly attribute DOMString uuid;
|
||||
};
|
18
dom/webidl/BluetoothGattService.webidl
Normal file
18
dom/webidl/BluetoothGattService.webidl
Normal file
@ -0,0 +1,18 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
[CheckPermissions="bluetooth"]
|
||||
interface BluetoothGattService
|
||||
{
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<BluetoothGattCharacteristic> characteristics;
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<BluetoothGattService> includedServices;
|
||||
|
||||
readonly attribute boolean isPrimary;
|
||||
readonly attribute DOMString uuid;
|
||||
readonly attribute unsigned short instanceId;
|
||||
};
|
@ -637,6 +637,9 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
'BluetoothDevice2.webidl',
|
||||
'BluetoothDiscoveryHandle.webidl',
|
||||
'BluetoothGatt.webidl',
|
||||
'BluetoothGattCharacteristic.webidl',
|
||||
'BluetoothGattDescriptor.webidl',
|
||||
'BluetoothGattService.webidl',
|
||||
'BluetoothManager2.webidl',
|
||||
'BluetoothPairingHandle.webidl',
|
||||
'BluetoothPairingListener.webidl',
|
||||
|
@ -106,7 +106,8 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
||||
// Escape hatch: we don't show the option to open this dialog in this state so this should
|
||||
// never be run. However, due to potential inconsistencies in synced client state
|
||||
// (e.g. bug 1122302 comment 47), we might fail.
|
||||
if (state == State.DEVICES_ONLY && clientrecords.length == 0) {
|
||||
if (state == State.DEVICES_ONLY &&
|
||||
(clientrecords == null || clientrecords.length == 0)) {
|
||||
Log.e(LOGTAG, "In state: " + State.DEVICES_ONLY + " and received 0 synced clients. Finishing...");
|
||||
Toast.makeText(this, getResources().getText(R.string.overlay_no_synced_devices), Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
|
@ -28,6 +28,7 @@ import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.overlays.ui.ShareDialog;
|
||||
import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.R;
|
||||
import java.io.File;
|
||||
|
||||
@ -1303,6 +1304,13 @@ public class ActivityChooserModel extends DataSetObservable {
|
||||
* Mozilla: Return whether or not there are other synced clients.
|
||||
*/
|
||||
private boolean hasOtherSyncClients() {
|
||||
// ClientsDatabaseAccessor returns stale data (bug 1145896) so we work around this by
|
||||
// checking if we have accounts set up - if not, we can't have any clients.
|
||||
if (!FirefoxAccounts.firefoxAccountsExist(mContext) &&
|
||||
!SyncAccounts.syncAccountsExist(mContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ClientsDatabaseAccessor db = new ClientsDatabaseAccessor(mContext);
|
||||
return db.clientsCount() > 0;
|
||||
}
|
||||
|
@ -106,12 +106,10 @@ static size_t getPageSize(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The stack size is chosen carefully so the frozen threads doesn't consume too
|
||||
* much memory in the Nuwa process. The threads shouldn't run deep recursive
|
||||
* methods or do large allocations on the stack to avoid stack overflow.
|
||||
* Use 1 MiB stack size as Android does.
|
||||
*/
|
||||
#ifndef NUWA_STACK_SIZE
|
||||
#define NUWA_STACK_SIZE (1024 * 128)
|
||||
#define NUWA_STACK_SIZE (1024 * 1024)
|
||||
#endif
|
||||
|
||||
#define NATIVE_THREAD_NAME_LENGTH 16
|
||||
@ -173,6 +171,8 @@ struct thread_info : public mozilla::LinkedListElement<thread_info> {
|
||||
pthread_mutex_t *condMutex;
|
||||
bool condMutexNeedsBalancing;
|
||||
|
||||
size_t stackSize;
|
||||
size_t guardSize;
|
||||
void *stk;
|
||||
|
||||
pid_t origNativeThreadID;
|
||||
@ -546,20 +546,10 @@ thread_info_new(void) {
|
||||
tinfo->recreatedNativeThreadID = 0;
|
||||
tinfo->condMutex = nullptr;
|
||||
tinfo->condMutexNeedsBalancing = false;
|
||||
tinfo->stk = MozTaggedAnonymousMmap(nullptr,
|
||||
NUWA_STACK_SIZE + getPageSize(),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
/* fd */ -1,
|
||||
/* offset */ 0,
|
||||
"nuwa-thread-stack");
|
||||
|
||||
// We use a smaller stack size. Add protection to stack overflow: mprotect()
|
||||
// stack top (the page at the lowest address) so we crash instead of corrupt
|
||||
// other content that is malloc()'d.
|
||||
mprotect(tinfo->stk, getPageSize(), PROT_NONE);
|
||||
|
||||
pthread_attr_init(&tinfo->threadAttr);
|
||||
// Default stack and guard size.
|
||||
tinfo->stackSize = NUWA_STACK_SIZE;
|
||||
tinfo->guardSize = getPageSize();
|
||||
|
||||
REAL(pthread_mutex_lock)(&sThreadCountLock);
|
||||
// Insert to the tail.
|
||||
@ -572,6 +562,44 @@ thread_info_new(void) {
|
||||
return tinfo;
|
||||
}
|
||||
|
||||
static void
|
||||
thread_attr_init(thread_info_t *tinfo, const pthread_attr_t *tattr)
|
||||
{
|
||||
pthread_attr_init(&tinfo->threadAttr);
|
||||
|
||||
if (tattr) {
|
||||
// Override default thread stack and guard size with tattr.
|
||||
pthread_attr_getstacksize(tattr, &tinfo->stackSize);
|
||||
pthread_attr_getguardsize(tattr, &tinfo->guardSize);
|
||||
|
||||
size_t pageSize = getPageSize();
|
||||
|
||||
tinfo->stackSize = (tinfo->stackSize + pageSize - 1) % pageSize;
|
||||
tinfo->guardSize = (tinfo->guardSize + pageSize - 1) % pageSize;
|
||||
|
||||
int detachState = 0;
|
||||
pthread_attr_getdetachstate(tattr, &detachState);
|
||||
pthread_attr_setdetachstate(&tinfo->threadAttr, detachState);
|
||||
}
|
||||
|
||||
tinfo->stk = MozTaggedAnonymousMmap(nullptr,
|
||||
tinfo->stackSize + tinfo->guardSize,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
/* fd */ -1,
|
||||
/* offset */ 0,
|
||||
"nuwa-thread-stack");
|
||||
|
||||
// Add protection to stack overflow: mprotect() stack top (the page at the
|
||||
// lowest address) so we crash instead of corrupt other content that is
|
||||
// malloc()'d.
|
||||
mprotect(tinfo->stk, tinfo->guardSize, PROT_NONE);
|
||||
|
||||
pthread_attr_setstack(&tinfo->threadAttr,
|
||||
(char*)tinfo->stk + tinfo->guardSize,
|
||||
tinfo->stackSize);
|
||||
}
|
||||
|
||||
static void
|
||||
thread_info_cleanup(void *arg) {
|
||||
if (sNuwaForking) {
|
||||
@ -582,7 +610,7 @@ thread_info_cleanup(void *arg) {
|
||||
thread_info_t *tinfo = (thread_info_t *)arg;
|
||||
pthread_attr_destroy(&tinfo->threadAttr);
|
||||
|
||||
munmap(tinfo->stk, NUWA_STACK_SIZE + getPageSize());
|
||||
munmap(tinfo->stk, tinfo->stackSize + tinfo->guardSize);
|
||||
|
||||
REAL(pthread_mutex_lock)(&sThreadCountLock);
|
||||
/* unlink tinfo from sAllThreads */
|
||||
@ -741,11 +769,9 @@ __wrap_pthread_create(pthread_t *thread,
|
||||
}
|
||||
|
||||
thread_info_t *tinfo = thread_info_new();
|
||||
thread_attr_init(tinfo, attr);
|
||||
tinfo->startupFunc = start_routine;
|
||||
tinfo->startupArg = arg;
|
||||
pthread_attr_setstack(&tinfo->threadAttr,
|
||||
(char*)tinfo->stk + getPageSize(),
|
||||
NUWA_STACK_SIZE);
|
||||
|
||||
int rv = REAL(pthread_create)(thread,
|
||||
&tinfo->threadAttr,
|
||||
|
@ -154,6 +154,7 @@ SandboxFilterImplContent::Build() {
|
||||
Allow(SYSCALL(munmap));
|
||||
Allow(SYSCALL(mprotect));
|
||||
Allow(SYSCALL(writev));
|
||||
Allow(SYSCALL(pread64));
|
||||
AllowThreadClone();
|
||||
Allow(SYSCALL(brk));
|
||||
#if SYSCALL_EXISTS(set_thread_area)
|
||||
|
@ -17,6 +17,8 @@ def parse_test_opts(input_str):
|
||||
tests.insert(0, cur_test)
|
||||
|
||||
def add_platform(value):
|
||||
# Ensure platforms exists...
|
||||
cur_test['platforms'] = cur_test.get('platforms', [])
|
||||
cur_test['platforms'].insert(0, value.strip())
|
||||
|
||||
# This might be somewhat confusing but we parse the string _backwards_ so
|
||||
@ -45,7 +47,6 @@ def parse_test_opts(input_str):
|
||||
elif char == ']':
|
||||
# Entering platform state.
|
||||
in_platforms = True
|
||||
cur_test['platforms'] = []
|
||||
else:
|
||||
# Accumulator.
|
||||
token = char + token
|
||||
|
@ -29,6 +29,18 @@ class TryTestParserTest(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEquals(
|
||||
parse_test_opts('mochitest-3[Ubuntu,10.6,10.8,Windows XP,Windows 7,Windows 8]'),
|
||||
[
|
||||
{
|
||||
'test': 'mochitest-3',
|
||||
'platforms': [
|
||||
'Ubuntu', '10.6', '10.8', 'Windows XP', 'Windows 7', 'Windows 8'
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEquals(
|
||||
parse_test_opts(''),
|
||||
[]
|
||||
|
@ -29,6 +29,7 @@ loader.lazyGetter(this, "Debugger", () => {
|
||||
loader.lazyRequireGetter(this, "SourceMapConsumer", "source-map", true);
|
||||
loader.lazyRequireGetter(this, "SourceMapGenerator", "source-map", true);
|
||||
loader.lazyRequireGetter(this, "CssLogic", "devtools/styleinspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "events", "sdk/event/core");
|
||||
|
||||
let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
"Uint32Array", "Int8Array", "Int16Array", "Int32Array", "Float32Array",
|
||||
@ -444,6 +445,7 @@ function ThreadActor(aParent, aGlobal)
|
||||
this._tabClosed = false;
|
||||
this._scripts = null;
|
||||
this._sources = null;
|
||||
this._pauseOnDOMEvents = null;
|
||||
|
||||
this._options = {
|
||||
useSourceMaps: false,
|
||||
@ -467,6 +469,8 @@ function ThreadActor(aParent, aGlobal)
|
||||
this.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
|
||||
this.onDebuggerStatement = this.onDebuggerStatement.bind(this);
|
||||
this.onNewScript = this.onNewScript.bind(this);
|
||||
this._onWindowReady = this._onWindowReady.bind(this);
|
||||
events.on(this._parent, "window-ready", this._onWindowReady);
|
||||
// Set a wrappedJSObject property so |this| can be sent via the observer svc
|
||||
// for the xpcshell harness.
|
||||
this.wrappedJSObject = this;
|
||||
@ -620,6 +624,7 @@ ThreadActor.prototype = {
|
||||
// things like breakpoints across connections.
|
||||
this._sourceActorStore = null;
|
||||
|
||||
events.off(this._parent, "window-ready", this._onWindowReady);
|
||||
this.clearDebuggees();
|
||||
this.conn.removeActorPool(this._threadLifetimePool);
|
||||
this._threadLifetimePool = null;
|
||||
@ -1009,6 +1014,16 @@ ThreadActor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If we are tasked with breaking on the load event, we have to add the
|
||||
* listener early enough.
|
||||
*/
|
||||
_onWindowReady: function () {
|
||||
this._maybeListenToEvents({
|
||||
pauseOnDOMEvents: this._pauseOnDOMEvents
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a protocol request to resume execution of the debuggee.
|
||||
*/
|
||||
@ -2791,21 +2806,16 @@ SourceActor.prototype = {
|
||||
* Ensure the given BreakpointActor is set as a breakpoint handler on all
|
||||
* scripts that match its location in the original source.
|
||||
*
|
||||
* It is possible that no scripts match the given location, because they have
|
||||
* all been garbage collected. In that case, the BreakpointActor is not set as
|
||||
* a breakpoint handler for any script, but is still inserted in the
|
||||
* BreakpointActorMap as a pending breakpoint. Whenever a new script is
|
||||
* introduced, we call this method again to see if there are now any scripts
|
||||
* that matches the given location.
|
||||
* If there are no scripts that match the location of the BreakpointActor,
|
||||
* we slide its location to the next closest line (for line breakpoints) or
|
||||
* column (for column breakpoint) that does.
|
||||
*
|
||||
* The first time we find one or more scripts that matches the given location,
|
||||
* we check if any of these scripts has any entry points for the given
|
||||
* location. If not, we assume that the given location does not have any code.
|
||||
*
|
||||
* If the given location does not contain any code, we slide the breakpoint
|
||||
* down to the next closest line that does, and update the BreakpointActorMap
|
||||
* accordingly. Note that we only do so if the BreakpointActor is still
|
||||
* pending (i.e. is not set as a breakpoint handler for any script).
|
||||
* If breakpoint sliding fails, then either there are no scripts that contain
|
||||
* any code for the given location, or they were all garbage collected before
|
||||
* the debugger started running. We cannot distinguish between these two
|
||||
* cases, so we insert the BreakpointActor in the BreakpointActorMap as
|
||||
* a pending breakpoint. Whenever a new script is introduced, this method is
|
||||
* called again for each pending breakpoint.
|
||||
*
|
||||
* @param BreakpointActor actor
|
||||
* The BreakpointActor to be set as a breakpoint handler.
|
||||
@ -2813,21 +2823,125 @@ SourceActor.prototype = {
|
||||
* @returns A Promise that resolves to the given BreakpointActor.
|
||||
*/
|
||||
_setBreakpointForActor: function (actor) {
|
||||
let { originalLocation } = actor;
|
||||
|
||||
if (this.isSourceMapped) {
|
||||
return this.threadActor.sources.getGeneratedLocation(
|
||||
actor.originalLocation
|
||||
).then((generatedLocation) => {
|
||||
// TODO: Refactor breakpoint sliding for source mapped sources.
|
||||
return this.threadActor.sources.getGeneratedLocation(originalLocation)
|
||||
.then((generatedLocation) => {
|
||||
return generatedLocation.generatedSourceActor
|
||||
._setBreakpointForActorAtLocation(
|
||||
._setBreakpointForActorAtLocationWithSliding(
|
||||
actor,
|
||||
generatedLocation
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(this._setBreakpointForActorAtLocation(
|
||||
actor,
|
||||
GeneratedLocation.fromOriginalLocation(actor.originalLocation)
|
||||
));
|
||||
// If this is a non-source mapped source, the original location and
|
||||
// generated location are the same, so we can safely convert between them.
|
||||
let generatedLocation = GeneratedLocation.fromOriginalLocation(originalLocation);
|
||||
let { generatedColumn } = generatedLocation;
|
||||
|
||||
// Try to set the breakpoint on the generated location directly. If this
|
||||
// succeeds, we can avoid the more expensive breakpoint sliding algorithm
|
||||
// below.
|
||||
if (this._setBreakpointForActorAtLocation(actor, generatedLocation)) {
|
||||
return Promise.resolve(actor);
|
||||
}
|
||||
|
||||
// There were no scripts that matched the given location, so we need to
|
||||
// perform breakpoint sliding.
|
||||
if (generatedColumn === undefined) {
|
||||
// To perform breakpoint sliding for line breakpoints, we need to build
|
||||
// a map from line numbers to a list of entry points for each line,
|
||||
// implemented as a sparse array. An entry point is a (script, offsets)
|
||||
// pair, and represents all offsets in that script that are entry points
|
||||
// for the corresponding line.
|
||||
let lineToEntryPointsMap = [];
|
||||
|
||||
// Iterate over all scripts that correspond to this source actor.
|
||||
let scripts = this.scripts.getScriptsBySourceActor(this);
|
||||
for (let script of scripts) {
|
||||
// Get all offsets for each line in the current script. This returns
|
||||
// a map from line numbers fo a list of offsets for each line,
|
||||
// implemented as a sparse array.
|
||||
let lineToOffsetsMap = script.getAllOffsets();
|
||||
|
||||
// Iterate over each line, and add their list of offsets to the map
|
||||
// from line numbers to entry points by forming a (script, offsets)
|
||||
// pair, where script is the current script, and offsets is the list
|
||||
// of offsets for the current line.
|
||||
for (let line = 0; line < lineToOffsetsMap.length; ++line) {
|
||||
let offsets = lineToOffsetsMap[line];
|
||||
if (offsets) {
|
||||
let entryPoints = lineToEntryPointsMap[line];
|
||||
if (!entryPoints) {
|
||||
// We dont have a list of entry points for the current line
|
||||
// number yet, so create it and add it to the map.
|
||||
entryPoints = [];
|
||||
lineToEntryPointsMap[line] = entryPoints;
|
||||
}
|
||||
entryPoints.push({ script, offsets });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let {
|
||||
originalSourceActor,
|
||||
originalLine,
|
||||
originalColumn
|
||||
} = originalLocation;
|
||||
|
||||
// Now that we have a map from line numbers to a list of entry points
|
||||
// for each line, we can use it to perform breakpoint sliding. Start
|
||||
// at the original line of the breakpoint actor, and keep incrementing
|
||||
// it by one, until either we find a line that has at least one entry
|
||||
// point, or we go past the last line in the map.
|
||||
//
|
||||
// Note that by computing the entire map up front, and implementing it
|
||||
// as a sparse array, we can easily tell when we went past the last line
|
||||
// in the map.
|
||||
let actualLine = originalLine;
|
||||
while (actualLine < lineToEntryPointsMap.length) {
|
||||
let entryPoints = lineToEntryPointsMap[actualLine];
|
||||
if (entryPoints) {
|
||||
setBreakpointForActorAtEntryPoints(actor, entryPoints);
|
||||
break;
|
||||
}
|
||||
++actualLine;
|
||||
}
|
||||
if (actualLine === lineToEntryPointsMap.length) {
|
||||
// We went past the last line in the map, so breakpoint sliding
|
||||
// failed. Keep the BreakpointActor in the BreakpointActorMap as a
|
||||
// pending breakpoint, so we can try again whenever a new script is
|
||||
// introduced.
|
||||
return Promise.resolve(actor);
|
||||
}
|
||||
|
||||
// If the actual line on which the BreakpointActor was set differs from
|
||||
// the original line that was requested, the BreakpointActor and the
|
||||
// BreakpointActorMap need to be updated accordingly.
|
||||
if (actualLine !== originalLine) {
|
||||
let actualLocation = new OriginalLocation(
|
||||
originalSourceActor,
|
||||
actualLine
|
||||
);
|
||||
let existingActor = this.breakpointActorMap.getActor(actualLocation);
|
||||
if (existingActor) {
|
||||
actor.onDelete();
|
||||
this.breakpointActorMap.deleteActor(originalLocation);
|
||||
actor = existingActor;
|
||||
} else {
|
||||
this.breakpointActorMap.deleteActor(originalLocation);
|
||||
actor.originalLocation = actualLocation;
|
||||
this.breakpointActorMap.setActor(actualLocation, actor);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve(actor);
|
||||
} else {
|
||||
// TODO: Implement breakpoint sliding for column breakpoints
|
||||
return Promise.resolve(actor);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -2841,8 +2955,79 @@ SourceActor.prototype = {
|
||||
* A GeneratedLocation representing the location in the generated
|
||||
* source for which the given BreakpointActor is to be set as a
|
||||
* breakpoint handler.
|
||||
*
|
||||
* @returns A Boolean that is true if the BreakpointActor was set as a
|
||||
* breakpoint handler on at least one script, and false otherwise.
|
||||
*/
|
||||
_setBreakpointForActorAtLocation: function (actor, generatedLocation) {
|
||||
let { generatedLine, generatedColumn } = generatedLocation;
|
||||
|
||||
// Find all scripts that match the given source actor and line number.
|
||||
let scripts = this.scripts.getScriptsBySourceActorAndLine(
|
||||
this,
|
||||
generatedLine
|
||||
).filter((script) => !actor.hasScript(script));
|
||||
|
||||
// Find all entry points that correspond to the given location.
|
||||
let entryPoints = [];
|
||||
if (generatedColumn === undefined) {
|
||||
// This is a line breakpoint, so we are interested in all offsets
|
||||
// that correspond to the given line number.
|
||||
for (let script of scripts) {
|
||||
let offsets = script.getLineOffsets(generatedLine);
|
||||
if (offsets.length > 0) {
|
||||
entryPoints.push({ script, offsets });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is a column breakpoint, so we are interested in all column
|
||||
// offsets that correspond to the given line *and* column number.
|
||||
for (let script of scripts) {
|
||||
let columnToOffsetMap = script.getAllColumnOffsets()
|
||||
.filter(({ lineNumber }) => {
|
||||
return lineNumber === generatedLine;
|
||||
});
|
||||
for (let { columnNumber: column, offset } of columnToOffsetMap) {
|
||||
// TODO: What we are actually interested in here is a range of
|
||||
// columns, rather than a single one.
|
||||
if (column == generatedColumn) {
|
||||
entryPoints.push({ script, offsets: [offset] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entryPoints.length === 0) {
|
||||
return false;
|
||||
}
|
||||
setBreakpointForActorAtEntryPoints(actor, entryPoints);
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
* Ensure the given BreakpointActor is set as breakpoint handler on all
|
||||
* scripts that match the given location in the generated source.
|
||||
*
|
||||
* TODO: This method is bugged, because it performs breakpoint sliding on
|
||||
* generated locations. Breakpoint sliding should be performed on original
|
||||
* locations, because there is no guarantee that the next line in the
|
||||
* generated source corresponds to the next line in an original source.
|
||||
*
|
||||
* The only place this method is still used is from setBreakpointForActor
|
||||
* when called for a source mapped source. Once that code has been refactored,
|
||||
* this method can be removed.
|
||||
*
|
||||
* @param BreakpointActor actor
|
||||
* The BreakpointActor to be set as a breakpoint handler.
|
||||
* @param GeneratedLocation generatedLocation
|
||||
* A GeneratedLocation representing the location in the generated
|
||||
* source for which the given BreakpointActor is to be set as a
|
||||
* breakpoint handler.
|
||||
*
|
||||
* @returns A Boolean that is true if the BreakpointActor was set as a
|
||||
* breakpoint handler on at least one script, and false otherwise.
|
||||
*/
|
||||
_setBreakpointForActorAtLocationWithSliding: function (actor, generatedLocation) {
|
||||
let originalLocation = actor.originalLocation;
|
||||
let { generatedLine, generatedColumn } = generatedLocation;
|
||||
|
||||
@ -2967,10 +3152,6 @@ SourceActor.prototype = {
|
||||
}
|
||||
actor.addScript(script, this.threadActor);
|
||||
}
|
||||
|
||||
return {
|
||||
actor: actor.actorID
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -79,6 +79,12 @@ ScriptStore.prototype = {
|
||||
return this._scripts.items;
|
||||
},
|
||||
|
||||
getScriptsBySourceActor(sourceActor) {
|
||||
return sourceActor.source ?
|
||||
this.getScriptsBySource(sourceActor.source) :
|
||||
this.getScriptsByURL(sourceActor._originalUrl);
|
||||
},
|
||||
|
||||
getScriptsBySourceActorAndLine(sourceActor, line) {
|
||||
return sourceActor.source ?
|
||||
this.getScriptsBySourceAndLine(sourceActor.source, line) :
|
||||
|
Loading…
Reference in New Issue
Block a user