mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Merge b2g-inbound to m-c.
This commit is contained in:
commit
1e0482e1c1
@ -30,6 +30,10 @@ function LOG(s) {
|
||||
dump("== Payment flow == " + s + "\n");
|
||||
}
|
||||
|
||||
function LOGE(s) {
|
||||
dump("== Payment flow ERROR == " + s + "\n");
|
||||
}
|
||||
|
||||
if (_debug) {
|
||||
LOG("Frame script injected");
|
||||
}
|
||||
@ -43,6 +47,12 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
Cu.import('resource://gre/modules/ObjectWrapper.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gRil",
|
||||
"@mozilla.org/ril;1",
|
||||
"nsIRadioInterfaceLayer");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
|
||||
"@mozilla.org/ril/content-helper;1",
|
||||
"nsIIccProvider");
|
||||
@ -59,6 +69,7 @@ const kSilentSmsReceivedTopic = "silent-sms-received";
|
||||
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
|
||||
|
||||
const kRilDefaultDataServiceId = "ril.data.defaultServiceId";
|
||||
const kRilDefaultPaymentServiceId = "ril.payment.defaultServiceId";
|
||||
|
||||
const MOBILEMESSAGECALLBACK_CID =
|
||||
Components.ID("{b484d8c9-6be4-4f94-ab60-c9c7ebcc853d}");
|
||||
@ -71,8 +82,8 @@ function SilentSmsRequest() {
|
||||
|
||||
SilentSmsRequest.prototype = {
|
||||
__exposedProps__: {
|
||||
onsuccess: 'rw',
|
||||
onerror: 'rw'
|
||||
onsuccess: "rw",
|
||||
onerror: "rw"
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileMessageCallback]),
|
||||
@ -95,33 +106,69 @@ SilentSmsRequest.prototype = {
|
||||
},
|
||||
|
||||
notifySendMessageFailed: function notifySendMessageFailed(aError) {
|
||||
if (_debug) {
|
||||
LOG("Error sending silent message " + aError);
|
||||
}
|
||||
LOGE("Error sending silent message " + aError);
|
||||
this._onerror(aError);
|
||||
}
|
||||
};
|
||||
|
||||
function PaymentSettings() {
|
||||
this.dataServiceId = 0;
|
||||
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
|
||||
gSettingsService.createLock().get(kRilDefaultDataServiceId, this);
|
||||
|
||||
[kRilDefaultDataServiceId, kRilDefaultPaymentServiceId].forEach(setting => {
|
||||
gSettingsService.createLock().get(setting, this);
|
||||
});
|
||||
}
|
||||
|
||||
PaymentSettings.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISettingsServiceCallback,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
dataServiceId: 0,
|
||||
_paymentServiceId: 0,
|
||||
|
||||
get paymentServiceId() {
|
||||
return this._paymentServiceId;
|
||||
},
|
||||
|
||||
set paymentServiceId(serviceId) {
|
||||
// We allow the payment provider to set the service ID that will be used
|
||||
// for the payment process.
|
||||
// This service ID will be the one used by the silent SMS flow.
|
||||
// If the payment is done with an external SIM, the service ID must be set
|
||||
// to null.
|
||||
if (serviceId != null && serviceId >= gRil.numRadioInterfaces) {
|
||||
LOGE("Invalid service ID " + serviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
gSettingsService.createLock().set(kRilDefaultPaymentServiceId,
|
||||
serviceId, null);
|
||||
this._paymentServiceId = serviceId;
|
||||
},
|
||||
|
||||
setServiceId: function(aName, aValue) {
|
||||
switch (aName) {
|
||||
case kRilDefaultDataServiceId:
|
||||
this.dataServiceId = aValue;
|
||||
if (_debug) {
|
||||
LOG("dataServiceId " + this.dataServiceId);
|
||||
}
|
||||
break;
|
||||
case kRilDefaultPaymentServiceId:
|
||||
this._paymentServiceId = aValue;
|
||||
if (_debug) {
|
||||
LOG("paymentServiceId " + this._paymentServiceId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handle: function(aName, aValue) {
|
||||
if (aName != kRilDefaultDataServiceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataServiceId = aValue;
|
||||
|
||||
if (_debug) {
|
||||
LOG("dataServiceId " + this.dataServiceId);
|
||||
}
|
||||
this.setServiceId(aName, aValue);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
@ -131,21 +178,15 @@ PaymentSettings.prototype = {
|
||||
|
||||
try {
|
||||
let setting = JSON.parse(aData);
|
||||
if (!setting.key || setting.key !== kRilDefaultDataServiceId) {
|
||||
if (!setting.key ||
|
||||
(setting.key !== kRilDefaultDataServiceId &&
|
||||
setting.key !== kRilDefaultPaymentServiceId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataServiceId = setting.value;
|
||||
|
||||
if (_debug) {
|
||||
LOG("dataServiceId " + setting.value);
|
||||
}
|
||||
this.setServiceId(setting.key, setting.value);
|
||||
} catch (e) {
|
||||
if (_debug) {
|
||||
LOG(e);
|
||||
}
|
||||
LOGE(e);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
cleanup: function() {
|
||||
@ -163,19 +204,18 @@ let gBrowser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let PaymentProvider = {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
__exposedProps__: {
|
||||
paymentSuccess: 'r',
|
||||
paymentFailed: 'r',
|
||||
iccIds: 'r',
|
||||
mcc: 'r',
|
||||
mnc: 'r',
|
||||
sendSilentSms: 'r',
|
||||
observeSilentSms: 'r',
|
||||
removeSilentSmsObserver: 'r'
|
||||
paymentSuccess: "r",
|
||||
paymentFailed: "r",
|
||||
paymentServiceId: "rw",
|
||||
iccInfo: "r",
|
||||
sendSilentSms: "r",
|
||||
observeSilentSms: "r",
|
||||
removeSilentSmsObserver: "r"
|
||||
},
|
||||
#else
|
||||
__exposedProps__: {
|
||||
paymentSuccess: 'r',
|
||||
paymentFailed: 'r'
|
||||
paymentSuccess: "r",
|
||||
paymentFailed: "r"
|
||||
},
|
||||
#endif
|
||||
|
||||
@ -242,9 +282,7 @@ let PaymentProvider = {
|
||||
},
|
||||
|
||||
paymentFailed: function paymentFailed(aErrorMsg) {
|
||||
if (_debug) {
|
||||
LOG("paymentFailed " + aErrorMsg);
|
||||
}
|
||||
LOGE("paymentFailed " + aErrorMsg);
|
||||
|
||||
PaymentProvider._closePaymentFlowDialog(function notifyError() {
|
||||
if (!gRequestId) {
|
||||
@ -256,22 +294,45 @@ let PaymentProvider = {
|
||||
},
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
// Bug 938993. Support Multi-SIM for Payments.
|
||||
get paymentServiceId() {
|
||||
return this._settings.paymentServiceId;
|
||||
},
|
||||
|
||||
set paymentServiceId(serviceId) {
|
||||
this._settings.paymentServiceId = serviceId;
|
||||
},
|
||||
|
||||
// We expose to the payment provider the information of all the SIMs
|
||||
// available in the device. iccInfo is an object of this form:
|
||||
// {
|
||||
// "serviceId1": {
|
||||
// mcc: <string>,
|
||||
// mnc: <string>,
|
||||
// iccId: <string>,
|
||||
// dataPrimary: <boolean>
|
||||
// },
|
||||
// "serviceIdN": {...}
|
||||
// }
|
||||
get iccInfo() {
|
||||
delete this.iccInfo;
|
||||
return this.iccInfo = iccProvider.getIccInfo(this._settings.dataServiceId);
|
||||
},
|
||||
if (!this._iccInfo) {
|
||||
this._iccInfo = {};
|
||||
for (let i = 0; i < gRil.numRadioInterfaces; i++) {
|
||||
let info = iccProvider.getIccInfo(i);
|
||||
if (!info) {
|
||||
LOGE("Tried to get the ICC info for an invalid service ID " + i);
|
||||
continue;
|
||||
}
|
||||
|
||||
get iccIds() {
|
||||
return [this.iccInfo.iccid];
|
||||
},
|
||||
this._iccInfo[i] = {
|
||||
iccId: info.iccid,
|
||||
mcc: info.mcc,
|
||||
mnc: info.mnc,
|
||||
dataPrimary: i == this._settings.dataServiceId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get mcc() {
|
||||
return [this.iccInfo.mcc];
|
||||
},
|
||||
|
||||
get mnc() {
|
||||
return [this.iccInfo.mnc];
|
||||
return ObjectWrapper.wrap(this._iccInfo, content);
|
||||
},
|
||||
|
||||
_silentNumbers: null,
|
||||
@ -283,7 +344,21 @@ let PaymentProvider = {
|
||||
}
|
||||
|
||||
let request = new SilentSmsRequest();
|
||||
smsService.send(aNumber, aMessage, true, request);
|
||||
|
||||
if (this._settings.paymentServiceId === null) {
|
||||
LOGE("No payment service ID set. Cannot send silent SMS");
|
||||
let runnable = {
|
||||
run: function run() {
|
||||
request.notifySendMessageFailed("NO_PAYMENT_SERVICE_ID");
|
||||
}
|
||||
};
|
||||
Services.tm.currentThread.dispatch(runnable,
|
||||
Ci.nsIThread.DISPATCH_NORMAL);
|
||||
return request;
|
||||
}
|
||||
|
||||
smsService.send(this._settings.paymentServiceId, aNumber, aMessage, true,
|
||||
request);
|
||||
return request;
|
||||
},
|
||||
|
||||
@ -349,6 +424,21 @@ let PaymentProvider = {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the service ID is null it means that the payment provider asked the
|
||||
// user for her MSISDN, so we are in a MT only SMS auth flow. In this case
|
||||
// we manually set the service ID to the one corresponding with the SIM
|
||||
// that received the SMS.
|
||||
if (this._settings.paymentServiceId === null) {
|
||||
let i = 0;
|
||||
while(i < gRil.numRadioInterfaces) {
|
||||
if (this.iccInfo[i].iccId === aSubject.iccId) {
|
||||
this._settings.paymentServiceId = i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
this._silentSmsObservers[number].forEach(function(callback) {
|
||||
callback(aSubject);
|
||||
});
|
||||
|
@ -0,0 +1,40 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||
const { Services } = Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var processId;
|
||||
|
||||
function peekChildId(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(peekChildId, 'recording-device-events');
|
||||
Services.obs.removeObserver(peekChildId, 'recording-device-ipc-events');
|
||||
let props = aSubject.QueryInterface(Ci.nsIPropertyBag2);
|
||||
if (props.hasKey('childID')) {
|
||||
processId = props.get('childID');
|
||||
}
|
||||
}
|
||||
|
||||
addMessageListener('init-chrome-event', function(message) {
|
||||
// listen mozChromeEvent and forward to content process.
|
||||
let browser = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
let type = message.type;
|
||||
browser.addEventListener('mozChromeEvent', function(event) {
|
||||
let details = event.detail;
|
||||
if (details.type === type) {
|
||||
sendAsyncMessage('chrome-event', details);
|
||||
}
|
||||
}, true);
|
||||
|
||||
Services.obs.addObserver(peekChildId, 'recording-device-events', false);
|
||||
Services.obs.addObserver(peekChildId, 'recording-device-ipc-events', false);
|
||||
});
|
||||
|
||||
addMessageListener('fake-content-shutdown', function(message) {
|
||||
let props = Cc["@mozilla.org/hash-property-bag;1"]
|
||||
.createInstance(Ci.nsIWritablePropertyBag2);
|
||||
if (processId) {
|
||||
props.setPropertyAsUint64('childID', processId);
|
||||
}
|
||||
Services.obs.notifyObservers(props, 'recording-device-ipc-events', 'content-shutdown');
|
||||
});
|
82
b2g/chrome/content/test/mochitest/RecordingStatusHelper.js
Normal file
82
b2g/chrome/content/test/mochitest/RecordingStatusHelper.js
Normal file
@ -0,0 +1,82 @@
|
||||
'use strict';
|
||||
|
||||
// resolve multiple promise in parallel
|
||||
function expectAll(aValue) {
|
||||
let deferred = new Promise(function(resolve, reject) {
|
||||
let countdown = aValue.length;
|
||||
let resolutionValues = new Array(countdown);
|
||||
|
||||
for (let i = 0; i < aValue.length; i++) {
|
||||
let index = i;
|
||||
aValue[i].then(function(val) {
|
||||
resolutionValues[index] = val;
|
||||
if (--countdown === 0) {
|
||||
resolve(resolutionValues);
|
||||
}
|
||||
}, reject);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
function TestInit() {
|
||||
let url = SimpleTest.getTestFileURL("RecordingStatusChromeScript.js")
|
||||
let script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
let helper = {
|
||||
finish: function () {
|
||||
script.destroy();
|
||||
},
|
||||
fakeShutdown: function () {
|
||||
script.sendAsyncMessage('fake-content-shutdown', {});
|
||||
}
|
||||
};
|
||||
|
||||
script.addMessageListener('chrome-event', function (message) {
|
||||
if (helper.hasOwnProperty('onEvent')) {
|
||||
helper.onEvent(message);
|
||||
} else {
|
||||
ok(false, 'unexpected message: ' + JSON.stringify(message));
|
||||
}
|
||||
});
|
||||
|
||||
script.sendAsyncMessage("init-chrome-event", {
|
||||
type: 'recording-status'
|
||||
});
|
||||
|
||||
return Promise.resolve(helper);
|
||||
}
|
||||
|
||||
function expectEvent(expected, eventHelper) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
eventHelper.onEvent = function(message) {
|
||||
delete eventHelper.onEvent;
|
||||
ok(message, JSON.stringify(message));
|
||||
is(message.type, 'recording-status', 'event type: ' + message.type);
|
||||
is(message.active, expected.active, 'recording active: ' + message.active);
|
||||
is(message.isAudio, expected.isAudio, 'audio recording active: ' + message.isAudio);
|
||||
is(message.isVideo, expected.isVideo, 'video recording active: ' + message.isVideo);
|
||||
resolve(eventHelper);
|
||||
};
|
||||
info('waiting for recording-status');
|
||||
});
|
||||
}
|
||||
|
||||
function expectStream(params, callback) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var req = navigator.mozGetUserMedia(
|
||||
params,
|
||||
function(stream) {
|
||||
ok(true, 'create media stream');
|
||||
callback(stream);
|
||||
resolve();
|
||||
},
|
||||
function(err) {
|
||||
ok(false, 'fail to create media stream');
|
||||
reject(err);
|
||||
}
|
||||
);
|
||||
info('waiting for gUM result');
|
||||
});
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Iframe for Recording Status</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
|
||||
var localStream;
|
||||
|
||||
window.addEventListener('message', function(event) {
|
||||
switch (event.data) {
|
||||
case 'start':
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStream = stream;
|
||||
event.source.postMessage('start-finished', window.location.origin);
|
||||
});
|
||||
break;
|
||||
case 'stop':
|
||||
localStream.stop();
|
||||
localStream = null;
|
||||
break;
|
||||
}
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
10
b2g/chrome/content/test/mochitest/mochitest.ini
Normal file
10
b2g/chrome/content/test/mochitest/mochitest.ini
Normal file
@ -0,0 +1,10 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
RecordingStatusChromeScript.js
|
||||
RecordingStatusHelper.js
|
||||
file_getusermedia_iframe.html
|
||||
|
||||
[test_recordingStatus_basic.html]
|
||||
[test_recordingStatus_multiple_requests.html]
|
||||
[test_recordingStatus_iframe.html]
|
||||
[test_recordingStatus_kill_content_process.html]
|
7
b2g/chrome/content/test/mochitest/moz.build
Normal file
7
b2g/chrome/content/test/mochitest/moz.build
Normal file
@ -0,0 +1,7 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Recording Status</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
'use strict';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
let localStreams = [];
|
||||
TestInit().then(function(eventHelper) {
|
||||
/* step 1: create one audio stream
|
||||
* expect: see one mozChromeEvent for audio recording start.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 2: close the audio stream
|
||||
* expect: see one mozChromeEvent for recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false,
|
||||
}, eventHelper);
|
||||
|
||||
localStreams.shift().stop();
|
||||
info('stop audio stream');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
/* step 3: create one video stream
|
||||
* expect: see one mozChromeEvent for video recording start
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: false,
|
||||
isVideo: true
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ video: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 4: close the audio stream
|
||||
* expect: see one mozChromeEvent for recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false,
|
||||
}, eventHelper);
|
||||
|
||||
localStreams.shift().stop();
|
||||
info('stop video stream');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
/* step 3: create one audio/video stream
|
||||
* expect: see one mozChromeEvent for audio/video recording start
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: true
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
video: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 4: close the audio stream
|
||||
* expect: see one mozChromeEvent for recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false,
|
||||
}, eventHelper);
|
||||
|
||||
localStreams.shift().stop();
|
||||
info('stop audio/video stream');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
eventHelper.finish();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
// ensure Promise API is enabled
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.promise.enabled", true],
|
||||
['media.navigator.permission.disabled', true]
|
||||
]
|
||||
}, test);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Recording Status in iframe</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<iframe id="gum-iframe"></iframe>
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
TestInit().then(function(eventHelper) {
|
||||
/* step 1: load iframe whilch creates audio stream
|
||||
* expect: see one mozChromeEvent for audio recording start.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
let loadDeferred = new Promise(function(resolve, reject) {
|
||||
let gumIframe = document.getElementById('gum-iframe');
|
||||
gumIframe.src = 'file_getusermedia_iframe.html';
|
||||
|
||||
window.addEventListener('message', function(event) {
|
||||
if (event.data === 'start-finished') {
|
||||
resolve();
|
||||
}
|
||||
}, false);
|
||||
|
||||
gumIframe.onload = function() {
|
||||
info('start audio stream in iframe');
|
||||
gumIframe.contentWindow.postMessage('start', window.location.origin);
|
||||
};
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, loadDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 2: close the audio stream
|
||||
* expect: see one mozChromeEvent for recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
let win = document.getElementById('gum-iframe').contentWindow;
|
||||
win.postMessage('stop', window.location.origin);
|
||||
info('stop audio stream in iframe');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
eventHelper.finish();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
// ensure Promise API is enabled
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.promise.enabled", true],
|
||||
['media.navigator.permission.disabled', true]
|
||||
]
|
||||
}, test);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Recording Status after process shutdown</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
let localStreams = [];
|
||||
TestInit().then(function(eventHelper) {
|
||||
/* step 1: load iframe whilch creates audio stream
|
||||
* expect: see one mozChromeEvent for audio recording start.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
fake: true
|
||||
}, function(stream) { localStreams.push(stream); });
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 2: create video stream
|
||||
* expect: see one mozChromeEvent for audio recording start.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: true
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ video: true,
|
||||
fake: true
|
||||
}, function(stream) { localStreams.push(stream); });
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 3: close the audio stream
|
||||
* expect: see one mozChromeEvent for recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
eventHelper.fakeShutdown();
|
||||
info('simulate content process been killed');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
eventHelper.finish();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
// ensure Promise API is enabled
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.promise.enabled", true],
|
||||
['media.navigator.permission.disabled', true]
|
||||
]
|
||||
}, test);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,110 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Recording Status with multiple gUM requests</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript;version=1.7">
|
||||
'use strict';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
let localStreams = [];
|
||||
TestInit().then(function(eventHelper) {
|
||||
/* step 1: create one audio stream
|
||||
* expect: see one mozChromeEvent for recording start.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 2: create another audio stream
|
||||
* expect: no mozChromeEvent after audio stream is created
|
||||
*/
|
||||
let gumDeferred = expectStream({ audio: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([Promise.resolve(eventHelper), gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 3: create video stream
|
||||
* expect: see one mozChromeEvent for recording start
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: true,
|
||||
isVideo: true
|
||||
}, eventHelper);
|
||||
|
||||
let gumDeferred = expectStream({ video: true,
|
||||
fake: true
|
||||
}, function(stream) {
|
||||
localStreams.push(stream);
|
||||
});
|
||||
|
||||
return expectAll([eventDeferred, gumDeferred]);
|
||||
}).then(function([eventHelper]) {
|
||||
/* step 4: stop first audio stream
|
||||
* expect: no mozChromeEvent after first audio stream is stopped
|
||||
*/
|
||||
localStreams.shift().stop();
|
||||
info('stop the first audio stream');
|
||||
return Promise.resolve(eventHelper);
|
||||
}).then(function(eventHelper) {
|
||||
/* step 5: stop the second audio stream
|
||||
* expect: see one mozChromeEvent for audio recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: true,
|
||||
isAudio: false,
|
||||
isVideo: true
|
||||
}, eventHelper);
|
||||
|
||||
localStreams.shift().stop();
|
||||
info('stop the second audio stream');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
/* step 6: stop the video stream
|
||||
* expect: see one mozChromeEvent for video recording stop.
|
||||
*/
|
||||
let eventDeferred = expectEvent({ active: false,
|
||||
isAudio: false,
|
||||
isVideo: false
|
||||
}, eventHelper);
|
||||
|
||||
localStreams.shift().stop();
|
||||
info('stop the video stream');
|
||||
return eventDeferred;
|
||||
}).then(function(eventHelper) {
|
||||
eventHelper.finish();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
// ensure Promise API is enabled
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.promise.enabled", true],
|
||||
['media.navigator.permission.disabled', true]
|
||||
]
|
||||
}, test);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -8,4 +8,6 @@ DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE']
|
||||
DEFINES['PACKAGE'] = 'browser'
|
||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
TEST_DIRS += ['content/test/mochitest']
|
||||
|
@ -12,7 +12,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
@ -11,7 +11,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
|
||||
|
@ -12,7 +12,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "5116c92a2905f6646d7049ddd1e1ab68eeb278d9",
|
||||
"revision": "407993cc2cef77f8c8d0415f11996889ed18dc56",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -11,7 +11,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -10,7 +10,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -12,7 +12,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -11,7 +11,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -11,7 +11,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
|
||||
|
@ -11,7 +11,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="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f382061fe95750d584a9078175c421a36892afc9"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
@ -7035,7 +7035,7 @@ if test "$OS_TARGET" = Android; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=memswap,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm"
|
||||
fi
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -2693,7 +2693,7 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
|
||||
|
||||
AppDownloadManager.remove(aNewApp.manifestURL);
|
||||
|
||||
return [id, newManifest];
|
||||
return [oldApp.id, newManifest];
|
||||
|
||||
}).bind(this)).then(
|
||||
aOnSuccess,
|
||||
@ -3150,7 +3150,8 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
|
||||
aOldApp.appStatus = AppsUtils.getAppManifestStatus(newManifest);
|
||||
|
||||
this._saveEtag(aIsUpdate, aOldApp, aRequestChannel, aHash, newManifest);
|
||||
this._checkOrigin(aIsSigned, aOldApp, newManifest, aIsUpdate);
|
||||
this._checkOrigin(aIsSigned || aIsLocalFileInstall, aOldApp, newManifest,
|
||||
aIsUpdate);
|
||||
this._getIds(aIsSigned, aZipReader, converter, aNewApp, aOldApp, aIsUpdate);
|
||||
|
||||
return newManifest;
|
||||
@ -3231,7 +3232,7 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
|
||||
|
||||
if (aIsUpdate) {
|
||||
// Changing the origin during an update is not allowed.
|
||||
if (uri.prePath != app.origin) {
|
||||
if (uri.prePath != aOldApp.origin) {
|
||||
throw "INVALID_ORIGIN_CHANGE";
|
||||
}
|
||||
// Nothing else to do for an update... since the
|
||||
@ -3239,24 +3240,25 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
|
||||
// app nor can we have a duplicated origin
|
||||
} else {
|
||||
debug("Setting origin to " + uri.prePath +
|
||||
" for " + app.manifestURL);
|
||||
" for " + aOldApp.manifestURL);
|
||||
let newId = uri.prePath.substring(6); // "app://".length
|
||||
if (newId in this.webapps) {
|
||||
throw "DUPLICATE_ORIGIN";
|
||||
}
|
||||
aOldApp.origin = uri.prePath;
|
||||
// Update the registry.
|
||||
let oldId = aOldApp.id;
|
||||
aOldApp.id = newId;
|
||||
this.webapps[newId] = aOldApp;
|
||||
delete this.webapps[aId];
|
||||
delete this.webapps[oldId];
|
||||
// Rename the directories where the files are installed.
|
||||
[DIRECTORY_NAME, "TmpD"].forEach(function(aDir) {
|
||||
let parent = FileUtils.getDir(aDir, ["webapps"], true, true);
|
||||
let dir = FileUtils.getDir(aDir, ["webapps", aId], true, true);
|
||||
let dir = FileUtils.getDir(aDir, ["webapps", oldId], true, true);
|
||||
dir.moveTo(parent, newId);
|
||||
});
|
||||
// Signals that we need to swap the old id with the new app.
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: aId });
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: oldId });
|
||||
this.broadcastMessage("Webapps:AddApp", { id: newId,
|
||||
app: aOldApp });
|
||||
}
|
||||
|
@ -586,18 +586,33 @@ BrowserElementParent.prototype = {
|
||||
_sendTouchEvent: function(type, identifiers, touchesX, touchesY,
|
||||
radiisX, radiisY, rotationAngles, forces,
|
||||
count, modifiers) {
|
||||
this._sendAsyncMsg("send-touch-event", {
|
||||
"type": type,
|
||||
"identifiers": identifiers,
|
||||
"touchesX": touchesX,
|
||||
"touchesY": touchesY,
|
||||
"radiisX": radiisX,
|
||||
"radiisY": radiisY,
|
||||
"rotationAngles": rotationAngles,
|
||||
"forces": forces,
|
||||
"count": count,
|
||||
"modifiers": modifiers
|
||||
});
|
||||
|
||||
let tabParent = this._frameLoader.tabParent;
|
||||
if (tabParent && tabParent.useAsyncPanZoom) {
|
||||
tabParent.injectTouchEvent(type,
|
||||
identifiers,
|
||||
touchesX,
|
||||
touchesY,
|
||||
radiisX,
|
||||
radiisY,
|
||||
rotationAngles,
|
||||
forces,
|
||||
count,
|
||||
modifiers);
|
||||
} else {
|
||||
this._sendAsyncMsg("send-touch-event", {
|
||||
"type": type,
|
||||
"identifiers": identifiers,
|
||||
"touchesX": touchesX,
|
||||
"touchesY": touchesY,
|
||||
"radiisX": radiisX,
|
||||
"radiisY": radiisY,
|
||||
"rotationAngles": rotationAngles,
|
||||
"forces": forces,
|
||||
"count": count,
|
||||
"modifiers": modifiers
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_goBack: function() {
|
||||
|
@ -5,8 +5,19 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
// Sole purpose is to be able to identify the concrete class nsTabParent
|
||||
[uuid(95c7c50b-6677-456f-9f1e-885e1cc272dc)]
|
||||
[scriptable, uuid(c402d6c2-837d-11e3-b47c-3c970e9f4238)]
|
||||
interface nsITabParent : nsISupports
|
||||
{
|
||||
void injectTouchEvent(in AString aType,
|
||||
[array, size_is(count)] in uint32_t aIdentifiers,
|
||||
[array, size_is(count)] in int32_t aXs,
|
||||
[array, size_is(count)] in int32_t aYs,
|
||||
[array, size_is(count)] in uint32_t aRxs,
|
||||
[array, size_is(count)] in uint32_t aRys,
|
||||
[array, size_is(count)] in float aRotationAngles,
|
||||
[array, size_is(count)] in float aForces,
|
||||
in uint32_t count,
|
||||
in long aModifiers);
|
||||
|
||||
readonly attribute boolean useAsyncPanZoom;
|
||||
};
|
||||
|
@ -1897,5 +1897,49 @@ TabParent::GetLoadContext()
|
||||
return loadContext.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::InjectTouchEvent(const nsAString& aType,
|
||||
uint32_t* aIdentifiers,
|
||||
int32_t* aXs,
|
||||
int32_t* aYs,
|
||||
uint32_t* aRxs,
|
||||
uint32_t* aRys,
|
||||
float* aRotationAngles,
|
||||
float* aForces,
|
||||
uint32_t aCount,
|
||||
int32_t aModifiers)
|
||||
{
|
||||
uint32_t msg;
|
||||
nsContentUtils::GetEventIdAndAtom(aType, NS_TOUCH_EVENT, &msg);
|
||||
if (msg != NS_TOUCH_START && msg != NS_TOUCH_MOVE &&
|
||||
msg != NS_TOUCH_END && msg != NS_TOUCH_CANCEL) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetTouchEvent event(true, msg, nullptr);
|
||||
event.modifiers = aModifiers;
|
||||
event.time = PR_IntervalNow();
|
||||
|
||||
event.touches.SetCapacity(aCount);
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
nsRefPtr<Touch> t = new Touch(aIdentifiers[i],
|
||||
nsIntPoint(aXs[i], aYs[i]),
|
||||
nsIntPoint(aRxs[i], aRys[i]),
|
||||
aRotationAngles[i],
|
||||
aForces[i]);
|
||||
event.touches.AppendElement(t);
|
||||
}
|
||||
|
||||
SendRealTouchEvent(event);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom)
|
||||
{
|
||||
*useAsyncPanZoom = UseAsyncPanZoom();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace tabs
|
||||
} // namespace mozilla
|
||||
|
@ -59,6 +59,9 @@ class TabParent : public PBrowserParent
|
||||
typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
|
||||
|
||||
public:
|
||||
// nsITabParent
|
||||
NS_DECL_NSITABPARENT
|
||||
|
||||
TabParent(ContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags);
|
||||
virtual ~TabParent();
|
||||
Element* GetOwnerElement() const { return mFrameElement; }
|
||||
|
@ -91,6 +91,7 @@ let NotificationDB = {
|
||||
var promise = OS.File.open(NOTIFICATION_STORE_PATH, {create: true});
|
||||
promise.then(
|
||||
function onSuccess(handle) {
|
||||
handle.close();
|
||||
callback && callback();
|
||||
},
|
||||
function onFailure(reason) {
|
||||
|
@ -174,6 +174,9 @@ public:
|
||||
RefPtr<UnixSocketConsumer> mConsumer;
|
||||
|
||||
private:
|
||||
|
||||
void FireSocketError();
|
||||
|
||||
/**
|
||||
* libevent triggered functions that reads data from socket when available and
|
||||
* guarenteed non-blocking. Only to be called on IO thread.
|
||||
@ -487,29 +490,47 @@ void ShutdownSocketTask::Run()
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketImpl::Accept()
|
||||
UnixSocketImpl::FireSocketError()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (!mConnector) {
|
||||
NS_WARNING("No connector object available!");
|
||||
return;
|
||||
}
|
||||
// Clean up watchers, statuses, fds
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
mFd.reset(-1);
|
||||
|
||||
// Tell the main thread we've errored
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketImpl::Accept()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mConnector);
|
||||
|
||||
// This will set things we don't particularly care about, but it will hand
|
||||
// back the correct structure size which is what we do care about.
|
||||
if (!mConnector->CreateAddr(true, mAddrSize, mAddr, nullptr)) {
|
||||
NS_WARNING("Cannot create socket address!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFd.get() < 0) {
|
||||
mFd = mConnector->Create();
|
||||
if (mFd.get() < 0) {
|
||||
NS_WARNING("Cannot create socket fd!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetSocketFlags()) {
|
||||
NS_WARNING("Cannot set socket flags!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -517,6 +538,7 @@ UnixSocketImpl::Accept()
|
||||
#ifdef DEBUG
|
||||
CHROMIUM_LOG("...bind(%d) gave errno %d", mFd.get(), errno);
|
||||
#endif
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -524,15 +546,13 @@ UnixSocketImpl::Accept()
|
||||
#ifdef DEBUG
|
||||
CHROMIUM_LOG("...listen(%d) gave errno %d", mFd.get(), errno);
|
||||
#endif
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mConnector->SetUpListenSocket(mFd)) {
|
||||
NS_WARNING("Could not set up listen socket!");
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -545,15 +565,13 @@ void
|
||||
UnixSocketImpl::Connect()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (!mConnector) {
|
||||
NS_WARNING("No connector object available!");
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mConnector);
|
||||
|
||||
if (mFd.get() < 0) {
|
||||
mFd = mConnector->Create();
|
||||
if (mFd.get() < 0) {
|
||||
NS_WARNING("Cannot create socket fd!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -562,15 +580,14 @@ UnixSocketImpl::Connect()
|
||||
|
||||
if (!mConnector->CreateAddr(false, mAddrSize, mAddr, mAddress.get())) {
|
||||
NS_WARNING("Cannot create socket address!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
// Select non-blocking IO.
|
||||
if (-1 == fcntl(mFd.get(), F_SETFL, O_NONBLOCK)) {
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
NS_WARNING("Cannot set nonblock!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -583,20 +600,12 @@ UnixSocketImpl::Connect()
|
||||
int current_opts = fcntl(mFd.get(), F_GETFL, 0);
|
||||
if (-1 == current_opts) {
|
||||
NS_WARNING("Cannot get socket opts!");
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
|
||||
NS_WARNING("Cannot set socket opts to blocking!");
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -616,20 +625,19 @@ UnixSocketImpl::Connect()
|
||||
#if DEBUG
|
||||
CHROMIUM_LOG("Socket connect errno=%d\n", errno);
|
||||
#endif
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetSocketFlags()) {
|
||||
NS_WARNING("Cannot set socket flags!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mConnector->SetUp(mFd)) {
|
||||
NS_WARNING("Could not set up socket!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -862,30 +870,19 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
|
||||
if (ret || error) {
|
||||
NS_WARNING("getsockopt failure on async socket connect!");
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetSocketFlags()) {
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
NS_WARNING("Cannot set socket flags!");
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mConnector->SetUp(mFd)) {
|
||||
NS_WARNING("Could not set up socket!");
|
||||
mFd.reset(-1);
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
mConnectionStatus = SOCKET_DISCONNECTED;
|
||||
FireSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,11 @@
|
||||
#include <pthread.h>
|
||||
#include <alloca.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <vector>
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
@ -25,6 +27,10 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
extern "C" MFBT_API int tgkill(pid_t tgid, pid_t tid, int signalno) {
|
||||
return syscall(__NR_tgkill, tgid, tid, signalno);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the wrappers to a selected set of pthread and system-level functions
|
||||
* as the basis for implementing Zygote-like preforking mechanism.
|
||||
@ -62,7 +68,6 @@ int __real_pipe2(int __pipedes[2], int flags);
|
||||
int __real_pipe(int __pipedes[2]);
|
||||
int __real_epoll_ctl(int aEpollFd, int aOp, int aFd, struct epoll_event *aEvent);
|
||||
int __real_close(int aFd);
|
||||
|
||||
}
|
||||
|
||||
#define REAL(s) __real_##s
|
||||
@ -139,6 +144,8 @@ TLSInfoList;
|
||||
#define NUWA_STACK_SIZE (1024 * 32)
|
||||
#endif
|
||||
|
||||
#define NATIVE_THREAD_NAME_LENGTH 16
|
||||
|
||||
struct thread_info : public mozilla::LinkedListElement<thread_info> {
|
||||
pthread_t origThreadID;
|
||||
pthread_t recreatedThreadID;
|
||||
@ -160,6 +167,10 @@ struct thread_info : public mozilla::LinkedListElement<thread_info> {
|
||||
|
||||
pthread_mutex_t *reacquireMutex;
|
||||
void *stk;
|
||||
|
||||
pid_t origNativeThreadID;
|
||||
pid_t recreatedNativeThreadID;
|
||||
char nativeThreadName[NATIVE_THREAD_NAME_LENGTH];
|
||||
};
|
||||
|
||||
typedef struct thread_info thread_info_t;
|
||||
@ -212,6 +223,7 @@ static TLSKeySet sTLSKeys;
|
||||
*/
|
||||
static pthread_mutex_t sThreadFreezeLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static thread_info_t sMainThread;
|
||||
static LinkedList<thread_info_t> sAllThreads;
|
||||
static int sThreadCount = 0;
|
||||
static int sThreadFreezeCount = 0;
|
||||
@ -277,6 +289,32 @@ GetThreadInfo(pthread_t threadID) {
|
||||
return tinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get thread info using the specified native thread ID.
|
||||
*
|
||||
* @return thread_info_t with nativeThreadID == specified threadID
|
||||
*/
|
||||
static thread_info_t*
|
||||
GetThreadInfo(pid_t threadID) {
|
||||
if (sIsNuwaProcess) {
|
||||
REAL(pthread_mutex_lock)(&sThreadCountLock);
|
||||
}
|
||||
thread_info_t *thrinfo = nullptr;
|
||||
for (thread_info_t *tinfo = sAllThreads.getFirst();
|
||||
tinfo;
|
||||
tinfo = tinfo->getNext()) {
|
||||
if (tinfo->origNativeThreadID == threadID) {
|
||||
thrinfo = tinfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sIsNuwaProcess) {
|
||||
pthread_mutex_unlock(&sThreadCountLock);
|
||||
}
|
||||
|
||||
return thrinfo;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_THREAD_TLS_KEYWORD)
|
||||
/**
|
||||
* Get thread info of the current thread.
|
||||
@ -449,6 +487,7 @@ thread_info_new(void) {
|
||||
tinfo->recrFunc = nullptr;
|
||||
tinfo->recrArg = nullptr;
|
||||
tinfo->recreatedThreadID = 0;
|
||||
tinfo->recreatedNativeThreadID = 0;
|
||||
tinfo->reacquireMutex = nullptr;
|
||||
tinfo->stk = malloc(NUWA_STACK_SIZE);
|
||||
pthread_attr_init(&tinfo->threadAttr);
|
||||
@ -497,6 +536,7 @@ _thread_create_startup(void *arg) {
|
||||
|
||||
SET_THREAD_INFO(tinfo);
|
||||
tinfo->origThreadID = REAL(pthread_self)();
|
||||
tinfo->origNativeThreadID = gettid();
|
||||
|
||||
pthread_cleanup_push(thread_info_cleanup, tinfo);
|
||||
|
||||
@ -619,6 +659,7 @@ RestoreTLSInfo(thread_info_t *tinfo) {
|
||||
|
||||
SET_THREAD_INFO(tinfo);
|
||||
tinfo->recreatedThreadID = REAL(pthread_self)();
|
||||
tinfo->recreatedNativeThreadID = gettid();
|
||||
}
|
||||
|
||||
extern "C" MFBT_API int
|
||||
@ -1215,6 +1256,27 @@ __wrap_close(int aFd) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
extern "C" MFBT_API int
|
||||
__wrap_tgkill(pid_t tgid, pid_t tid, int signalno)
|
||||
{
|
||||
if (sIsNuwaProcess) {
|
||||
return tgkill(tgid, tid, signalno);
|
||||
}
|
||||
|
||||
if (tid == sMainThread.origNativeThreadID) {
|
||||
return tgkill(tgid, sMainThread.recreatedNativeThreadID, signalno);
|
||||
}
|
||||
|
||||
thread_info_t *tinfo = (tid == sMainThread.origNativeThreadID ?
|
||||
&sMainThread :
|
||||
GetThreadInfo(tid));
|
||||
if (!tinfo) {
|
||||
return tgkill(tgid, tid, signalno);
|
||||
}
|
||||
|
||||
return tgkill(tgid, tinfo->recreatedNativeThreadID, signalno);
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_recreate_startup(void *arg) {
|
||||
/*
|
||||
@ -1232,6 +1294,7 @@ thread_recreate_startup(void *arg) {
|
||||
*/
|
||||
thread_info_t *tinfo = (thread_info_t *)arg;
|
||||
|
||||
prctl(PR_SET_NAME, (unsigned long)&tinfo->nativeThreadName, 0, 0, 0);
|
||||
RestoreTLSInfo(tinfo);
|
||||
|
||||
if (setjmp(tinfo->retEnv) != 0) {
|
||||
@ -1267,6 +1330,9 @@ RecreateThreads() {
|
||||
sIsNuwaProcess = false;
|
||||
sIsFreezing = false;
|
||||
|
||||
sMainThread.recreatedThreadID = pthread_self();
|
||||
sMainThread.recreatedNativeThreadID = gettid();
|
||||
|
||||
// Run registered constructors.
|
||||
for (std::vector<nuwa_construct_t>::iterator ctr = sConstructors.begin();
|
||||
ctr != sConstructors.end();
|
||||
@ -1556,6 +1622,10 @@ PrepareNuwaProcess() {
|
||||
|
||||
// Make marked threads block in one freeze point.
|
||||
REAL(pthread_mutex_lock)(&sThreadFreezeLock);
|
||||
|
||||
// Populate sMainThread for mapping of tgkill.
|
||||
sMainThread.origThreadID = pthread_self();
|
||||
sMainThread.origNativeThreadID = gettid();
|
||||
}
|
||||
|
||||
// Make current process as a Nuwa process.
|
||||
@ -1607,6 +1677,10 @@ NuwaMarkCurrentThread(void (*recreate)(void *), void *arg) {
|
||||
tinfo->flags |= TINFO_FLAG_NUWA_SUPPORT;
|
||||
tinfo->recrFunc = recreate;
|
||||
tinfo->recrArg = arg;
|
||||
|
||||
// XXX Thread name might be set later than this call. If this is the case, we
|
||||
// might need to delay getting the thread name.
|
||||
prctl(PR_GET_NAME, (unsigned long)&tinfo->nativeThreadName, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@
|
||||
"toolkit/devtools/apps": ""
|
||||
},
|
||||
"excludetests": {
|
||||
"b2g/chrome/content/test/mochitest": "require OOP support for mochitest-b2g-desktop, Bug 957554",
|
||||
"content/xul":"tests that use xul",
|
||||
"layout/xul" : "",
|
||||
"dom/tests/mochitest/general/test_focusrings.xul":"",
|
||||
|
@ -83,6 +83,10 @@
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#define SIGNAL_SAVE_PROFILE SIGUSR2
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
@ -229,9 +233,15 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
sem_post(&sSignalHandlingDone);
|
||||
}
|
||||
|
||||
// If the Nuwa process is enabled, we need to use the wrapper of tgkill() to
|
||||
// perform the mapping of thread ID.
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
extern "C" MFBT_API int tgkill(pid_t tgid, pid_t tid, int signalno);
|
||||
#else
|
||||
int tgkill(pid_t tgid, pid_t tid, int signalno) {
|
||||
return syscall(SYS_tgkill, tgid, tid, signalno);
|
||||
}
|
||||
#endif
|
||||
|
||||
class PlatformData : public Malloced {
|
||||
public:
|
||||
@ -263,6 +273,18 @@ static void* SignalSender(void* arg) {
|
||||
static void* initialize_atfork = setup_atfork();
|
||||
# endif
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// If the Nuwa process is enabled, we need to mark and freeze the sampler
|
||||
// thread in the Nuwa process and have this thread recreated in the spawned
|
||||
// child.
|
||||
if(IsNuwaProcess()) {
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
// Freeze the thread here so the spawned child will get the correct tgid
|
||||
// from the getpid() call below.
|
||||
NuwaFreezeCurrentThread();
|
||||
}
|
||||
#endif
|
||||
|
||||
int vm_tgid_ = getpid();
|
||||
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
|
Loading…
Reference in New Issue
Block a user