зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound. a=merge
This commit is contained in:
Коммит
377a09c902
|
@ -22,6 +22,10 @@ const Cu = Components.utils;
|
|||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "settings",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
function debug(msg) {
|
||||
log(msg);
|
||||
}
|
||||
|
@ -89,14 +93,19 @@ ProcessGlobal.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
processWipeFile: function(text) {
|
||||
log("processWipeFile " + text);
|
||||
processCommandsFile: function(text) {
|
||||
log("processCommandsFile " + text);
|
||||
let lines = text.split("\n");
|
||||
lines.forEach((line) => {
|
||||
log(line);
|
||||
let params = line.split(" ");
|
||||
if (params[0] == "wipe") {
|
||||
this.wipeDir(params[1]);
|
||||
} else if (params[0] == "root") {
|
||||
log("unrestrict devtools");
|
||||
Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", false);
|
||||
let lock = settings.createLock();
|
||||
lock.set("developer.menu.enabled", true, null);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -113,7 +122,7 @@ ProcessGlobal.prototype = {
|
|||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(postResetFile);
|
||||
if (!file.exists()) {
|
||||
debug("Nothing to wipe.")
|
||||
debug("No additional command.")
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -122,7 +131,7 @@ ProcessGlobal.prototype = {
|
|||
(array) => {
|
||||
file.remove(false);
|
||||
let decoder = new TextDecoder();
|
||||
this.processWipeFile(decoder.decode(array));
|
||||
this.processCommandsFile(decoder.decode(array));
|
||||
},
|
||||
function onError(error) {
|
||||
debug("Error: " + error);
|
||||
|
|
|
@ -81,19 +81,24 @@ RecoveryService.prototype = {
|
|||
}
|
||||
|
||||
log("factoryReset " + reason);
|
||||
let commands = [];
|
||||
if (reason == "wipe") {
|
||||
let volumeService = Cc["@mozilla.org/telephony/volume-service;1"]
|
||||
.getService(Ci.nsIVolumeService);
|
||||
let volNames = volumeService.getVolumeNames();
|
||||
log("Found " + volNames.length + " volumes");
|
||||
let text = "";
|
||||
|
||||
for (let i = 0; i < volNames.length; i++) {
|
||||
let name = volNames.queryElementAt(i, Ci.nsISupportsString);
|
||||
let volume = volumeService.getVolumeByName(name.data);
|
||||
log("Got volume: " + name.data + " at " + volume.mountPoint);
|
||||
text += "wipe " + volume.mountPoint + "\n";
|
||||
commands.push("wipe " + volume.mountPoint);
|
||||
}
|
||||
} else if (reason == "root") {
|
||||
commands.push("root");
|
||||
}
|
||||
|
||||
if (commands.length > 0) {
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
dir.initWithPath("/persist");
|
||||
|
@ -101,6 +106,7 @@ RecoveryService.prototype = {
|
|||
OS.Path.join("/persist", gFactoryResetFile):
|
||||
OS.Path.join("/cache", gFactoryResetFile);
|
||||
let encoder = new TextEncoder();
|
||||
let text = commands.join("\n");
|
||||
let array = encoder.encode(text);
|
||||
let promise = OS.File.writeAtomic(postResetFile, array,
|
||||
{ tmpPath: postResetFile + ".tmp" });
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -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="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a3e4614c7fb0a6ffa8c748bf5d49b34612c9d6d4"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -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="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a3e4614c7fb0a6ffa8c748bf5d49b34612c9d6d4"/>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "5f064a62ce5ee63c6f75ff3422a7472bec71f7bf",
|
||||
"revision": "0d6dca3dab03252cef2eb22079d0cab6362eda1e",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,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="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
|
|
|
@ -15,7 +15,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="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a3e4614c7fb0a6ffa8c748bf5d49b34612c9d6d4"/>
|
||||
|
|
|
@ -17,7 +17,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="6cfde14a9fc87659963092a6b9d7898a8c23ec74"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="bd4dcc8c4582e2368b47b0e62506d3031fb2fc09"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -346,6 +346,7 @@ let LoopRoomsInternal = {
|
|||
.then(response => {
|
||||
this.rooms.delete(roomToken);
|
||||
eventEmitter.emit("delete", room);
|
||||
eventEmitter.emit("delete:" + room.roomToken, room);
|
||||
callback(null, room);
|
||||
}, error => callback(error)).catch(error => callback(error));
|
||||
},
|
||||
|
|
|
@ -211,6 +211,8 @@ loop.store.ActiveRoomStore = (function() {
|
|||
|
||||
this._mozLoop.rooms.on("update:" + actionData.roomToken,
|
||||
this._handleRoomUpdate.bind(this));
|
||||
this._mozLoop.rooms.on("delete:" + actionData.roomToken,
|
||||
this._handleRoomDelete.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -230,6 +232,8 @@ loop.store.ActiveRoomStore = (function() {
|
|||
|
||||
this._mozLoop.rooms.on("update:" + actionData.roomToken,
|
||||
this._handleRoomUpdate.bind(this));
|
||||
this._mozLoop.rooms.on("delete:" + actionData.roomToken,
|
||||
this._handleRoomDelete.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -259,6 +263,18 @@ loop.store.ActiveRoomStore = (function() {
|
|||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the deletion of a room, notified by the mozLoop rooms API.
|
||||
*
|
||||
* @param {String} eventName The name of the event
|
||||
* @param {Object} roomData The roomData of the deleted room
|
||||
*/
|
||||
_handleRoomDelete: function(eventName, roomData) {
|
||||
this._sdkDriver.forceDisconnectAll(function() {
|
||||
window.close();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action to join to a room.
|
||||
*/
|
||||
|
@ -391,7 +407,9 @@ loop.store.ActiveRoomStore = (function() {
|
|||
this._leaveRoom(ROOM_STATES.CLOSING);
|
||||
|
||||
// If we're closing the window, we can stop listening to updates.
|
||||
this._mozLoop.rooms.off("update:" + this.getStoreState().roomToken);
|
||||
var roomToken = this.getStoreState().roomToken;
|
||||
this._mozLoop.rooms.off("update:" + roomToken);
|
||||
this._mozLoop.rooms.off("delete:" + roomToken);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,8 @@ loop.OTSdkDriver = (function() {
|
|||
this.dispatcher = options.dispatcher;
|
||||
this.sdk = options.sdk;
|
||||
|
||||
this.connections = {};
|
||||
|
||||
this.dispatcher.register(this, [
|
||||
"setupStreamElements",
|
||||
"setMute"
|
||||
|
@ -115,6 +117,38 @@ loop.OTSdkDriver = (function() {
|
|||
delete this._publisherReady;
|
||||
delete this._publishedLocalStream;
|
||||
delete this._subscribedRemoteStream;
|
||||
this.connections = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Oust all users from an ongoing session. This is typically done when a room
|
||||
* owner deletes the room.
|
||||
*
|
||||
* @param {Function} callback Function to be invoked once all connections are
|
||||
* ousted
|
||||
*/
|
||||
forceDisconnectAll: function(callback) {
|
||||
if (!this._sessionConnected) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var connectionNames = Object.keys(this.connections);
|
||||
if (connectionNames.length === 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
var disconnectCount = 0;
|
||||
connectionNames.forEach(function(id) {
|
||||
var connection = this.connections[id];
|
||||
this.session.forceDisconnect(connection, function() {
|
||||
// When all connections have disconnected, call the callback, since
|
||||
// we're done.
|
||||
if (++disconnectCount === connectionNames.length) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -139,10 +173,14 @@ loop.OTSdkDriver = (function() {
|
|||
/**
|
||||
* Handles the connection event for a peer's connection being dropped.
|
||||
*
|
||||
* @param {SessionDisconnectEvent} event The event details
|
||||
* https://tokbox.com/opentok/libraries/client/js/reference/SessionDisconnectEvent.html
|
||||
* @param {ConnectionEvent} event The event details
|
||||
* https://tokbox.com/opentok/libraries/client/js/reference/ConnectionEvent.html
|
||||
*/
|
||||
_onConnectionDestroyed: function(event) {
|
||||
var connection = event.connection;
|
||||
if (connection && (connection.id in this.connections)) {
|
||||
delete this.connections[connection.id];
|
||||
}
|
||||
this.dispatcher.dispatch(new sharedActions.RemotePeerDisconnected({
|
||||
peerHungup: event.reason === "clientDisconnected"
|
||||
}));
|
||||
|
@ -164,11 +202,18 @@ loop.OTSdkDriver = (function() {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the connection event for a newly connecting peer.
|
||||
*
|
||||
* @param {ConnectionEvent} event The event details
|
||||
* https://tokbox.com/opentok/libraries/client/js/reference/ConnectionEvent.html
|
||||
*/
|
||||
_onConnectionCreated: function(event) {
|
||||
if (this.session.connection.id === event.connection.id) {
|
||||
var connection = event.connection;
|
||||
if (this.session.connection.id === connection.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.connections[connection.id] = connection;
|
||||
this.dispatcher.dispatch(new sharedActions.RemotePeerConnected());
|
||||
},
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
|
||||
fakeSdkDriver = {
|
||||
connectSession: sandbox.stub(),
|
||||
disconnectSession: sandbox.stub()
|
||||
disconnectSession: sandbox.stub(),
|
||||
forceDisconnectAll: sandbox.stub().callsArg(0)
|
||||
};
|
||||
|
||||
fakeMultiplexGum = {
|
||||
|
@ -740,7 +741,7 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
});
|
||||
|
||||
it("should dispatch an UpdateRoomInfo action", function() {
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.on);
|
||||
sinon.assert.calledTwice(fakeMozLoop.rooms.on);
|
||||
|
||||
var fakeRoomData = {
|
||||
roomName: "fakeName",
|
||||
|
@ -755,5 +756,30 @@ describe("loop.store.ActiveRoomStore", function () {
|
|||
new sharedActions.UpdateRoomInfo(fakeRoomData));
|
||||
});
|
||||
});
|
||||
|
||||
describe("delete:{roomToken}", function() {
|
||||
var fakeRoomData = {
|
||||
roomName: "Its a room",
|
||||
roomOwner: "Me",
|
||||
roomToken: "fakeToken",
|
||||
roomUrl: "http://invalid"
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
store.setupRoomInfo(new sharedActions.SetupRoomInfo(fakeRoomData));
|
||||
});
|
||||
|
||||
it("should disconnect all room connections", function() {
|
||||
fakeMozLoop.rooms.on.callArgWith(1, "delete:" + fakeRoomData.roomToken, fakeRoomData);
|
||||
|
||||
sinon.assert.calledOnce(fakeSdkDriver.forceDisconnectAll);
|
||||
});
|
||||
|
||||
it("should not disconnect anything when another room is deleted", function() {
|
||||
fakeMozLoop.rooms.on.callArgWith(1, "delete:invalidToken", fakeRoomData);
|
||||
|
||||
sinon.assert.calledOnce(fakeSdkDriver.forceDisconnectAll);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,7 +34,8 @@ describe("loop.OTSdkDriver", function () {
|
|||
connect: sinon.stub(),
|
||||
disconnect: sinon.stub(),
|
||||
publish: sinon.stub(),
|
||||
subscribe: sinon.stub()
|
||||
subscribe: sinon.stub(),
|
||||
forceDisconnect: sinon.stub()
|
||||
}, Backbone.Events);
|
||||
|
||||
publisher = _.extend({
|
||||
|
@ -175,6 +176,43 @@ describe("loop.OTSdkDriver", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#forceDisconnectAll", function() {
|
||||
it("should not disconnect anything when not connected", function() {
|
||||
driver.session = session;
|
||||
driver.forceDisconnectAll(function() {});
|
||||
|
||||
sinon.assert.notCalled(session.forceDisconnect);
|
||||
});
|
||||
|
||||
it("should disconnect all remote connections when called", function() {
|
||||
driver.connectSession(sessionData);
|
||||
sinon.assert.calledOnce(session.connect);
|
||||
driver._sessionConnected = true;
|
||||
|
||||
// Setup the right state in the driver to make `forceDisconnectAll` do
|
||||
// something.
|
||||
session.connection = {
|
||||
id: "localUser"
|
||||
};
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "remoteUser"}
|
||||
});
|
||||
expect(driver.connections).to.include.keys("remoteUser");
|
||||
|
||||
driver.forceDisconnectAll(function() {});
|
||||
sinon.assert.calledOnce(session.forceDisconnect);
|
||||
|
||||
// Add another remote connection.
|
||||
session.trigger("connectionCreated", {
|
||||
connection: {id: "remoteUser2"}
|
||||
});
|
||||
expect(driver.connections).to.include.keys("remoteUser", "remoteUser2");
|
||||
|
||||
driver.forceDisconnectAll(function() {});
|
||||
sinon.assert.calledThrice(session.forceDisconnect);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Events", function() {
|
||||
beforeEach(function() {
|
||||
driver.connectSession(sessionData);
|
||||
|
@ -275,6 +313,9 @@ describe("loop.OTSdkDriver", function () {
|
|||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.RemotePeerConnected());
|
||||
it("should store the connection details for a remote user", function() {
|
||||
expect(driver.connections).to.include.keys("remoteUser");
|
||||
});
|
||||
});
|
||||
|
||||
it("should not dispatch an action if this is for a local user",
|
||||
|
@ -284,6 +325,9 @@ describe("loop.OTSdkDriver", function () {
|
|||
});
|
||||
|
||||
sinon.assert.notCalled(dispatcher.dispatch);
|
||||
it("should not store the connection details for a local user", function() {
|
||||
expect(driver.connections).to.not.include.keys("localUser");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ devtools.lazyRequireGetter(this, "DevToolsUtils",
|
|||
"devtools/toolkit/DevToolsUtils");
|
||||
devtools.lazyRequireGetter(this, "L10N",
|
||||
"devtools/profiler/global", true);
|
||||
devtools.lazyRequireGetter(this, "FramerateFront",
|
||||
"devtools/server/actors/framerate", true);
|
||||
devtools.lazyRequireGetter(this, "Waterfall",
|
||||
"devtools/timeline/waterfall", true);
|
||||
devtools.lazyRequireGetter(this, "MarkerDetails",
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const OVERVIEW_UPDATE_INTERVAL = 100;
|
||||
const FRAMERATE_CALC_INTERVAL = 16; // ms
|
||||
// No sense updating the overview more often than receiving data from the
|
||||
// backend. Make sure this isn't lower than DEFAULT_TIMELINE_DATA_PULL_TIMEOUT
|
||||
// in toolkit/devtools/server/actors/timeline.js
|
||||
const OVERVIEW_UPDATE_INTERVAL = 200; // ms
|
||||
|
||||
const FRAMERATE_GRAPH_HEIGHT = 60; // px
|
||||
const GRAPH_SCROLL_EVENTS_DRAIN = 50; // ms
|
||||
|
||||
|
@ -13,11 +16,10 @@ const GRAPH_SCROLL_EVENTS_DRAIN = 50; // ms
|
|||
* framerate over time.
|
||||
*/
|
||||
let OverviewView = {
|
||||
|
||||
/**
|
||||
* Sets up the view with event binding.
|
||||
*/
|
||||
initialize: function () {
|
||||
initialize: Task.async(function *() {
|
||||
this._framerateEl = $("#time-framerate");
|
||||
this._ticksData = [];
|
||||
|
||||
|
@ -28,14 +30,14 @@ let OverviewView = {
|
|||
this._onGraphMouseUp = this._onGraphMouseUp.bind(this);
|
||||
this._onGraphScroll = this._onGraphScroll.bind(this);
|
||||
|
||||
this._initializeFramerateGraph();
|
||||
yield this._initializeFramerateGraph();
|
||||
|
||||
this.framerateGraph.on("mouseup", this._onGraphMouseUp);
|
||||
this.framerateGraph.on("scroll", this._onGraphScroll);
|
||||
PerformanceController.on(EVENTS.RECORDING_STARTED, this._start);
|
||||
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._stop);
|
||||
PerformanceController.on(EVENTS.TIMELINE_DATA, this._onTimelineData);
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Unbinds events.
|
||||
|
@ -55,9 +57,13 @@ let OverviewView = {
|
|||
* data into all the corresponding overview graphs.
|
||||
*/
|
||||
_onRecordingTick: Task.async(function *() {
|
||||
yield this.framerateGraph.setDataWhenReady(this._ticksData);
|
||||
// The `ticks` event on the TimelineFront returns all ticks for the
|
||||
// recording session, so just convert to plottable values and draw.
|
||||
let [, timestamps] = this._ticksData;
|
||||
yield this.framerateGraph.setDataFromTimestamps(timestamps);
|
||||
|
||||
this.emit(EVENTS.OVERVIEW_RENDERED);
|
||||
this._draw();
|
||||
this._prepareNextTick();
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -94,20 +100,21 @@ let OverviewView = {
|
|||
/**
|
||||
* Sets up the framerate graph.
|
||||
*/
|
||||
_initializeFramerateGraph: function () {
|
||||
_initializeFramerateGraph: Task.async(function *() {
|
||||
let graph = new LineGraphWidget(this._framerateEl, L10N.getStr("graphs.fps"));
|
||||
graph.minDistanceBetweenPoints = 1;
|
||||
graph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
|
||||
graph.selectionEnabled = false;
|
||||
this.framerateGraph = graph;
|
||||
},
|
||||
|
||||
yield graph.ready();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called to refresh the timer to keep firing _onRecordingTick.
|
||||
*/
|
||||
_draw: function () {
|
||||
_prepareNextTick: function () {
|
||||
// Check here to see if there's still a _timeoutId, incase
|
||||
// `stop` was called before the _draw call was executed.
|
||||
// `stop` was called before the _prepareNextTick call was executed.
|
||||
if (this._timeoutId) {
|
||||
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
|
||||
}
|
||||
|
@ -134,11 +141,7 @@ let OverviewView = {
|
|||
*/
|
||||
_onTimelineData: function (_, eventName, ...data) {
|
||||
if (eventName === "ticks") {
|
||||
let [delta, timestamps] = data;
|
||||
// the `ticks` event on the TimelineFront returns all ticks for the
|
||||
// recording session, so just convert to plottable values
|
||||
// and store.
|
||||
this._ticksData = FramerateFront.plotFPS(timestamps, FRAMERATE_CALC_INTERVAL);
|
||||
this._ticksData = data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -394,7 +394,6 @@ let ProfileView = {
|
|||
|
||||
let graph = new LineGraphWidget($(".framerate", panel), L10N.getStr("graphs.fps"));
|
||||
graph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
|
||||
graph.minDistanceBetweenPoints = 1;
|
||||
graph.dataOffsetX = beginAt;
|
||||
|
||||
yield graph.setDataWhenReady(framerateData);
|
||||
|
|
|
@ -23,6 +23,7 @@ EXTRA_JS_MODULES.devtools += [
|
|||
'widgets/BreadcrumbsWidget.jsm',
|
||||
'widgets/Chart.jsm',
|
||||
'widgets/Graphs.jsm',
|
||||
'widgets/GraphsWorker.js',
|
||||
'widgets/SideMenuWidget.jsm',
|
||||
'widgets/SimpleListWidget.jsm',
|
||||
'widgets/VariablesView.jsm',
|
||||
|
|
|
@ -19,6 +19,7 @@ this.EXPORTED_SYMBOLS = [
|
|||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml";
|
||||
const WORKER_URL = "resource:///modules/devtools/GraphsWorker.js";
|
||||
const L10N = new ViewHelpers.L10N();
|
||||
|
||||
// Generic constants.
|
||||
|
@ -44,7 +45,7 @@ const GRAPH_STRIPE_PATTERN_LINE_SPACING = 4; // px
|
|||
// Line graph constants.
|
||||
|
||||
const LINE_GRAPH_DAMPEN_VALUES = 0.85;
|
||||
const LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS = 400; // 20 px
|
||||
const LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS = 1; // px
|
||||
const LINE_GRAPH_TOOLTIP_SAFE_BOUNDS = 8; // px
|
||||
const LINE_GRAPH_MIN_MAX_TOOLTIP_DISTANCE = 14; // px
|
||||
|
||||
|
@ -92,10 +93,10 @@ const BAR_GRAPH_LEGEND_MOUSEOVER_DEBOUNCE = 50; // ms
|
|||
/**
|
||||
* Small data primitives for all graphs.
|
||||
*/
|
||||
this.GraphCursor = function() {}
|
||||
this.GraphSelection = function() {}
|
||||
this.GraphSelectionDragger = function() {}
|
||||
this.GraphSelectionResizer = function() {}
|
||||
this.GraphCursor = function() {};
|
||||
this.GraphSelection = function() {};
|
||||
this.GraphSelectionDragger = function() {};
|
||||
this.GraphSelectionResizer = function() {};
|
||||
|
||||
GraphCursor.prototype = {
|
||||
x: null,
|
||||
|
@ -206,7 +207,7 @@ this.AbstractCanvasGraph = function(parent, name, sharpness) {
|
|||
this._ready.resolve(this);
|
||||
this.emit("ready", this);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
AbstractCanvasGraph.prototype = {
|
||||
/**
|
||||
|
@ -895,7 +896,7 @@ AbstractCanvasGraph.prototype = {
|
|||
while (node = node.offsetParent) {
|
||||
x += node.offsetLeft;
|
||||
y += node.offsetTop;
|
||||
};
|
||||
}
|
||||
|
||||
return { left: x, top: y };
|
||||
},
|
||||
|
@ -1178,7 +1179,7 @@ this.LineGraphWidget = function(parent, metric, ...args) {
|
|||
this._avgTooltip = this._createTooltip("average", "end", "avg", metric);
|
||||
this._minTooltip = this._createTooltip("minimum", "start", "min", metric);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
backgroundColor: LINE_GRAPH_BACKGROUND_COLOR,
|
||||
|
@ -1211,7 +1212,7 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
* Points that are too close too each other in the graph will not be rendered.
|
||||
* This scalar specifies the required minimum squared distance between points.
|
||||
*/
|
||||
minDistanceBetweenPoints: LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS,
|
||||
minSquaredDistanceBetweenPoints: LINE_GRAPH_MIN_SQUARED_DISTANCE_BETWEEN_POINTS,
|
||||
|
||||
/**
|
||||
* Specifies if min/max/avg tooltips have arrow handlers on their sides.
|
||||
|
@ -1224,6 +1225,36 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
*/
|
||||
withFixedTooltipPositions: false,
|
||||
|
||||
/**
|
||||
* Takes a list of numbers and plots them on a line graph representing
|
||||
* the rate of occurences in a specified interval. Useful for drawing
|
||||
* framerate, for example, from a sequence of timestamps.
|
||||
*
|
||||
* @param array timestamps
|
||||
* A list of numbers representing time, ordered ascending. For example,
|
||||
* this can be the raw data received from the framerate actor, which
|
||||
* represents the elapsed time on each refresh driver tick.
|
||||
* @param number interval
|
||||
* The maximum amount of time to wait between calculations.
|
||||
*/
|
||||
setDataFromTimestamps: Task.async(function*(timestamps, interval) {
|
||||
let {
|
||||
plottedData,
|
||||
plottedMinMaxSum
|
||||
} = yield CanvasGraphUtils._performTaskInWorker("plotTimestampsGraph", {
|
||||
width: this._width,
|
||||
height: this._height,
|
||||
dataOffsetX: this.dataOffsetX,
|
||||
dampenValuesFactor: this.dampenValuesFactor,
|
||||
minSquaredDistanceBetweenPoints: this.minSquaredDistanceBetweenPoints,
|
||||
timestamps: timestamps,
|
||||
interval: interval
|
||||
});
|
||||
|
||||
this._tempMinMaxSum = plottedMinMaxSum;
|
||||
this.setData(plottedData);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Renders the graph's data source.
|
||||
* @see AbstractCanvasGraph.prototype.buildGraphImage
|
||||
|
@ -1238,31 +1269,37 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
let lastTick = totalTicks ? this._data[totalTicks - 1].delta : 0;
|
||||
let maxValue = Number.MIN_SAFE_INTEGER;
|
||||
let minValue = Number.MAX_SAFE_INTEGER;
|
||||
let sumValues = 0;
|
||||
let avgValue = 0;
|
||||
let forceDrawAllPoints = false;
|
||||
|
||||
if (this._tempMinMaxSum) {
|
||||
maxValue = this._tempMinMaxSum.maxValue;
|
||||
minValue = this._tempMinMaxSum.minValue;
|
||||
avgValue = this._tempMinMaxSum.avgValue;
|
||||
// If we use cached `minValue`, `maxValue`, `avgValue` then we can assume
|
||||
// that we've already removed points that did not meet the
|
||||
// `minSquaredDistanceBetweenPoints` requirement.
|
||||
forceDrawAllPoints = true;
|
||||
} else {
|
||||
let sumValues = 0;
|
||||
for (let { delta, value } of this._data) {
|
||||
maxValue = Math.max(value, maxValue);
|
||||
minValue = Math.min(value, minValue);
|
||||
sumValues += value;
|
||||
}
|
||||
avgValue = sumValues / totalTicks;
|
||||
}
|
||||
|
||||
let dataScaleX = this.dataScaleX = width / (lastTick - this.dataOffsetX);
|
||||
let dataScaleY = this.dataScaleY = height / maxValue * this.dampenValuesFactor;
|
||||
|
||||
/**
|
||||
* Calculates the squared distance between two 2D points.
|
||||
*/
|
||||
function distSquared(x0, y0, x1, y1) {
|
||||
let xs = x1 - x0;
|
||||
let ys = y1 - y0;
|
||||
return xs * xs + ys * ys;
|
||||
}
|
||||
|
||||
// Draw the graph.
|
||||
// Draw the background.
|
||||
|
||||
ctx.fillStyle = this.backgroundColor;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
// Draw the graph.
|
||||
|
||||
let gradient = ctx.createLinearGradient(0, height / 2, 0, height);
|
||||
gradient.addColorStop(0, this.backgroundGradientStart);
|
||||
gradient.addColorStop(1, this.backgroundGradientEnd);
|
||||
|
@ -1273,6 +1310,7 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
|
||||
let prevX = 0;
|
||||
let prevY = 0;
|
||||
let minSqDist = this.minSquaredDistanceBetweenPoints;
|
||||
|
||||
for (let { delta, value } of this._data) {
|
||||
let currX = (delta - this.dataOffsetX) * dataScaleX;
|
||||
|
@ -1283,8 +1321,7 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
ctx.lineTo(-LINE_GRAPH_STROKE_WIDTH, currY);
|
||||
}
|
||||
|
||||
let distance = distSquared(prevX, prevY, currX, currY);
|
||||
if (distance >= this.minDistanceBetweenPoints) {
|
||||
if (forceDrawAllPoints || distSquared(prevX, prevY, currX, currY) >= minSqDist) {
|
||||
ctx.lineTo(currX, currY);
|
||||
prevX = currX;
|
||||
prevY = currY;
|
||||
|
@ -1299,6 +1336,26 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
this._drawOverlays(ctx, minValue, maxValue, avgValue, dataScaleY);
|
||||
|
||||
return canvas;
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws the min, max and average horizontal lines, along with their
|
||||
* repsective tooltips.
|
||||
*
|
||||
* @param CanvasRenderingContext2D ctx
|
||||
* @param number minValue
|
||||
* @param number maxValue
|
||||
* @param number avgValue
|
||||
* @param number dataScaleY
|
||||
*/
|
||||
_drawOverlays: function(ctx, minValue, maxValue, avgValue, dataScaleY) {
|
||||
let width = this._width;
|
||||
let height = this._height;
|
||||
let totalTicks = this._data.length;
|
||||
|
||||
// Draw the maximum value horizontal line.
|
||||
|
||||
ctx.strokeStyle = this.maximumLineColor;
|
||||
|
@ -1316,7 +1373,6 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
|
||||
ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
|
||||
ctx.beginPath();
|
||||
let avgValue = totalTicks ? sumValues / totalTicks : 0;
|
||||
let averageY = height - avgValue * dataScaleY;
|
||||
ctx.moveTo(0, averageY);
|
||||
ctx.lineTo(width, averageY);
|
||||
|
@ -1342,15 +1398,6 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
this._minTooltip.querySelector("[text=value]").textContent =
|
||||
L10N.numberWithDecimals(minValue, 2);
|
||||
|
||||
/**
|
||||
* Constrains a value to a range.
|
||||
*/
|
||||
function clamp(value, min, max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
let bottom = height / this._pixelRatio;
|
||||
let maxPosY = map(maxValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
|
||||
let avgPosY = map(avgValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
|
||||
|
@ -1384,8 +1431,6 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
this._minTooltip.hidden = !totalTicks;
|
||||
|
||||
this._gutter.hidden = !this.withTooltipArrows;
|
||||
|
||||
return canvas;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1445,7 +1490,6 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* A bar graph, plotting tuples of values as rectangles.
|
||||
*
|
||||
|
@ -1501,7 +1545,7 @@ this.BarGraphWidget = function(parent, ...args) {
|
|||
}
|
||||
this.outstandingEventListeners = null;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
clipheadLineColor: BAR_GRAPH_CLIPHEAD_LINE_COLOR,
|
||||
|
@ -1955,6 +1999,9 @@ const gCachedStripePattern = new Map();
|
|||
* Utility functions for graph canvases.
|
||||
*/
|
||||
this.CanvasGraphUtils = {
|
||||
_graphUtilsWorker: null,
|
||||
_graphUtilsTaskId: 0,
|
||||
|
||||
/**
|
||||
* Merges the animation loop of two graphs.
|
||||
*/
|
||||
|
@ -2004,6 +2051,47 @@ this.CanvasGraphUtils = {
|
|||
graph2.on("deselecting", () => {
|
||||
graph1.dropSelection();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs the given task in a chrome worker, assuming it exists.
|
||||
*
|
||||
* @param string task
|
||||
* The task name. Currently supported: "plotTimestampsGraph".
|
||||
* @param any args
|
||||
* Extra arguments to pass to the worker.
|
||||
* @param array transferrable [optional]
|
||||
* A list of transferrable objects, if any.
|
||||
* @return object
|
||||
* A promise that is resolved once the worker finishes the task.
|
||||
*/
|
||||
_performTaskInWorker: function(task, args, transferrable) {
|
||||
let worker = this._graphUtilsWorker || new ChromeWorker(WORKER_URL);
|
||||
let id = this._graphUtilsTaskId++;
|
||||
worker.postMessage({ task, id, args }, transferrable);
|
||||
return this._waitForWorkerResponse(worker, id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Waits for the specified worker to finish a task.
|
||||
*
|
||||
* @param ChromeWorker worker
|
||||
* The worker for which to add a message listener.
|
||||
* @param number id
|
||||
* The worker task id.
|
||||
*/
|
||||
_waitForWorkerResponse: function(worker, id) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
worker.addEventListener("message", function listener({ data }) {
|
||||
if (data.id != id) {
|
||||
return;
|
||||
}
|
||||
worker.removeEventListener("message", listener);
|
||||
deferred.resolve(data);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2016,6 +2104,26 @@ function map(value, istart, istop, ostart, ostop) {
|
|||
return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains a value to a range.
|
||||
* @param number value, min, max
|
||||
* @return number
|
||||
*/
|
||||
function clamp(value, min, max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the squared distance between two 2D points.
|
||||
*/
|
||||
function distSquared(x0, y0, x1, y1) {
|
||||
let xs = x1 - x0;
|
||||
let ys = y1 - y0;
|
||||
return xs * xs + ys * ys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first element in an array that validates a predicate.
|
||||
* @param array
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
self.onmessage = e => {
|
||||
const { id, task, args } = e.data;
|
||||
|
||||
switch (task) {
|
||||
case "plotTimestampsGraph":
|
||||
plotTimestampsGraph(id, args);
|
||||
break;
|
||||
default:
|
||||
self.postMessage({ id, error: e.message + "\n" + e.stack });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @see LineGraphWidget.prototype.setDataFromTimestamps in Graphs.jsm
|
||||
* @param number id
|
||||
* @param number width
|
||||
* @param number height
|
||||
* @param array timestamps
|
||||
* @param number interval
|
||||
*/
|
||||
function plotTimestampsGraph(id, args) {
|
||||
let plottedData = plotTimestamps(args.timestamps, args.interval);
|
||||
let plottedMinMaxSum = getMinMaxSum(plottedData);
|
||||
let sparsifiedData = sparsifyLineData(plottedData, plottedMinMaxSum, args);
|
||||
|
||||
let response = { id, plottedData: sparsifiedData, plottedMinMaxSum };
|
||||
self.postMessage(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the min, max and average of the values in an array.
|
||||
* @param array source
|
||||
* @return object
|
||||
*/
|
||||
function getMinMaxSum(source) {
|
||||
let totalTicks = source.length;
|
||||
let maxValue = Number.MIN_SAFE_INTEGER;
|
||||
let minValue = Number.MAX_SAFE_INTEGER;
|
||||
let avgValue = 0;
|
||||
let sumValues = 0;
|
||||
|
||||
for (let { value } of source) {
|
||||
maxValue = Math.max(value, maxValue);
|
||||
minValue = Math.min(value, minValue);
|
||||
sumValues += value;
|
||||
}
|
||||
avgValue = sumValues / totalTicks;
|
||||
|
||||
return { minValue, maxValue, avgValue };
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a data source for a line graph, based off of a minimum distance
|
||||
* between the points to render.
|
||||
*/
|
||||
function sparsifyLineData(plottedData, plottedMinMaxSum, options) {
|
||||
let { width: graphWidth, height: graphHeight } = options;
|
||||
let { dataOffsetX, dampenValuesFactor } = options;
|
||||
let { minSquaredDistanceBetweenPoints } = options;
|
||||
|
||||
let result = [];
|
||||
|
||||
let totalTicks = plottedData.length;
|
||||
let maxValue = plottedMinMaxSum.maxValue;
|
||||
|
||||
let firstTick = totalTicks ? plottedData[0].delta : 0;
|
||||
let lastTick = totalTicks ? plottedData[totalTicks - 1].delta : 0;
|
||||
let dataScaleX = graphWidth / (lastTick - dataOffsetX);
|
||||
let dataScaleY = graphHeight / maxValue * dampenValuesFactor;
|
||||
|
||||
let prevX = 0;
|
||||
let prevY = 0;
|
||||
|
||||
for (let { delta, value } of plottedData) {
|
||||
let currX = (delta - dataOffsetX) * dataScaleX;
|
||||
let currY = graphHeight - value * dataScaleY;
|
||||
|
||||
if (delta == firstTick || delta == lastTick) {
|
||||
result.push({ delta, value });
|
||||
continue;
|
||||
}
|
||||
|
||||
let dist = distSquared(prevX, prevY, currX, currY);
|
||||
if (dist >= minSquaredDistanceBetweenPoints) {
|
||||
result.push({ delta, value });
|
||||
prevX = currX;
|
||||
prevY = currY;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of numbers and plots them on a line graph representing
|
||||
* the rate of occurences in a specified interval.
|
||||
*
|
||||
* XXX: Copied almost verbatim from toolkit/devtools/server/actors/framerate.js
|
||||
* Remove that dead code after the Performance panel lands, bug 1075567.
|
||||
*
|
||||
* @param array timestamps
|
||||
* A list of numbers representing time, ordered ascending. For example,
|
||||
* this can be the raw data received from the framerate actor, which
|
||||
* represents the elapsed time on each refresh driver tick.
|
||||
* @param number interval
|
||||
* The maximum amount of time to wait between calculations.
|
||||
* @param number clamp
|
||||
* The maximum allowed value.
|
||||
* @return array
|
||||
* A collection of { delta, value } objects representing the
|
||||
* plotted value at every delta time.
|
||||
*/
|
||||
function plotTimestamps(timestamps, interval = 100, clamp = 60) {
|
||||
let timeline = [];
|
||||
let totalTicks = timestamps.length;
|
||||
|
||||
// If the refresh driver didn't get a chance to tick before the
|
||||
// recording was stopped, assume rate was 0.
|
||||
if (totalTicks == 0) {
|
||||
timeline.push({ delta: 0, value: 0 });
|
||||
timeline.push({ delta: interval, value: 0 });
|
||||
return timeline;
|
||||
}
|
||||
|
||||
let frameCount = 0;
|
||||
let prevTime = +timestamps[0];
|
||||
|
||||
for (let i = 1; i < totalTicks; i++) {
|
||||
let currTime = +timestamps[i];
|
||||
frameCount++;
|
||||
|
||||
let elapsedTime = currTime - prevTime;
|
||||
if (elapsedTime < interval) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let rate = Math.min(1000 / (elapsedTime / frameCount), clamp);
|
||||
timeline.push({ delta: prevTime, value: rate });
|
||||
timeline.push({ delta: currTime, value: rate });
|
||||
|
||||
frameCount = 0;
|
||||
prevTime = currTime;
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the squared distance between two 2D points.
|
||||
*/
|
||||
function distSquared(x0, y0, x1, y1) {
|
||||
let xs = x1 - x0;
|
||||
let ys = y1 - y0;
|
||||
return xs * xs + ys * ys;
|
||||
}
|
|
@ -3,20 +3,26 @@
|
|||
* 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/. */
|
||||
|
||||
/* CSS Variables specific to this panel that aren't defined by the themes */
|
||||
.theme-dark {
|
||||
--cell-border-color: rgba(255,255,255,0.15);
|
||||
--focus-cell-border-color: rgba(255,255,255,0.5);
|
||||
--row-alt-background-color: rgba(29,79,115,0.15);
|
||||
--row-hover-background-color: rgba(29,79,115,0.25);
|
||||
}
|
||||
|
||||
.theme-light {
|
||||
--cell-border-color: rgba(0,0,0,0.15);
|
||||
--focus-cell-border-color: rgba(0,0,0,0.3);
|
||||
--row-alt-background-color: rgba(76,158,217,0.1);
|
||||
--row-hover-background-color: rgba(76,158,217,0.2);
|
||||
}
|
||||
|
||||
/* Toolbar */
|
||||
|
||||
#performance-toolbar > tabs,
|
||||
#performance-toolbar {
|
||||
-moz-border-end: 1px solid;
|
||||
}
|
||||
|
||||
.theme-dark #performance-toolbar > tabs,
|
||||
.theme-dark #performance-toolbar {
|
||||
-moz-border-end-color: #000; /* Splitters */
|
||||
}
|
||||
|
||||
.theme-light #performance-toolbar > tabs,
|
||||
.theme-light #performance-toolbar {
|
||||
-moz-border-end-color: #aaa; /* Splitters */
|
||||
-moz-border-end-color: var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
/* Overview Panel */
|
||||
|
@ -85,23 +91,14 @@
|
|||
-moz-box-align: center;
|
||||
overflow: hidden;
|
||||
padding: 1px 4px;
|
||||
color: var(--theme-body-color);
|
||||
-moz-border-end-color: var(--cell-border-color);
|
||||
}
|
||||
|
||||
.call-tree-header:not(:last-child),
|
||||
.call-tree-cell:not(:last-child) {
|
||||
-moz-border-end: 1px solid;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-header,
|
||||
.theme-dark .call-tree-cell {
|
||||
-moz-border-end-color: rgba(255,255,255,0.15);
|
||||
color: #8fa1b2; /* Body Text */
|
||||
}
|
||||
|
||||
.theme-light .call-tree-header,
|
||||
.theme-light .call-tree-cell {
|
||||
-moz-border-end-color: rgba(0,0,0,0.15);
|
||||
color: #18191a; /* Body Text */
|
||||
-moz-border-end-width: 1px;
|
||||
-moz-border-end-style: solid;
|
||||
}
|
||||
|
||||
.call-tree-header:not(:last-child) {
|
||||
|
@ -112,56 +109,32 @@
|
|||
text-align: end;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-header {
|
||||
background-color: #252c33; /* Tab Toolbar */
|
||||
.call-tree-header {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-header {
|
||||
background-color: #ebeced; /* Tab Toolbar */
|
||||
.call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid var(--cell-border-color);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.15);
|
||||
.call-tree-item:nth-child(2n) {
|
||||
background-color: var(--row-alt-background-color);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.15);
|
||||
.call-tree-item:hover {
|
||||
background-color: var(--row-hover-background-color);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:nth-child(2n) {
|
||||
background-color: rgba(29,79,115,0.15);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:nth-child(2n) {
|
||||
background-color: rgba(76,158,217,0.1);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:hover {
|
||||
background-color: rgba(29,79,115,0.25);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:hover {
|
||||
background-color: rgba(76,158,217,0.2);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:focus {
|
||||
background-color: #1d4f73; /* Select Highlight Blue */
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:focus {
|
||||
background-color: #4c9ed9; /* Select Highlight Blue */
|
||||
.call-tree-item:focus {
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.call-tree-item:focus label {
|
||||
color: #f5f7fa !important; /* Light foreground text */
|
||||
color: var(--theme-selection-color) !important;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: rgba(255,255,255,0.5);
|
||||
.call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: var(--focus-cell-border-color);
|
||||
}
|
||||
|
||||
.call-tree-item:not([origin="content"]) .call-tree-name,
|
||||
|
@ -180,33 +153,18 @@
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-url {
|
||||
color: #46afe3;
|
||||
.call-tree-url {
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-url {
|
||||
color: #0088cc;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-line {
|
||||
color: #d96629;
|
||||
}
|
||||
|
||||
.theme-light .call-tree-line {
|
||||
color: #f13c00;
|
||||
.call-tree-line {
|
||||
color: var(--theme-highlight-orange);
|
||||
}
|
||||
|
||||
.call-tree-host {
|
||||
-moz-margin-start: 8px !important;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-host {
|
||||
color: #8fa1b2;
|
||||
}
|
||||
|
||||
.theme-light .call-tree-host {
|
||||
color: #8fa1b2;
|
||||
color: var(--theme-content-color2);
|
||||
}
|
||||
|
||||
.call-tree-url[value=""],
|
||||
|
@ -307,15 +265,7 @@
|
|||
}
|
||||
|
||||
.waterfall-sidebar {
|
||||
-moz-border-end: 1px solid;
|
||||
}
|
||||
|
||||
.theme-dark .waterfall-sidebar {
|
||||
-moz-border-end-color: #000;
|
||||
}
|
||||
|
||||
.theme-light .waterfall-sidebar {
|
||||
-moz-border-end-color: #aaa;
|
||||
-moz-border-end: 1px solid var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
.waterfall-marker-container:hover > .waterfall-sidebar {
|
||||
|
@ -330,14 +280,7 @@
|
|||
width: 100px;
|
||||
font-size: 9px;
|
||||
transform-origin: left center;
|
||||
}
|
||||
|
||||
.theme-dark .waterfall-header-tick {
|
||||
color: #a9bacb;
|
||||
}
|
||||
|
||||
.theme-light .waterfall-header-tick {
|
||||
color: #292e33;
|
||||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.waterfall-header-tick:not(:first-child) {
|
||||
|
@ -365,16 +308,9 @@
|
|||
transform-origin: left center;
|
||||
}
|
||||
|
||||
.theme-light .waterfall-marker-container.selected > .waterfall-sidebar,
|
||||
.theme-light .waterfall-marker-container.selected > .waterfall-marker-item {
|
||||
background-color: #4c9ed9; /* Select Highlight Blue */
|
||||
color: #f5f7fa; /* Light foreground text */
|
||||
}
|
||||
|
||||
.theme-dark .waterfall-marker-container.selected > .waterfall-sidebar,
|
||||
.theme-dark .waterfall-marker-container.selected > .waterfall-marker-item {
|
||||
background-color: #1d4f73; /* Select Highlight Blue */
|
||||
color: #f5f7fa; /* Light foreground text */
|
||||
.waterfall-marker-container.selected > .waterfall-marker-item {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.waterfall-marker-container.selected .waterfall-marker-bullet,
|
||||
|
|
|
@ -3,6 +3,21 @@
|
|||
* 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/. */
|
||||
|
||||
/* CSS Variables specific to this panel that aren't defined by the themes */
|
||||
.theme-dark {
|
||||
--cell-border-color: rgba(255,255,255,0.15);
|
||||
--focus-cell-border-color: rgba(0,0,0,0.3);
|
||||
--row-alt-background-color: rgba(29,79,115,0.15);
|
||||
--row-hover-background-color: rgba(29,79,115,0.25);
|
||||
}
|
||||
|
||||
.theme-light {
|
||||
--cell-border-color: rgba(0,0,0,0.15);
|
||||
--focus-cell-border-color: rgba(255,255,255,0.5);
|
||||
--row-alt-background-color: rgba(76,158,217,0.1);
|
||||
--row-hover-background-color: rgba(76,158,217,0.2);
|
||||
}
|
||||
|
||||
/* Reload and waiting notices */
|
||||
|
||||
.notice-container {
|
||||
|
@ -245,17 +260,13 @@
|
|||
|
||||
.call-tree-header:not(:last-child),
|
||||
.call-tree-cell:not(:last-child) {
|
||||
-moz-border-end: 1px solid;
|
||||
-moz-border-end-width: 1px;
|
||||
-moz-border-end-style: solid;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-header,
|
||||
.theme-dark .call-tree-cell {
|
||||
-moz-border-end-color: rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-header,
|
||||
.theme-light .call-tree-cell {
|
||||
-moz-border-end-color: rgba(0,0,0,0.15);
|
||||
.call-tree-header,
|
||||
.call-tree-cell {
|
||||
-moz-border-end-color: var(--cell-border-color);
|
||||
}
|
||||
|
||||
.call-tree-header:not(:last-child) {
|
||||
|
@ -270,28 +281,16 @@
|
|||
background-color: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.15);
|
||||
.call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid var(--cell-border-color);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:last-child:not(:focus) {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.15);
|
||||
.call-tree-item:nth-child(2n) {
|
||||
background-color: var(--row-alt-background-color);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:nth-child(2n) {
|
||||
background-color: rgba(29,79,115,0.15);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:nth-child(2n) {
|
||||
background-color: rgba(76,158,217,0.1);
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:hover {
|
||||
background-color: rgba(29,79,115,0.25);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:hover {
|
||||
background-color: rgba(76,158,217,0.2);
|
||||
.call-tree-item:hover {
|
||||
background-color: var(--row-hover-background-color);
|
||||
}
|
||||
|
||||
.call-tree-item:focus {
|
||||
|
@ -302,12 +301,8 @@
|
|||
color: var(--theme-selection-color) !important;
|
||||
}
|
||||
|
||||
.theme-dark .call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.theme-light .call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: rgba(255,255,255,0.5);
|
||||
.call-tree-item:focus .call-tree-cell {
|
||||
-moz-border-end-color: var(--focus-cell-border-color);
|
||||
}
|
||||
|
||||
.call-tree-item:not([origin="content"]) .call-tree-name,
|
||||
|
|
|
@ -77,8 +77,13 @@ AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
|
|||
#endif
|
||||
|
||||
CHECK(aObserver);
|
||||
#if ANDROID_VERSION >= 21
|
||||
mSessionId = AudioSystem::newAudioUniqueId();
|
||||
AudioSystem::acquireAudioSessionId(mSessionId, -1);
|
||||
#else
|
||||
mSessionId = AudioSystem::newAudioSessionId();
|
||||
AudioSystem::acquireAudioSessionId(mSessionId);
|
||||
#endif
|
||||
mAudioSink = new AudioOutput(mSessionId,
|
||||
IPCThreadState::self()->getCallingUid());
|
||||
}
|
||||
|
@ -86,7 +91,11 @@ AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
|
|||
AudioOffloadPlayer::~AudioOffloadPlayer()
|
||||
{
|
||||
Reset();
|
||||
#if ANDROID_VERSION >= 21
|
||||
AudioSystem::releaseAudioSessionId(mSessionId, -1);
|
||||
#else
|
||||
AudioSystem::releaseAudioSessionId(mSessionId);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioOffloadPlayer::SetSource(const sp<MediaSource> &aSource)
|
||||
|
|
|
@ -9,10 +9,13 @@ interface MozWakeLockListener;
|
|||
* The reason for the factory reset.
|
||||
* "normal" : simple factory reset.
|
||||
* "wipe" : will also attempt to wipe all user storage areas.
|
||||
* "root" : simple factory reset that also root the phone to get more
|
||||
* privileges when using devtools.
|
||||
*/
|
||||
enum FactoryResetReason {
|
||||
"normal",
|
||||
"wipe"
|
||||
"wipe",
|
||||
"root"
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1777,6 +1777,8 @@ FactoryReset(FactoryResetReason& aReason)
|
|||
|
||||
if (aReason == FactoryResetReason::Wipe) {
|
||||
recoveryService->FactoryReset("wipe");
|
||||
} else if (aReason == FactoryResetReason::Root) {
|
||||
recoveryService->FactoryReset("root");
|
||||
} else {
|
||||
recoveryService->FactoryReset("normal");
|
||||
}
|
||||
|
|
|
@ -446,6 +446,8 @@ FactoryReset(FactoryResetReason& aReason)
|
|||
Hal()->SendFactoryReset(NS_LITERAL_STRING("normal"));
|
||||
} else if (aReason == FactoryResetReason::Wipe) {
|
||||
Hal()->SendFactoryReset(NS_LITERAL_STRING("wipe"));
|
||||
} else if (aReason == FactoryResetReason::Root) {
|
||||
Hal()->SendFactoryReset(NS_LITERAL_STRING("root"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -870,6 +872,8 @@ public:
|
|||
reason = FactoryResetReason::Normal;
|
||||
} else if (aReason.EqualsLiteral("wipe")) {
|
||||
reason = FactoryResetReason::Wipe;
|
||||
} else if (aReason.EqualsLiteral("root")) {
|
||||
reason = FactoryResetReason::Root;
|
||||
} else {
|
||||
// Invalid factory reset reason. That should never happen.
|
||||
return false;
|
||||
|
|
|
@ -65,7 +65,12 @@ public abstract class SessionParser {
|
|||
for (int i = 0; i < tabs.length(); i++) {
|
||||
final JSONObject tab = tabs.getJSONObject(i);
|
||||
final int index = tab.getInt("index");
|
||||
final JSONObject entry = tab.getJSONArray("entries").getJSONObject(index - 1);
|
||||
final JSONArray entries = tab.getJSONArray("entries");
|
||||
if (index < 1 || entries.length() < index) {
|
||||
Log.w(LOGTAG, "Session entries and index don't agree.");
|
||||
continue;
|
||||
}
|
||||
final JSONObject entry = entries.getJSONObject(index - 1);
|
||||
final String url = entry.getString("url");
|
||||
|
||||
String title = entry.optString("title");
|
||||
|
|
|
@ -244,6 +244,7 @@ SandboxFilterImplContent::Build() {
|
|||
Allow(SYSCALL(sched_setparam));
|
||||
Allow(SYSCALL(sigaltstack));
|
||||
Allow(SYSCALL(pipe));
|
||||
Allow(SYSCALL(set_tid_address));
|
||||
|
||||
/* Always last and always OK calls */
|
||||
/* Architecture-specific very infrequently used syscalls */
|
||||
|
|
|
@ -34,6 +34,19 @@ const {FramerateActor} = require("devtools/server/actors/framerate");
|
|||
// docShell, no event is sent).
|
||||
const DEFAULT_TIMELINE_DATA_PULL_TIMEOUT = 200; // ms
|
||||
|
||||
/**
|
||||
* Type representing an array of numbers as strings, serialized fast(er).
|
||||
* http://jsperf.com/json-stringify-parse-vs-array-join-split/3
|
||||
*
|
||||
* XXX: It would be nice if on local connections (only), we could just *give*
|
||||
* the array directly to the front, instead of going through all this
|
||||
* serialization redundancy.
|
||||
*/
|
||||
protocol.types.addType("array-of-numbers-as-strings", {
|
||||
write: (v) => v.join(","),
|
||||
read: (v) => v.split(",")
|
||||
});
|
||||
|
||||
/**
|
||||
* The timeline actor pops and forwards timeline markers registered in docshells.
|
||||
*/
|
||||
|
@ -72,7 +85,7 @@ let TimelineActor = exports.TimelineActor = protocol.ActorClass({
|
|||
"ticks" : {
|
||||
type: "ticks",
|
||||
delta: Arg(0, "number"),
|
||||
timestamps: Arg(1, "array:number")
|
||||
timestamps: Arg(1, "array-of-numbers-as-strings")
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче