mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge b2g-inbound to m-c. a=merge
CLOSED TREE
This commit is contained in:
commit
f0ac763ef5
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
bug 832837 removes nsISecurityWarningDialogs.idl, which requires a clobber according to bug 1114669
|
||||
Bug 879861 - Touch CLOBBER because adding a new IDL is a crapshoot these days.
|
||||
|
@ -340,10 +340,26 @@ pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240"
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
// Safe browsing does nothing unless this pref is set
|
||||
pref("browser.safebrowsing.enabled", true);
|
||||
pref("browser.safebrowsing.enabled", false);
|
||||
|
||||
// Prevent loading of pages identified as malware
|
||||
pref("browser.safebrowsing.malware.enabled", true);
|
||||
pref("browser.safebrowsing.malware.enabled", false);
|
||||
|
||||
pref("browser.safebrowsing.debug", false);
|
||||
pref("browser.safebrowsing.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
pref("browser.safebrowsing.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
|
||||
pref("browser.safebrowsing.reportURL", "https://safebrowsing.google.com/safebrowsing/report?");
|
||||
pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
|
||||
pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
|
||||
pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
|
||||
pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
|
||||
pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
|
||||
pref("browser.safebrowsing.appRepURL", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
|
||||
|
||||
pref("browser.safebrowsing.id", "Firefox");
|
||||
|
||||
// Tables for application reputation.
|
||||
pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
|
||||
|
||||
// Non-enhanced mode (local url lists) URL list to check for updates
|
||||
pref("browser.safebrowsing.provider.0.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client={moz:client}&appver={moz:version}&pver=2.2&key=%GOOGLE_API_KEY%");
|
||||
@ -364,10 +380,6 @@ pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:local
|
||||
|
||||
// FAQ URLs
|
||||
|
||||
// Name of the about: page contributed by safebrowsing to handle display of error
|
||||
// pages on phishing/malware hits. (bug 399233)
|
||||
pref("urlclassifier.alternate_error_page", "blocked");
|
||||
|
||||
// The number of random entries to send with a gethash request.
|
||||
pref("urlclassifier.gethashnoise", 4);
|
||||
|
||||
|
@ -70,6 +70,11 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'captivePortalDetector',
|
||||
'nsICaptivePortalDetector');
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
||||
"resource://gre/modules/SafeBrowsing.jsm");
|
||||
#endif
|
||||
|
||||
function getContentWindow() {
|
||||
return shell.contentBrowser.contentWindow;
|
||||
}
|
||||
@ -361,6 +366,11 @@ var shell = {
|
||||
ppmm.addMessageListener("sms-handler", this);
|
||||
ppmm.addMessageListener("mail-handler", this);
|
||||
ppmm.addMessageListener("file-picker", this);
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
setTimeout(function() {
|
||||
SafeBrowsing.init();
|
||||
}, 5000);
|
||||
#endif
|
||||
},
|
||||
|
||||
stop: function shell_stop() {
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<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="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="f47964c89a9c34d9a2e77afa3608d9ec604c3d20">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
@ -101,7 +101,6 @@
|
||||
<project name="platform/external/zlib" path="external/zlib" revision="6eb3570ff8fa71bd83bb375b4bf09804c6089fed"/>
|
||||
<project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="dbbe673145107e99883f62bafd70c5f43f11065c"/>
|
||||
<project name="platform/frameworks/wilhelm" path="frameworks/wilhelm" revision="f0c3b4edf597c40aae4ea311575f39c8bcf203df"/>
|
||||
<project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="adb52b35ecb523bd332854945c09828ee887e575"/>
|
||||
<project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
|
||||
<project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
|
||||
<project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
|
||||
@ -118,6 +117,7 @@
|
||||
<project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
|
||||
<project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
|
||||
<project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="76c4bf4bc430a1b8317f2f21ef735867733e50cc"/>
|
||||
<project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/>
|
||||
<!--original fetch url was git://github.com/t2m-foxfone/-->
|
||||
<remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "2a2b008f9ae957fe19ad540d233d86b5c0b6829e",
|
||||
"git_revision": "71defd569502274e877b56094e3a44d776033120",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "a37735733273b7cf2aee44ea123195bb610d0a8e",
|
||||
"revision": "59488903252981b50ff1d73fa5652332a2ca7fc3",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="7f2ee9f4cb926684883fc2a2e407045fd9db2199">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a2b008f9ae957fe19ad540d233d86b5c0b6829e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="71defd569502274e877b56094e3a44d776033120"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="da777082e02eec11c4b7e27679bdb15f47a44f66"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="50d1ca4ab8add54523b7bc692860d57e8ee4c0d1"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="fb3845864573857677f9b500040a8f011eaf5078"/>
|
||||
|
@ -17,7 +17,7 @@ MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
|
||||
MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
|
||||
# MOZ_APP_DISPLAYNAME is set by branding/configure.sh
|
||||
|
||||
MOZ_SAFE_BROWSING=
|
||||
MOZ_SAFE_BROWSING=1
|
||||
MOZ_SERVICES_COMMON=1
|
||||
MOZ_SERVICES_METRICS=1
|
||||
MOZ_CAPTIVEDETECT=1
|
||||
|
@ -183,6 +183,9 @@
|
||||
@BINPATH@/components/dom_geolocation.xpt
|
||||
@BINPATH@/components/dom_media.xpt
|
||||
@BINPATH@/components/dom_network.xpt
|
||||
#ifdef MOZ_SECUREELEMENT
|
||||
@BINPATH@/components/dom_secureelement.xpt
|
||||
#endif
|
||||
#ifdef MOZ_NFC
|
||||
@BINPATH@/components/dom_nfc.xpt
|
||||
#endif
|
||||
@ -412,6 +415,12 @@
|
||||
@BINPATH@/components/htmlMenuBuilder.manifest
|
||||
@BINPATH@/components/PresentationDeviceInfoManager.manifest
|
||||
@BINPATH@/components/PresentationDeviceInfoManager.js
|
||||
#ifdef MOZ_SECUREELEMENT
|
||||
@BINPATH@/components/SecureElement.js
|
||||
@BINPATH@/components/SecureElement.manifest
|
||||
@BINPATH@/components/UiccConnector.js
|
||||
@BINPATH@/components/UiccConnector.manifest
|
||||
#endif
|
||||
|
||||
; WiFi, NetworkManager, NetworkStats
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
@ -547,6 +556,10 @@
|
||||
@BINPATH@/components/NfcContentHelper.manifest
|
||||
@BINPATH@/components/NfcContentHelper.js
|
||||
#endif
|
||||
#ifdef MOZ_SECUREELEMENT
|
||||
@BINPATH@/components/DOMSecureElement.manifest
|
||||
@BINPATH@/components/DOMSecureElement.js
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_DBUS
|
||||
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
||||
#endif
|
||||
|
12
configure.in
12
configure.in
@ -240,6 +240,7 @@ if test -n "$gonkdir" ; then
|
||||
AC_SUBST(MOZ_OMX_DECODER)
|
||||
MOZ_RTSP=1
|
||||
MOZ_FMP4=1
|
||||
MOZ_SECUREELEMENT=1
|
||||
;;
|
||||
17|18)
|
||||
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
|
||||
@ -264,6 +265,7 @@ if test -n "$gonkdir" ; then
|
||||
AC_SUBST(MOZ_OMX_ENCODER)
|
||||
AC_DEFINE(MOZ_OMX_ENCODER)
|
||||
MOZ_FMP4=1
|
||||
MOZ_SECUREELEMENT=1
|
||||
;;
|
||||
19)
|
||||
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
|
||||
@ -279,6 +281,7 @@ if test -n "$gonkdir" ; then
|
||||
MOZ_OMX_ENCODER=1
|
||||
AC_DEFINE(MOZ_OMX_ENCODER)
|
||||
MOZ_AUDIO_OFFLOAD=1
|
||||
MOZ_SECUREELEMENT=1
|
||||
AC_SUBST(MOZ_AUDIO_OFFLOAD)
|
||||
AC_DEFINE(MOZ_AUDIO_OFFLOAD)
|
||||
MOZ_FMP4=1
|
||||
@ -7585,6 +7588,15 @@ if test -n "$MOZ_AUDIO_CHANNEL_MANAGER"; then
|
||||
fi
|
||||
AC_SUBST(MOZ_AUDIO_CHANNEL_MANAGER)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for Secure Element API
|
||||
dnl ========================================================
|
||||
MOZ_SECUREELEMENT=1,
|
||||
if test -n "$MOZ_SECUREELEMENT"; then
|
||||
AC_DEFINE(MOZ_SECUREELEMENT)
|
||||
fi
|
||||
AC_SUBST(MOZ_SECUREELEMENT)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Support for demangling undefined symbols
|
||||
dnl ========================================================
|
||||
|
@ -530,6 +530,12 @@ this.PermissionsTable = { geolocation: {
|
||||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"secureelement-manage": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* -*- Mode: c++; c-basic-offset: 3; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
@ -98,11 +98,11 @@ BluetoothInterface::GetInstance()
|
||||
/* We pick a default backend from the available ones. The branches
|
||||
* are ordered by preference.
|
||||
*/
|
||||
#ifdef MOZ_B2G_BT_DAEMON
|
||||
static const char sDefaultBackend[] = "bluetoothd";
|
||||
#else
|
||||
#ifdef MOZ_B2G_BT_BLUEDROID
|
||||
static const char sDefaultBackend[] = "bluedroid";
|
||||
#else
|
||||
#ifdef MOZ_B2G_BT_DAEMON
|
||||
static const char sDefaultBackend[] = "bluetoothd";
|
||||
#else
|
||||
static const char* const sDefaultBackend = nullptr;
|
||||
#endif
|
||||
|
@ -5,6 +5,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BluetoothInterface.h"
|
||||
#if ANDROID_VERSION >= 17
|
||||
#include <cutils/properties.h>
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT_BLUEDROID
|
||||
#include "BluetoothHALInterface.h"
|
||||
#endif
|
||||
@ -126,19 +129,59 @@ BluetoothNotificationHandler::~BluetoothNotificationHandler()
|
||||
BluetoothInterface*
|
||||
BluetoothInterface::GetInstance()
|
||||
{
|
||||
#if ANDROID_VERSION >= 17
|
||||
/* We pick a default backend from the available ones. The branches
|
||||
* are ordered by preference.
|
||||
*/
|
||||
#ifdef MOZ_B2G_BT_BLUEDROID
|
||||
static const char sDefaultBackend[] = "bluedroid";
|
||||
#else
|
||||
#ifdef MOZ_B2G_BT_DAEMON
|
||||
static const char sDefaultBackend[] = "bluetoothd";
|
||||
#else
|
||||
static const char* const sDefaultBackend = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Here's where we decide which implementation to use. Currently
|
||||
* there is only Bluedroid and the Bluetooth daemon, but others are
|
||||
* possible. Having multiple interfaces built-in and selecting the
|
||||
* correct one at runtime could also be an option.
|
||||
* correct one at runtime is also an option.
|
||||
*/
|
||||
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
int len;
|
||||
|
||||
len = property_get("ro.moz.bluetooth.backend", value, sDefaultBackend);
|
||||
if (len < 0) {
|
||||
BT_WARNING("No Bluetooth backend available.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const nsDependentCString backend(value, len);
|
||||
|
||||
#ifdef MOZ_B2G_BT_BLUEDROID
|
||||
return BluetoothHALInterface::GetInstance();
|
||||
#else
|
||||
#ifdef MOZ_B2G_BT_DAEMON
|
||||
return BluetoothDaemonInterface::GetInstance();
|
||||
#else
|
||||
return nullptr;
|
||||
if (backend.LowerCaseEqualsLiteral("bluedroid")) {
|
||||
return BluetoothHALInterface::GetInstance();
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT_DAEMON
|
||||
if (backend.LowerCaseEqualsLiteral("bluetoothd")) {
|
||||
return BluetoothDaemonInterface::GetInstance();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
BT_WARNING("Bluetooth backend '%s' is unknown or not available.",
|
||||
backend.get());
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
#else
|
||||
/* Anything that's not Android 4.2 or later uses BlueZ instead. The
|
||||
* code should actually never reach this point.
|
||||
*/
|
||||
BT_WARNING("No Bluetooth backend available for your system.");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,18 @@ Convert(uint8_t aIn, BluetoothHandsfreeVolumeType& aOut)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(int aIn, int32_t& aOut)
|
||||
{
|
||||
if (NS_WARN_IF(aIn < std::numeric_limits<int32_t>::min()) ||
|
||||
NS_WARN_IF(aIn > std::numeric_limits<int32_t>::max())) {
|
||||
aOut = 0; // silences compiler warning
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<int32_t>(aIn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(int32_t aIn, BluetoothTypeOfDevice& aOut)
|
||||
{
|
||||
@ -659,6 +671,22 @@ Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpPlayerAttribute aIn, uint8_t& aOut)
|
||||
{
|
||||
static const uint8_t sValue[] = {
|
||||
CONVERT(AVRCP_PLAYER_ATTRIBUTE_EQUALIZER, 0x01),
|
||||
CONVERT(AVRCP_PLAYER_ATTRIBUTE_REPEAT, 0x02),
|
||||
CONVERT(AVRCP_PLAYER_ATTRIBUTE_SHUFFLE, 0x03),
|
||||
CONVERT(AVRCP_PLAYER_ATTRIBUTE_SCAN, 0x04)
|
||||
};
|
||||
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = sValue[aIn];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut)
|
||||
{
|
||||
@ -671,6 +699,23 @@ Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpStatus aIn, uint8_t& aOut)
|
||||
{
|
||||
static const uint8_t sValue[] = {
|
||||
CONVERT(AVRCP_STATUS_BAD_COMMAND, 0x00),
|
||||
CONVERT(AVRCP_STATUS_BAD_PARAMETER, 0x01),
|
||||
CONVERT(AVRCP_STATUS_NOT_FOUND, 0x02),
|
||||
CONVERT(AVRCP_STATUS_INTERNAL_ERROR, 0x03),
|
||||
CONVERT(AVRCP_STATUS_SUCCESS, 0x04)
|
||||
};
|
||||
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = sValue[aIn];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut)
|
||||
{
|
||||
@ -1092,6 +1137,19 @@ PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU)
|
||||
PackConversion<BluetoothAvrcpNotification, uint8_t>(aIn), aPDU);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PackPDU(BluetoothAvrcpPlayerAttribute aIn, BluetoothDaemonPDU& aPDU)
|
||||
{
|
||||
return PackPDU(
|
||||
PackConversion<BluetoothAvrcpPlayerAttribute, uint8_t>(aIn), aPDU);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PackPDU(BluetoothAvrcpStatus aIn, BluetoothDaemonPDU& aPDU)
|
||||
{
|
||||
return PackPDU(PackConversion<BluetoothAvrcpStatus, uint8_t>(aIn), aPDU);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU)
|
||||
{
|
||||
|
@ -128,6 +128,9 @@ Convert(int aIn, uint8_t& aOut);
|
||||
nsresult
|
||||
Convert(int aIn, int16_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(int aIn, int32_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(uint8_t aIn, bool& aOut);
|
||||
|
||||
@ -233,9 +236,15 @@ Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut);
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpPlayerAttribute aIn, uint8_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothAvrcpStatus aIn, uint8_t& aOut);
|
||||
|
||||
nsresult
|
||||
Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut);
|
||||
|
||||
@ -285,6 +294,11 @@ Convert(ControlPlayStatus aIn, uint8_t& aOut);
|
||||
// Packing
|
||||
//
|
||||
|
||||
// introduce link errors on non-handled data types
|
||||
template <typename T>
|
||||
nsresult
|
||||
PackPDU(T aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
nsresult
|
||||
PackPDU(bool aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
@ -335,6 +349,12 @@ PackPDU(const BluetoothAvrcpEventParamPair& aIn, BluetoothDaemonPDU& aPDU);
|
||||
nsresult
|
||||
PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
nsresult
|
||||
PackPDU(BluetoothAvrcpPlayerAttribute aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
nsresult
|
||||
PackPDU(BluetoothAvrcpStatus aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
nsresult
|
||||
PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU);
|
||||
|
||||
@ -593,6 +613,11 @@ PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
|
||||
// Unpacking
|
||||
//
|
||||
|
||||
// introduce link errors on non-handled data types
|
||||
template <typename T>
|
||||
nsresult
|
||||
UnpackPDU(BluetoothDaemonPDU& aPDU, T& aOut);
|
||||
|
||||
inline nsresult
|
||||
UnpackPDU(BluetoothDaemonPDU& aPDU, int8_t& aOut)
|
||||
{
|
||||
@ -804,6 +829,19 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackArray<T>& aOut)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline nsresult
|
||||
UnpackPDU(BluetoothDaemonPDU& aPDU, UnpackArray<T>& aOut)
|
||||
{
|
||||
for (size_t i = 0; i < aOut.mLength; ++i) {
|
||||
nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline nsresult
|
||||
UnpackPDU<uint8_t>(BluetoothDaemonPDU& aPDU, const UnpackArray<uint8_t>& aOut)
|
||||
|
@ -5,6 +5,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BluetoothDaemonInterface.h"
|
||||
#include <cutils/properties.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include "BluetoothDaemonA2dpInterface.h"
|
||||
#include "BluetoothDaemonAvrcpInterface.h"
|
||||
#include "BluetoothDaemonHandsfreeInterface.h"
|
||||
@ -12,7 +15,10 @@
|
||||
#include "BluetoothDaemonSetupInterface.h"
|
||||
#include "BluetoothDaemonSocketInterface.h"
|
||||
#include "BluetoothInterfaceHelpers.h"
|
||||
#include "mozilla/ipc/ListenSocket.h"
|
||||
#include "mozilla/ipc/UnixSocketConnector.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "prrng.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
@ -1512,7 +1518,9 @@ class BluetoothDaemonProtocol MOZ_FINAL
|
||||
, public BluetoothDaemonAvrcpModule
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
|
||||
BluetoothDaemonProtocol();
|
||||
|
||||
void SetConnection(BluetoothDaemonConnection* aConnection);
|
||||
|
||||
nsresult RegisterModule(uint8_t aId, uint8_t aMode,
|
||||
BluetoothSetupResultHandler* aRes) MOZ_OVERRIDE;
|
||||
@ -1552,11 +1560,13 @@ private:
|
||||
nsTArray<void*> mUserDataQ;
|
||||
};
|
||||
|
||||
BluetoothDaemonProtocol::BluetoothDaemonProtocol(
|
||||
BluetoothDaemonConnection* aConnection)
|
||||
: mConnection(aConnection)
|
||||
BluetoothDaemonProtocol::BluetoothDaemonProtocol()
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothDaemonProtocol::SetConnection(BluetoothDaemonConnection* aConnection)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
mConnection = aConnection;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1576,6 +1586,7 @@ BluetoothDaemonProtocol::UnregisterModule(uint8_t aId,
|
||||
nsresult
|
||||
BluetoothDaemonProtocol::Send(BluetoothDaemonPDU* aPDU, void* aUserData)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(aPDU);
|
||||
|
||||
aPDU->SetUserData(aUserData);
|
||||
@ -1688,16 +1699,13 @@ BluetoothDaemonProtocol::FetchUserData(const BluetoothDaemonPDUHeader& aHeader)
|
||||
}
|
||||
|
||||
//
|
||||
// Channels
|
||||
// Listen socket
|
||||
//
|
||||
|
||||
class BluetoothDaemonChannel MOZ_FINAL : public BluetoothDaemonConnection
|
||||
class BluetoothDaemonListenSocket MOZ_FINAL : public ipc::ListenSocket
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonChannel(BluetoothDaemonInterface::Channel aChannel);
|
||||
|
||||
nsresult ConnectSocket(BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonPDUConsumer* aConsumer);
|
||||
BluetoothDaemonListenSocket(BluetoothDaemonInterface* aInterface);
|
||||
|
||||
// Connection state
|
||||
//
|
||||
@ -1706,28 +1714,80 @@ public:
|
||||
void OnConnectError() MOZ_OVERRIDE;
|
||||
void OnDisconnect() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
BluetoothDaemonInterface* mInterface;
|
||||
};
|
||||
|
||||
BluetoothDaemonListenSocket::BluetoothDaemonListenSocket(
|
||||
BluetoothDaemonInterface* aInterface)
|
||||
: mInterface(aInterface)
|
||||
{ }
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnConnectSuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectSuccess(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnConnectError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectError(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonListenSocket::OnDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnDisconnect(BluetoothDaemonInterface::LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
//
|
||||
// Channels
|
||||
//
|
||||
|
||||
class BluetoothDaemonChannel MOZ_FINAL : public BluetoothDaemonConnection
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonChannel(BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonInterface::Channel aChannel,
|
||||
BluetoothDaemonPDUConsumer* aConsumer);
|
||||
|
||||
// SocketBase
|
||||
//
|
||||
|
||||
void OnConnectSuccess() MOZ_OVERRIDE;
|
||||
void OnConnectError() MOZ_OVERRIDE;
|
||||
void OnDisconnect() MOZ_OVERRIDE;
|
||||
|
||||
// ConnectionOrientedSocket
|
||||
//
|
||||
|
||||
ConnectionOrientedSocketIO* GetIO() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
BluetoothDaemonInterface* mInterface;
|
||||
BluetoothDaemonInterface::Channel mChannel;
|
||||
BluetoothDaemonPDUConsumer* mConsumer;
|
||||
};
|
||||
|
||||
BluetoothDaemonChannel::BluetoothDaemonChannel(
|
||||
BluetoothDaemonInterface::Channel aChannel)
|
||||
: mInterface(nullptr)
|
||||
, mChannel(aChannel)
|
||||
BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonInterface::Channel aChannel,
|
||||
BluetoothDaemonPDUConsumer* aConsumer)
|
||||
: mInterface(aInterface)
|
||||
, mChannel(aChannel)
|
||||
, mConsumer(aConsumer)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
BluetoothDaemonChannel::ConnectSocket(BluetoothDaemonInterface* aInterface,
|
||||
BluetoothDaemonPDUConsumer* aConsumer)
|
||||
{
|
||||
MOZ_ASSERT(aInterface);
|
||||
|
||||
mInterface = aInterface;
|
||||
|
||||
return BluetoothDaemonConnection::ConnectSocket(aConsumer);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothDaemonChannel::OnConnectSuccess()
|
||||
{
|
||||
@ -1744,7 +1804,6 @@ BluetoothDaemonChannel::OnConnectError()
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnConnectError(mChannel);
|
||||
mInterface = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1754,7 +1813,12 @@ BluetoothDaemonChannel::OnDisconnect()
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->OnDisconnect(mChannel);
|
||||
mInterface = nullptr;
|
||||
}
|
||||
|
||||
ConnectionOrientedSocketIO*
|
||||
BluetoothDaemonChannel::GetIO()
|
||||
{
|
||||
return PrepareAccept(mConsumer);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1776,38 +1840,13 @@ BluetoothDaemonInterface::GetInstance()
|
||||
return sBluetoothInterface;
|
||||
}
|
||||
|
||||
// Only create channel objects here. The connection will be
|
||||
// established by |BluetoothDaemonInterface::Init|.
|
||||
|
||||
BluetoothDaemonChannel* cmdChannel =
|
||||
new BluetoothDaemonChannel(BluetoothDaemonInterface::CMD_CHANNEL);
|
||||
|
||||
BluetoothDaemonChannel* ntfChannel =
|
||||
new BluetoothDaemonChannel(BluetoothDaemonInterface::NTF_CHANNEL);
|
||||
|
||||
// Create a new interface object with the channels and a
|
||||
// protocol handler.
|
||||
|
||||
sBluetoothInterface =
|
||||
new BluetoothDaemonInterface(cmdChannel,
|
||||
ntfChannel,
|
||||
new BluetoothDaemonProtocol(cmdChannel));
|
||||
sBluetoothInterface = new BluetoothDaemonInterface();
|
||||
|
||||
return sBluetoothInterface;
|
||||
}
|
||||
|
||||
BluetoothDaemonInterface::BluetoothDaemonInterface(
|
||||
BluetoothDaemonChannel* aCmdChannel,
|
||||
BluetoothDaemonChannel* aNtfChannel,
|
||||
BluetoothDaemonProtocol* aProtocol)
|
||||
: mCmdChannel(aCmdChannel)
|
||||
, mNtfChannel(aNtfChannel)
|
||||
, mProtocol(aProtocol)
|
||||
{
|
||||
MOZ_ASSERT(mCmdChannel);
|
||||
MOZ_ASSERT(mNtfChannel);
|
||||
MOZ_ASSERT(mProtocol);
|
||||
}
|
||||
BluetoothDaemonInterface::BluetoothDaemonInterface()
|
||||
{ }
|
||||
|
||||
BluetoothDaemonInterface::~BluetoothDaemonInterface()
|
||||
{ }
|
||||
@ -1845,11 +1884,11 @@ public:
|
||||
|
||||
if (!mRegisteredSocketModule) {
|
||||
mRegisteredSocketModule = true;
|
||||
// Init, step 4: Register Socket module
|
||||
// Init, step 5: Register Socket module
|
||||
mInterface->mProtocol->RegisterModuleCmd(
|
||||
BluetoothDaemonSocketModule::SERVICE_ID, 0x00, this);
|
||||
} else if (mRes) {
|
||||
// Init, step 5: Signal success to caller
|
||||
// Init, step 6: Signal success to caller
|
||||
mRes->Init();
|
||||
}
|
||||
}
|
||||
@ -1867,24 +1906,33 @@ BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel)
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aChannel) {
|
||||
case CMD_CHANNEL:
|
||||
// Init, step 2: Connect notification channel...
|
||||
if (mNtfChannel->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
nsresult rv = mNtfChannel->ConnectSocket(this, mProtocol);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnConnectError(NTF_CHANNEL);
|
||||
case LISTEN_SOCKET: {
|
||||
// Init, step 2: Start Bluetooth daemon */
|
||||
nsCString value("bluetoothd:-a ");
|
||||
value.Append(mListenSocketName);
|
||||
if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
|
||||
OnConnectError(CMD_CHANNEL);
|
||||
}
|
||||
} else {
|
||||
// ...or go to step 3 if channel is already connected.
|
||||
OnConnectSuccess(NTF_CHANNEL);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_CHANNEL:
|
||||
// Init, step 3: Listen for notification channel...
|
||||
if (!mNtfChannel) {
|
||||
mNtfChannel = new BluetoothDaemonChannel(this, NTF_CHANNEL, mProtocol);
|
||||
} else if (
|
||||
NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
|
||||
/* Notification channel should not be open; let's close it. */
|
||||
mNtfChannel->CloseSocket();
|
||||
}
|
||||
if (!mListenSocket->Listen(mNtfChannel)) {
|
||||
OnConnectError(NTF_CHANNEL);
|
||||
}
|
||||
break;
|
||||
case NTF_CHANNEL: {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
// Init, step 3: Register Core module
|
||||
// Init, step 4: Register Core module
|
||||
nsresult rv = mProtocol->RegisterModuleCmd(
|
||||
BluetoothDaemonCoreModule::SERVICE_ID, 0x00,
|
||||
new InitResultHandler(this, res));
|
||||
@ -1907,7 +1955,11 @@ BluetoothDaemonInterface::OnConnectError(enum Channel aChannel)
|
||||
// Close command channel
|
||||
mCmdChannel->CloseSocket();
|
||||
/* fall through for cleanup and error signalling */
|
||||
case CMD_CHANNEL: {
|
||||
case CMD_CHANNEL:
|
||||
// Stop daemon and close listen socket
|
||||
unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd"));
|
||||
mListenSocket->Close();
|
||||
case LISTEN_SOCKET: {
|
||||
// Signal error to caller
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
@ -1927,11 +1979,15 @@ BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aChannel) {
|
||||
case NTF_CHANNEL:
|
||||
// Cleanup, step 4: Close command channel
|
||||
mCmdChannel->CloseSocket();
|
||||
case CMD_CHANNEL:
|
||||
// We don't have to do anything here. Step 4 is triggered
|
||||
// by the daemon.
|
||||
break;
|
||||
case CMD_CHANNEL: {
|
||||
case NTF_CHANNEL:
|
||||
// Cleanup, step 4: Close listen socket
|
||||
mListenSocket->Close();
|
||||
break;
|
||||
case LISTEN_SOCKET: {
|
||||
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
@ -1944,25 +2000,207 @@ BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
class BluetoothDaemonSocketConnector MOZ_FINAL
|
||||
: public mozilla::ipc::UnixSocketConnector
|
||||
{
|
||||
public:
|
||||
BluetoothDaemonSocketConnector(const nsACString& aSocketName)
|
||||
: mSocketName(aSocketName)
|
||||
{ }
|
||||
|
||||
int
|
||||
Create() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
if (fd < 0) {
|
||||
BT_WARNING("Could not open socket!");
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
CreateAddr(bool aIsServer,
|
||||
socklen_t& aAddrSize,
|
||||
sockaddr_any& aAddr,
|
||||
const char* aAddress) MOZ_OVERRIDE
|
||||
{
|
||||
static const size_t sNameOffset = 1;
|
||||
|
||||
size_t namesiz = mSocketName.Length() + 1; /* include trailing '\0' */
|
||||
|
||||
if ((sNameOffset + namesiz) > sizeof(aAddr.un.sun_path)) {
|
||||
BT_WARNING("Address too long for socket struct!");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(aAddr.un.sun_path, '\0', sNameOffset); // abstract socket
|
||||
memcpy(aAddr.un.sun_path + sNameOffset, mSocketName.get(), namesiz);
|
||||
aAddr.un.sun_family = AF_UNIX;
|
||||
|
||||
aAddrSize = offsetof(struct sockaddr_un, sun_path) + sNameOffset + namesiz;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetUp(int aFd) MOZ_OVERRIDE
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, O_NONBLOCK)) < 0) {
|
||||
BT_WARNING("Failed to set non-blocking I/O.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetUpListenSocket(int aFd) MOZ_OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GetSocketAddr(const sockaddr_any& aAddr, nsAString& aAddrStr) MOZ_OVERRIDE
|
||||
{
|
||||
// Unused.
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mSocketName;
|
||||
};
|
||||
|
||||
nsresult
|
||||
BluetoothDaemonInterface::CreateRandomAddressString(
|
||||
const nsACString& aPrefix, unsigned long aPostfixLength,
|
||||
nsACString& aAddress)
|
||||
{
|
||||
static const char sHexChar[16] = {
|
||||
[0x0] = '0', [0x1] = '1', [0x2] = '2', [0x3] = '3',
|
||||
[0x4] = '4', [0x5] = '5', [0x6] = '6', [0x7] = '7',
|
||||
[0x8] = '8', [0x9] = '9', [0xa] = 'a', [0xb] = 'b',
|
||||
[0xc] = 'c', [0xd] = 'd', [0xe] = 'e', [0xf] = 'f'
|
||||
};
|
||||
|
||||
unsigned short seed[3];
|
||||
|
||||
if (NS_WARN_IF(!PR_GetRandomNoise(seed, sizeof(seed)))) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
aAddress = aPrefix;
|
||||
aAddress.Append('-');
|
||||
|
||||
while (aPostfixLength) {
|
||||
|
||||
// Android doesn't provide rand_r, so we use nrand48 here,
|
||||
// even though it's deprecated.
|
||||
long value = nrand48(seed);
|
||||
|
||||
size_t bits = sizeof(value) * CHAR_BIT;
|
||||
|
||||
while ((bits > 4) && aPostfixLength) {
|
||||
aAddress.Append(sHexChar[value&0xf]);
|
||||
bits -= 4;
|
||||
value >>= 4;
|
||||
--aPostfixLength;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The init procedure consists of several steps.
|
||||
*
|
||||
* (1) Start listening for the command channel's socket connection: We
|
||||
* do this before anything else, so that we don't miss connection
|
||||
* requests from the Bluetooth daemon. This step will create a
|
||||
* listen socket.
|
||||
*
|
||||
* (2) Start the Bluetooth daemon: When the daemon starts up it will
|
||||
* open two socket connections to Gecko and thus create the command
|
||||
* and notification channels. Gecko already opened the listen socket
|
||||
* in step (1). Step (2) ends with the creation of the command channel.
|
||||
*
|
||||
* (3) Start listening for the notification channel's socket connection:
|
||||
* At the end of step (2), the command channel was opened by the
|
||||
* daemon. In step (3), the daemon immediately tries to open the
|
||||
* next socket for the notification channel. Gecko will accept the
|
||||
* incoming connection request for the notification channel. The
|
||||
* listen socket remained open after step (2), so there's no race
|
||||
* condition between Gecko and the Bluetooth daemon.
|
||||
*
|
||||
* (4)(5) Register Core and Socket modules: The Core and Socket modules
|
||||
* are always available and have to be registered after opening the
|
||||
* socket connections during the initialization.
|
||||
*
|
||||
* (6) Signal success to the caller.
|
||||
*
|
||||
* If any step fails, we roll-back the procedure and signal an error to the
|
||||
* caller.
|
||||
*/
|
||||
void
|
||||
BluetoothDaemonInterface::Init(
|
||||
BluetoothNotificationHandler* aNotificationHandler,
|
||||
BluetoothResultHandler* aRes)
|
||||
{
|
||||
static const char BASE_SOCKET_NAME[] = "bluetoothd";
|
||||
static unsigned long POSTFIX_LENGTH = 16;
|
||||
|
||||
// If we could not cleanup properly before and an old
|
||||
// instance of the daemon is still running, we kill it
|
||||
// here.
|
||||
unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd"));
|
||||
|
||||
sNotificationHandler = aNotificationHandler;
|
||||
|
||||
mResultHandlerQ.AppendElement(aRes);
|
||||
|
||||
// Init, step 1: Connect command channel...
|
||||
if (mCmdChannel->GetConnectionStatus() != SOCKET_CONNECTED) {
|
||||
nsresult rv = mCmdChannel->ConnectSocket(this, mProtocol);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnConnectError(CMD_CHANNEL);
|
||||
}
|
||||
} else {
|
||||
// ...or go to step 2 if channel is already connected.
|
||||
OnConnectSuccess(CMD_CHANNEL);
|
||||
if (!mProtocol) {
|
||||
mProtocol = new BluetoothDaemonProtocol();
|
||||
}
|
||||
|
||||
if (!mListenSocket) {
|
||||
mListenSocket = new BluetoothDaemonListenSocket(this);
|
||||
}
|
||||
|
||||
// Init, step 1: Listen for command channel... */
|
||||
|
||||
if (!mCmdChannel) {
|
||||
mCmdChannel = new BluetoothDaemonChannel(this, CMD_CHANNEL, mProtocol);
|
||||
} else if (
|
||||
NS_WARN_IF(mCmdChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
|
||||
// Command channel should not be open; let's close it.
|
||||
mCmdChannel->CloseSocket();
|
||||
}
|
||||
|
||||
// The listen socket's name is generated with a random postfix. This
|
||||
// avoids naming collisions if we still have a listen socket from a
|
||||
// previously failed cleanup. It also makes it hard for malicious
|
||||
// external programs to capture the socket name or connect before
|
||||
// the daemon can do so. If no random postfix can be generated, we
|
||||
// simply use the base name as-is.
|
||||
nsresult rv = CreateRandomAddressString(NS_LITERAL_CSTRING(BASE_SOCKET_NAME),
|
||||
POSTFIX_LENGTH,
|
||||
mListenSocketName);
|
||||
if (NS_FAILED(rv)) {
|
||||
mListenSocketName = BASE_SOCKET_NAME;
|
||||
}
|
||||
|
||||
bool success = mListenSocket->Listen(
|
||||
new BluetoothDaemonSocketConnector(mListenSocketName), mCmdChannel);
|
||||
if (!success) {
|
||||
OnConnectError(CMD_CHANNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
// The protocol implementation needs a command channel for
|
||||
// sending commands to the daemon. We set it here, because
|
||||
// this is the earliest time when it's available.
|
||||
mProtocol->SetConnection(mCmdChannel);
|
||||
}
|
||||
|
||||
class BluetoothDaemonInterface::CleanupResultHandler MOZ_FINAL
|
||||
@ -1998,8 +2236,8 @@ private:
|
||||
mInterface->mProtocol->UnregisterModuleCmd(
|
||||
BluetoothDaemonCoreModule::SERVICE_ID, this);
|
||||
} else {
|
||||
// Cleanup, step 3: Close notification channel
|
||||
mInterface->mNtfChannel->CloseSocket();
|
||||
// Cleanup, step 3: Close command channel
|
||||
mInterface->mCmdChannel->CloseSocket();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2007,6 +2245,31 @@ private:
|
||||
bool mUnregisteredCoreModule;
|
||||
};
|
||||
|
||||
/*
|
||||
* Cleaning up is inverse to initialization, except for the shutdown
|
||||
* of the socket connections in step (3)
|
||||
*
|
||||
* (1)(2) Unregister Socket and Core modules: These modules have been
|
||||
* registered during initialization and need to be unregistered
|
||||
* here. We assume that all other modules are already unregistered.
|
||||
*
|
||||
* (3) Close command socket: We only close the command socket. The
|
||||
* daemon will then send any final notifications and close the
|
||||
* notification socket on its side. Once we see the notification
|
||||
* socket's disconnect, we continue with the cleanup.
|
||||
*
|
||||
* (4) Close listen socket: The listen socket is not active any longer
|
||||
* and we simply close it.
|
||||
*
|
||||
* (5) Signal success to the caller.
|
||||
*
|
||||
* We don't have to stop the daemon explicitly. It will cleanup and quit
|
||||
* after it closed the notification socket.
|
||||
*
|
||||
* Rolling-back half-completed cleanups is not possible. In the case of
|
||||
* an error, we simply push forward and try to recover during the next
|
||||
* initialization.
|
||||
*/
|
||||
void
|
||||
BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
|
||||
{
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothDaemonListenSocket;
|
||||
class BluetoothDaemonChannel;
|
||||
class BluetoothDaemonA2dpInterface;
|
||||
class BluetoothDaemonAvrcpInterface;
|
||||
@ -24,6 +25,7 @@ public:
|
||||
class CleanupResultHandler;
|
||||
class InitResultHandler;
|
||||
|
||||
friend class BluetoothDaemonListenSocket;
|
||||
friend class BluetoothDaemonChannel;
|
||||
friend class CleanupResultHandler;
|
||||
friend class InitResultHandler;
|
||||
@ -106,24 +108,29 @@ public:
|
||||
|
||||
protected:
|
||||
enum Channel {
|
||||
LISTEN_SOCKET,
|
||||
CMD_CHANNEL,
|
||||
NTF_CHANNEL
|
||||
};
|
||||
|
||||
BluetoothDaemonInterface(BluetoothDaemonChannel* aCmdChannel,
|
||||
BluetoothDaemonChannel* aNtfChannel,
|
||||
BluetoothDaemonProtocol* aProtocol);
|
||||
BluetoothDaemonInterface();
|
||||
~BluetoothDaemonInterface();
|
||||
|
||||
void OnConnectSuccess(enum Channel aChannel);
|
||||
void OnConnectError(enum Channel aChannel);
|
||||
void OnDisconnect(enum Channel aChannel);
|
||||
|
||||
nsresult CreateRandomAddressString(const nsACString& aPrefix,
|
||||
unsigned long aPostfixLength,
|
||||
nsACString& aAddress);
|
||||
|
||||
private:
|
||||
void DispatchError(BluetoothResultHandler* aRes, BluetoothStatus aStatus);
|
||||
|
||||
nsAutoPtr<BluetoothDaemonChannel> mCmdChannel;
|
||||
nsAutoPtr<BluetoothDaemonChannel> mNtfChannel;
|
||||
nsCString mListenSocketName;
|
||||
nsRefPtr<BluetoothDaemonListenSocket> mListenSocket;
|
||||
nsRefPtr<BluetoothDaemonChannel> mCmdChannel;
|
||||
nsRefPtr<BluetoothDaemonChannel> mNtfChannel;
|
||||
nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
|
||||
|
||||
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
|
||||
|
@ -35,7 +35,7 @@ BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
|
||||
aType,
|
||||
PackConversion<nsAString, BluetoothServiceName>(aServiceName),
|
||||
PackArray<uint8_t>(aServiceUuid, 16),
|
||||
PackConversion<int, uint16_t>(aChannel),
|
||||
PackConversion<int, int32_t>(aChannel),
|
||||
SocketFlags(aEncrypt, aAuth), *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
@ -65,7 +65,7 @@ BluetoothDaemonSocketModule::ConnectCmd(const nsAString& aBdAddr,
|
||||
PackConversion<nsAString, BluetoothAddress>(aBdAddr),
|
||||
aType,
|
||||
PackArray<uint8_t>(aUuid, 16),
|
||||
PackConversion<int, int16_t>(aChannel),
|
||||
PackConversion<int, int32_t>(aChannel),
|
||||
SocketFlags(aEncrypt, aAuth), *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -89,6 +89,8 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
]
|
||||
|
||||
DEFINES['MOZ_B2G_BT_BLUEDROID'] = True
|
||||
if CONFIG['MOZ_B2G_BT_DAEMON']:
|
||||
DEFINES['MOZ_B2G_BT_DAEMON'] = True
|
||||
elif CONFIG['MOZ_ENABLE_DBUS']:
|
||||
CFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
|
||||
CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
|
||||
|
@ -135,6 +135,9 @@ if CONFIG['MOZ_GAMEPAD']:
|
||||
if CONFIG['MOZ_NFC']:
|
||||
DIRS += ['nfc']
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
DIRS += ['secureelement']
|
||||
|
||||
if CONFIG['MOZ_B2G']:
|
||||
DIRS += [
|
||||
'downloads',
|
||||
|
566
dom/secureelement/DOMSecureElement.js
Normal file
566
dom/secureelement/DOMSecureElement.js
Normal file
@ -0,0 +1,566 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2014, Deutsche Telekom, Inc. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* globals dump, Components, XPCOMUtils, DOMRequestIpcHelper, cpmm, SE */
|
||||
|
||||
const DEBUG = false;
|
||||
function debug(s) {
|
||||
if (DEBUG) {
|
||||
dump("-*- SecureElement DOM: " + s + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SE", function() {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/se_consts.js", obj);
|
||||
return obj;
|
||||
});
|
||||
|
||||
function PromiseHelpersSubclass(win) {
|
||||
this._window = win;
|
||||
}
|
||||
|
||||
PromiseHelpersSubclass.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_window: null,
|
||||
|
||||
_context: [],
|
||||
|
||||
createSEPromise: function createSEPromise(callback, /* optional */ ctx) {
|
||||
let ctxCallback = (resolverId) => {
|
||||
if (ctx) {
|
||||
this._context[resolverId] = ctx;
|
||||
}
|
||||
|
||||
callback(resolverId);
|
||||
};
|
||||
|
||||
return this.createPromise((resolve, reject) => {
|
||||
let resolverId = this.getPromiseResolverId({
|
||||
resolve: resolve,
|
||||
reject: reject
|
||||
});
|
||||
ctxCallback(resolverId);
|
||||
});
|
||||
},
|
||||
|
||||
takePromise: function takePromise(resolverId) {
|
||||
let resolver = this.takePromiseResolver(resolverId);
|
||||
if (!resolver) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the context associated with this resolverId
|
||||
let context = this._context[resolverId];
|
||||
delete this._context[resolverId];
|
||||
|
||||
return {resolver: resolver, context: context};
|
||||
},
|
||||
|
||||
rejectWithSEError: function rejectWithSEError(reason) {
|
||||
return this.createSEPromise((resolverId) => {
|
||||
debug("rejectWithSEError : " + reason);
|
||||
this.takePromiseResolver(resolverId).reject(new Error(reason));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Helper wrapper class to do promises related chores
|
||||
let PromiseHelpers;
|
||||
|
||||
/**
|
||||
* Instance of 'SEReaderImpl' class is the connector to a secure element.
|
||||
* A reader may or may not have a secure element present, since some
|
||||
* secure elements are removable in nature (eg:- 'uicc'). These
|
||||
* Readers can be physical devices or virtual devices.
|
||||
*/
|
||||
function SEReaderImpl() {}
|
||||
|
||||
SEReaderImpl.prototype = {
|
||||
_window: null,
|
||||
|
||||
_sessions: [],
|
||||
|
||||
type: null,
|
||||
|
||||
classID: Components.ID("{1c7bdba3-cd35-4f8b-a546-55b3232457d5}"),
|
||||
contractID: "@mozilla.org/secureelement/reader;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
// Chrome-only function
|
||||
onSessionClose: function onSessionClose(sessionCtx) {
|
||||
let index = this._sessions.indexOf(sessionCtx);
|
||||
if (index != -1) {
|
||||
this._sessions.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function initialize(win, type) {
|
||||
this._window = win;
|
||||
this.type = type;
|
||||
},
|
||||
|
||||
openSession: function openSession() {
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
let chromeObj = new SESessionImpl();
|
||||
chromeObj.initialize(this._window, this);
|
||||
let contentObj = this._window.SESession._create(this._window, chromeObj);
|
||||
this._sessions.push(contentObj);
|
||||
PromiseHelpers.takePromiseResolver(resolverId).resolve(contentObj);
|
||||
});
|
||||
},
|
||||
|
||||
closeAll: function closeAll() {
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
let promises = [];
|
||||
for (let session of this._sessions) {
|
||||
if (!session.isClosed) {
|
||||
promises.push(session.closeAll());
|
||||
}
|
||||
}
|
||||
|
||||
let resolver = PromiseHelpers.takePromiseResolver(resolverId);
|
||||
// Wait till all the promises are resolved
|
||||
Promise.all(promises).then(() => {
|
||||
this._sessions = [];
|
||||
resolver.resolve();
|
||||
}, (reason) => {
|
||||
resolver.reject(new Error(SE.ERROR_BADSTATE +
|
||||
" Unable to close all channels associated with this reader"));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get isSEPresent() {
|
||||
// TODO: Bug 1119152 - Implement new idl with interfaces to detect
|
||||
// secureelement state changes.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instance of 'SESessionImpl' object represent a connection session
|
||||
* to one of the secure elements available on the device.
|
||||
* These objects can be used to get a communication channel with an application
|
||||
* hosted by the Secure Element.
|
||||
*/
|
||||
function SESessionImpl() {}
|
||||
|
||||
SESessionImpl.prototype = {
|
||||
_window: null,
|
||||
|
||||
_channels: [],
|
||||
|
||||
_isClosed: false,
|
||||
|
||||
_reader: null,
|
||||
|
||||
classID: Components.ID("{2b1809f8-17bd-4947-abd7-bdef1498561c}"),
|
||||
contractID: "@mozilla.org/secureelement/session;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
// Private function
|
||||
_checkClosed: function _checkClosed() {
|
||||
if (this._isClosed) {
|
||||
throw new Error(SE.ERROR_BADSTATE + " Session Already Closed!");
|
||||
}
|
||||
},
|
||||
|
||||
// Chrome-only function
|
||||
onChannelOpen: function onChannelOpen(channelCtx) {
|
||||
this._channels.push(channelCtx);
|
||||
},
|
||||
|
||||
// Chrome-only function
|
||||
onChannelClose: function onChannelClose(channelCtx) {
|
||||
let index = this._channels.indexOf(channelCtx);
|
||||
if (index != -1) {
|
||||
this._channels.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function initialize(win, readerCtx) {
|
||||
this._window = win;
|
||||
this._reader = readerCtx;
|
||||
},
|
||||
|
||||
openLogicalChannel: function openLogicalChannel(aid) {
|
||||
this._checkClosed();
|
||||
|
||||
let aidLen = aid ? aid.length : 0;
|
||||
if (aidLen < SE.MIN_AID_LEN || aidLen > SE.MAX_AID_LEN) {
|
||||
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
||||
" Invalid AID length - " + aidLen);
|
||||
}
|
||||
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
/**
|
||||
* @params for 'SE:OpenChannel'
|
||||
*
|
||||
* resolverId : ID that identifies this IPC request.
|
||||
* aid : AID that identifies the applet on SecureElement
|
||||
* type : Reader type ('uicc' / 'eSE')
|
||||
* appId : Current appId obtained from 'Principal' obj
|
||||
*/
|
||||
cpmm.sendAsyncMessage("SE:OpenChannel", {
|
||||
resolverId: resolverId,
|
||||
aid: aid,
|
||||
type: this.reader.type,
|
||||
appId: this._window.document.nodePrincipal.appId
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
closeAll: function closeAll() {
|
||||
this._checkClosed();
|
||||
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
let promises = [];
|
||||
for (let channel of this._channels) {
|
||||
if (!channel.isClosed) {
|
||||
promises.push(channel.close());
|
||||
}
|
||||
}
|
||||
|
||||
let resolver = PromiseHelpers.takePromiseResolver(resolverId);
|
||||
Promise.all(promises).then(() => {
|
||||
this._isClosed = true;
|
||||
this._channels = [];
|
||||
// Notify parent of this session instance's closure, so that its
|
||||
// instance entry can be removed from the parent as well.
|
||||
this._reader.onSessionClose(this.__DOM_IMPL__);
|
||||
resolver.resolve();
|
||||
}, (reason) => {
|
||||
resolver.reject(new Error(SE.ERROR_BADSTATE +
|
||||
" Unable to close all channels associated with this session"));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get reader() {
|
||||
return this._reader.__DOM_IMPL__;
|
||||
},
|
||||
|
||||
get isClosed() {
|
||||
return this._isClosed;
|
||||
},
|
||||
|
||||
set isClosed(isClosed) {
|
||||
this._isClosed = isClosed;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instance of 'SEChannelImpl' object represent an ISO/IEC 7816-4 specification
|
||||
* channel opened to a secure element. It can be either a logical channel
|
||||
* or basic channel.
|
||||
*/
|
||||
function SEChannelImpl() {}
|
||||
|
||||
SEChannelImpl.prototype = {
|
||||
_window: null,
|
||||
|
||||
_channelToken: null,
|
||||
|
||||
_isClosed: false,
|
||||
|
||||
_session: null,
|
||||
|
||||
openResponse: [],
|
||||
|
||||
type: null,
|
||||
|
||||
classID: Components.ID("{181ebcf4-5164-4e28-99f2-877ec6fa83b9}"),
|
||||
contractID: "@mozilla.org/secureelement/channel;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
_checkClosed: function _checkClosed() {
|
||||
if (this._isClosed) {
|
||||
throw new Error(SE.ERROR_BADSTATE + " Channel Already Closed!");
|
||||
}
|
||||
},
|
||||
|
||||
// Chrome-only function
|
||||
onClose: function onClose() {
|
||||
this._isClosed = true;
|
||||
// Notify the parent
|
||||
this._session.onChannelClose(this.__DOM_IMPL__);
|
||||
},
|
||||
|
||||
initialize: function initialize(win, channelToken, isBasicChannel,
|
||||
openResponse, sessionCtx) {
|
||||
this._window = win;
|
||||
// Update the 'channel token' that identifies and represents this
|
||||
// instance of the object
|
||||
this._channelToken = channelToken;
|
||||
// Update 'session' obj
|
||||
this._session = sessionCtx;
|
||||
this.openResponse = Cu.cloneInto(new Uint8Array(openResponse), win);
|
||||
this.type = isBasicChannel ? "basic" : "logical";
|
||||
},
|
||||
|
||||
transmit: function transmit(command) {
|
||||
// TODO remove this once it will be possible to have a non-optional dict
|
||||
// in the WebIDL
|
||||
if (!command) {
|
||||
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
||||
" SECommand dict must be defined");
|
||||
}
|
||||
|
||||
this._checkClosed();
|
||||
|
||||
let dataLen = command.data ? command.data.length : 0;
|
||||
if (dataLen > SE.MAX_APDU_LEN) {
|
||||
return PromiseHelpers.rejectWithSEError(SE.ERROR_GENERIC +
|
||||
" Command data length exceeds max limit - 255. " +
|
||||
" Extended APDU is not supported!");
|
||||
}
|
||||
|
||||
if ((command.cla & 0x80 === 0) && ((command.cla & 0x60) !== 0x20)) {
|
||||
if (command.ins === SE.INS_MANAGE_CHANNEL) {
|
||||
return PromiseHelpers.rejectWithSEError(SE.ERROR_SECURITY +
|
||||
", MANAGE CHANNEL command not permitted");
|
||||
}
|
||||
if ((command.ins === SE.INS_SELECT) && (command.p1 == 0x04)) {
|
||||
// SELECT by DF Name (p1=04) is not allowed
|
||||
return PromiseHelpers.rejectWithSEError(SE.ERROR_SECURITY +
|
||||
", SELECT command not permitted");
|
||||
}
|
||||
debug("Attempting to transmit an ISO command");
|
||||
} else {
|
||||
debug("Attempting to transmit GlobalPlatform command");
|
||||
}
|
||||
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
/**
|
||||
* @params for 'SE:TransmitAPDU'
|
||||
*
|
||||
* resolverId : Id that identifies this IPC request.
|
||||
* apdu : Object containing APDU data
|
||||
* channelToken: Token that identifies the current channel over which
|
||||
'c-apdu' is being sent.
|
||||
* appId : Current appId obtained from 'Principal' obj
|
||||
*/
|
||||
cpmm.sendAsyncMessage("SE:TransmitAPDU", {
|
||||
resolverId: resolverId,
|
||||
apdu: command,
|
||||
channelToken: this._channelToken,
|
||||
appId: this._window.document.nodePrincipal.appId
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
close: function close() {
|
||||
this._checkClosed();
|
||||
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
/**
|
||||
* @params for 'SE:CloseChannel'
|
||||
*
|
||||
* resolverId : Id that identifies this IPC request.
|
||||
* channelToken: Token that identifies the current channel over which
|
||||
'c-apdu' is being sent.
|
||||
* appId : Current appId obtained from 'Principal' obj
|
||||
*/
|
||||
cpmm.sendAsyncMessage("SE:CloseChannel", {
|
||||
resolverId: resolverId,
|
||||
channelToken: this._channelToken,
|
||||
appId: this._window.document.nodePrincipal.appId
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
get session() {
|
||||
return this._session.__DOM_IMPL__;
|
||||
},
|
||||
|
||||
get isClosed() {
|
||||
return this._isClosed;
|
||||
},
|
||||
|
||||
set isClosed(isClosed) {
|
||||
this._isClosed = isClosed;
|
||||
}
|
||||
};
|
||||
|
||||
function SEResponseImpl() {}
|
||||
|
||||
SEResponseImpl.prototype = {
|
||||
sw1: 0x00,
|
||||
|
||||
sw2: 0x00,
|
||||
|
||||
data: null,
|
||||
|
||||
_channel: null,
|
||||
|
||||
classID: Components.ID("{58bc6c7b-686c-47cc-8867-578a6ed23f4e}"),
|
||||
contractID: "@mozilla.org/secureelement/response;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([]),
|
||||
|
||||
initialize: function initialize(sw1, sw2, response, channelCtx) {
|
||||
// Update the status bytes
|
||||
this.sw1 = sw1;
|
||||
this.sw2 = sw2;
|
||||
this.data = response ? response.slice(0) : null;
|
||||
// Update the channel obj
|
||||
this._channel = channelCtx;
|
||||
},
|
||||
|
||||
get channel() {
|
||||
return this._channel.__DOM_IMPL__;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SEManagerImpl
|
||||
*/
|
||||
function SEManagerImpl() {}
|
||||
|
||||
SEManagerImpl.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_window: null,
|
||||
|
||||
classID: Components.ID("{4a8b6ec0-4674-11e4-916c-0800200c9a66}"),
|
||||
contractID: "@mozilla.org/secureelement/manager;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver
|
||||
]),
|
||||
|
||||
init: function init(win) {
|
||||
this._window = win;
|
||||
PromiseHelpers = new PromiseHelpersSubclass(this._window);
|
||||
|
||||
// Add the messages to be listened to.
|
||||
const messages = ["SE:GetSEReadersResolved",
|
||||
"SE:OpenChannelResolved",
|
||||
"SE:CloseChannelResolved",
|
||||
"SE:TransmitAPDUResolved",
|
||||
"SE:GetSEReadersRejected",
|
||||
"SE:OpenChannelRejected",
|
||||
"SE:CloseChannelRejected",
|
||||
"SE:TransmitAPDURejected"];
|
||||
|
||||
this.initDOMRequestHelper(win, messages);
|
||||
},
|
||||
|
||||
// This function will be called from DOMRequestIPCHelper.
|
||||
uninit: function uninit() {
|
||||
// All requests that are still pending need to be invalidated
|
||||
// because the context is no longer valid.
|
||||
this.forEachPromiseResolver((k) => {
|
||||
this.takePromiseResolver(k).reject("Window Context got destroyed!");
|
||||
});
|
||||
PromiseHelpers = null;
|
||||
this._window = null;
|
||||
},
|
||||
|
||||
getSEReaders: function getSEReaders() {
|
||||
return PromiseHelpers.createSEPromise((resolverId) => {
|
||||
/**
|
||||
* @params for 'SE:GetSEReaders'
|
||||
*
|
||||
* resolverId : Id that identifies this IPC request.
|
||||
* appId : Current appId obtained from 'Principal' obj
|
||||
*/
|
||||
cpmm.sendAsyncMessage("SE:GetSEReaders", {
|
||||
resolverId: resolverId,
|
||||
appId: this._window.document.nodePrincipal.appId
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(message) {
|
||||
let result = message.data.result;
|
||||
let chromeObj = null;
|
||||
let contentObj = null;
|
||||
let resolver = null;
|
||||
let context = null;
|
||||
|
||||
let promiseResolver = PromiseHelpers.takePromise(result.resolverId);
|
||||
if (promiseResolver) {
|
||||
resolver = promiseResolver.resolver;
|
||||
// This 'context' is the instance that originated this IPC message.
|
||||
context = promiseResolver.context;
|
||||
}
|
||||
|
||||
debug("receiveMessage(): " + message.name);
|
||||
switch (message.name) {
|
||||
case "SE:GetSEReadersResolved":
|
||||
let readers = new this._window.Array();
|
||||
for (let i = 0; i < result.readerTypes.length; i++) {
|
||||
chromeObj = new SEReaderImpl();
|
||||
chromeObj.initialize(this._window, result.readerTypes[i]);
|
||||
contentObj = this._window.SEReader._create(this._window, chromeObj);
|
||||
readers.push(contentObj);
|
||||
}
|
||||
resolver.resolve(readers);
|
||||
break;
|
||||
case "SE:OpenChannelResolved":
|
||||
chromeObj = new SEChannelImpl();
|
||||
chromeObj.initialize(this._window,
|
||||
result.channelToken,
|
||||
result.isBasicChannel,
|
||||
result.openResponse,
|
||||
context);
|
||||
contentObj = this._window.SEChannel._create(this._window, chromeObj);
|
||||
if (context) {
|
||||
// Notify context's handler with SEChannel instance
|
||||
context.onChannelOpen(contentObj);
|
||||
}
|
||||
resolver.resolve(contentObj);
|
||||
break;
|
||||
case "SE:TransmitAPDUResolved":
|
||||
chromeObj = new SEResponseImpl();
|
||||
chromeObj.initialize(result.sw1,
|
||||
result.sw2,
|
||||
result.response,
|
||||
context);
|
||||
contentObj = this._window.SEResponse._create(this._window, chromeObj);
|
||||
resolver.resolve(contentObj);
|
||||
break;
|
||||
case "SE:CloseChannelResolved":
|
||||
if (context) {
|
||||
// Notify context's onClose handler
|
||||
context.onClose();
|
||||
}
|
||||
resolver.resolve();
|
||||
break;
|
||||
case "SE:GetSEReadersRejected":
|
||||
case "SE:OpenChannelRejected":
|
||||
case "SE:CloseChannelRejected":
|
||||
case "SE:TransmitAPDURejected":
|
||||
let error = result.error || SE.ERROR_GENERIC;
|
||||
resolver.reject(error);
|
||||
break;
|
||||
default:
|
||||
debug("Could not find a handler for " + message.name);
|
||||
resolver.reject();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
|
||||
SEResponseImpl, SEChannelImpl, SESessionImpl, SEReaderImpl, SEManagerImpl
|
||||
]);
|
21
dom/secureelement/DOMSecureElement.manifest
Normal file
21
dom/secureelement/DOMSecureElement.manifest
Normal file
@ -0,0 +1,21 @@
|
||||
component {4a8b6ec0-4674-11e4-916c-0800200c9a66} DOMSecureElement.js
|
||||
contract @mozilla.org/secureelement/manager;1 {4a8b6ec0-4674-11e4-916c-0800200c9a66}
|
||||
|
||||
component {1c7bdba3-cd35-4f8b-a546-55b3232457d5} DOMSecureElement.js
|
||||
contract @mozilla.org/secureelement/reader;1 {1c7bdba3-cd35-4f8b-a546-55b3232457d5}
|
||||
|
||||
component {2b1809f8-17bd-4947-abd7-bdef1498561c} DOMSecureElement.js
|
||||
contract @mozilla.org/secureelement/session;1 {2b1809f8-17bd-4947-abd7-bdef1498561c}
|
||||
|
||||
component {181ebcf4-5164-4e28-99f2-877ec6fa83b9} DOMSecureElement.js
|
||||
contract @mozilla.org/secureelement/channel;1 {181ebcf4-5164-4e28-99f2-877ec6fa83b9}
|
||||
|
||||
# component {cb8ccb1c-0e99-4a62-bf7d-11acc13848e0} DOMSecureElement.js
|
||||
# contract @mozilla.org/secureelement/command;1 {cb8ccb1c-0e99-4a62-bf7d-11acc13848e0}
|
||||
|
||||
component {58bc6c7b-686c-47cc-8867-578a6ed23f4e} DOMSecureElement.js
|
||||
contract @mozilla.org/secureelement/response;1 {58bc6c7b-686c-47cc-8867-578a6ed23f4e}
|
||||
|
||||
|
||||
|
||||
|
55
dom/secureelement/SEUtils.jsm
Normal file
55
dom/secureelement/SEUtils.jsm
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2015, Deutsche Telekom, Inc. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.SEUtils = {
|
||||
byteArrayToHexString: function byteArrayToHexString(array) {
|
||||
let hexStr = "";
|
||||
|
||||
let len = array ? array.length : 0;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let hex = (array[i] & 0xff).toString(16);
|
||||
hex = (hex.length === 1) ? "0" + hex : hex;
|
||||
hexStr += hex;
|
||||
}
|
||||
|
||||
return hexStr.toUpperCase();
|
||||
},
|
||||
|
||||
hexStringToByteArray: function hexStringToByteArray(hexStr) {
|
||||
if (typeof hexStr !== "string" || hexStr.length % 2 !== 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let array = [];
|
||||
for (let i = 0, len = hexStr.length; i < len; i += 2) {
|
||||
array.push(parseInt(hexStr.substr(i, 2), 16));
|
||||
}
|
||||
|
||||
return array;
|
||||
},
|
||||
|
||||
arraysEqual: function arraysEqual(a1, a2) {
|
||||
if (!a1 || !a2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a1.length !== a2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0, len = a1.length; i < len; i++) {
|
||||
if (a1[i] !== a2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SEUtils"];
|
466
dom/secureelement/gonk/SecureElement.js
Normal file
466
dom/secureelement/gonk/SecureElement.js
Normal file
@ -0,0 +1,466 @@
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Copyright © 2014, Deutsche Telekom, Inc. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* globals dump, Components, XPCOMUtils, SE, Services, UiccConnector,
|
||||
SEUtils, ppmm, gMap, UUIDGenerator */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SE", () => {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/se_consts.js", obj);
|
||||
return obj;
|
||||
});
|
||||
|
||||
// set to true in se_consts.js to see debug messages
|
||||
let DEBUG = SE.DEBUG_SE;
|
||||
function debug(s) {
|
||||
if (DEBUG) {
|
||||
dump("-*- SecureElement: " + s + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
const SE_IPC_SECUREELEMENT_MSG_NAMES = [
|
||||
"SE:GetSEReaders",
|
||||
"SE:OpenChannel",
|
||||
"SE:CloseChannel",
|
||||
"SE:TransmitAPDU"
|
||||
];
|
||||
|
||||
const SECUREELEMENTMANAGER_CONTRACTID =
|
||||
"@mozilla.org/secureelement/parent-manager;1";
|
||||
const SECUREELEMENTMANAGER_CID =
|
||||
Components.ID("{48f4e650-28d2-11e4-8c21-0800200c9a66}");
|
||||
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
|
||||
"resource://gre/modules/SEUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "UiccConnector", () => {
|
||||
let uiccClass = Cc["@mozilla.org/secureelement/connector/uicc;1"];
|
||||
return uiccClass ? uiccClass.getService(Ci.nsISecureElementConnector) : null;
|
||||
});
|
||||
|
||||
function getConnector(type) {
|
||||
switch (type) {
|
||||
case SE.TYPE_UICC:
|
||||
return UiccConnector;
|
||||
case SE.TYPE_ESE:
|
||||
default:
|
||||
debug("Unsupported SEConnector : " + type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 'gMap' is a nested dictionary object that manages all the information
|
||||
* pertaining to channels for a given application (appId). It manages the
|
||||
* relationship between given application and its opened channels.
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(this, "gMap", function() {
|
||||
return {
|
||||
// example structure of AppInfoMap
|
||||
// {
|
||||
// "appId1": {
|
||||
// target: target1,
|
||||
// readerType: ["uicc", "eSE"],
|
||||
// channels: {
|
||||
// "channelToken1": {
|
||||
// seType: "uicc",
|
||||
// aid: "aid1",
|
||||
// channelNumber: 1
|
||||
// },
|
||||
// "channelToken2": { ... }
|
||||
// }
|
||||
// },
|
||||
// "appId2": { ... }
|
||||
// }
|
||||
appInfoMap: {},
|
||||
|
||||
registerSecureElementTarget: function(appId, readerTypes, target) {
|
||||
if (this.isAppIdRegistered(appId)) {
|
||||
debug("AppId: " + appId + "already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
this.appInfoMap[appId] = {
|
||||
target: target,
|
||||
readerTypes: readerTypes,
|
||||
channels: {}
|
||||
};
|
||||
|
||||
debug("Registered a new SE target " + appId);
|
||||
},
|
||||
|
||||
unregisterSecureElementTarget: function(target) {
|
||||
let appId = Object.keys(this.appInfoMap).find((id) => {
|
||||
return this.appInfoMap[id].target === target;
|
||||
});
|
||||
|
||||
if (!appId) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Unregistered SE Target for AppId: " + appId);
|
||||
delete this.appInfoMap[appId];
|
||||
},
|
||||
|
||||
isAppIdRegistered: function(appId) {
|
||||
return this.appInfoMap[appId] !== undefined;
|
||||
},
|
||||
|
||||
getChannelCountByAppIdType: function(appId, type) {
|
||||
return Object.keys(this.appInfoMap[appId].channels)
|
||||
.reduce((cnt, ch) => ch.type === type ? ++cnt : cnt, 0);
|
||||
},
|
||||
|
||||
// Add channel to the appId. Upon successfully adding the entry
|
||||
// this function will return the 'token'
|
||||
addChannel: function(appId, type, aid, channelNumber) {
|
||||
let token = UUIDGenerator.generateUUID().toString();
|
||||
this.appInfoMap[appId].channels[token] = {
|
||||
seType: type,
|
||||
aid: aid,
|
||||
channelNumber: channelNumber
|
||||
};
|
||||
return token;
|
||||
},
|
||||
|
||||
removeChannel: function(appId, channelToken) {
|
||||
if (this.appInfoMap[appId].channels[channelToken]) {
|
||||
debug("Deleting channel with token : " + channelToken);
|
||||
delete this.appInfoMap[appId].channels[channelToken];
|
||||
}
|
||||
},
|
||||
|
||||
getChannel: function(appId, channelToken) {
|
||||
if (!this.appInfoMap[appId].channels[channelToken]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.appInfoMap[appId].channels[channelToken];
|
||||
},
|
||||
|
||||
getChannelsByTarget: function(target) {
|
||||
let appId = Object.keys(this.appInfoMap).find((id) => {
|
||||
return this.appInfoMap[id].target === target;
|
||||
});
|
||||
|
||||
if (!appId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Object.keys(this.appInfoMap[appId].channels)
|
||||
.map(token => this.appInfoMap[appId].channels[token]);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 'SecureElementManager' is the main object that handles IPC messages from
|
||||
* child process. It interacts with other objects such as 'gMap' & 'Connector
|
||||
* instances (UiccConnector, eSEConnector)' to perform various
|
||||
* SE-related (open,close,transmit) operations.
|
||||
*/
|
||||
function SecureElementManager() {
|
||||
this._registerMessageListeners();
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
}
|
||||
|
||||
SecureElementManager.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIMessageListener,
|
||||
Ci.nsIObserver]),
|
||||
classID: SECUREELEMENTMANAGER_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: SECUREELEMENTMANAGER_CID,
|
||||
classDescription: "SecureElementManager",
|
||||
interfaces: [Ci.nsIMessageListener,
|
||||
Ci.nsIObserver]
|
||||
}),
|
||||
|
||||
_shutdown: function() {
|
||||
this.secureelement = null;
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
this._unregisterMessageListeners();
|
||||
},
|
||||
|
||||
_registerMessageListeners: function() {
|
||||
ppmm.addMessageListener("child-process-shutdown", this);
|
||||
for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) {
|
||||
ppmm.addMessageListener(msgname, this);
|
||||
}
|
||||
},
|
||||
|
||||
_unregisterMessageListeners: function() {
|
||||
ppmm.removeMessageListener("child-process-shutdown", this);
|
||||
for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) {
|
||||
ppmm.removeMessageListener(msgname, this);
|
||||
}
|
||||
ppmm = null;
|
||||
},
|
||||
|
||||
_getAvailableReaderTypes: function() {
|
||||
let readerTypes = [];
|
||||
// TODO 1: Bug 1118096 - Add IDL so that other sub-systems such as RIL ,
|
||||
// NFC can implement it.
|
||||
// TODO 2: Bug 1118097 - According to OpenMobile spec, the reader names
|
||||
// should support slot based naming convention.
|
||||
// i;e; Instead of returning 'uicc', return 'uicc<slot#>'.
|
||||
|
||||
if (UiccConnector) {
|
||||
readerTypes.push(SE.TYPE_UICC);
|
||||
}
|
||||
|
||||
return readerTypes;
|
||||
},
|
||||
|
||||
_canOpenChannel: function(appId, type) {
|
||||
let opened = gMap.getChannelCountByAppIdType(appId, type);
|
||||
let limit = SE.MAX_CHANNELS_ALLOWED_PER_SESSION;
|
||||
// UICC basic channel is not accessible see comment in se_consts.js
|
||||
limit = type === SE.TYPE_UICC ? limit - 1 : limit;
|
||||
return opened < limit;
|
||||
},
|
||||
|
||||
_handleOpenChannel: function(msg, callback) {
|
||||
if (!this._canOpenChannel(msg.appId, msg.type)) {
|
||||
debug("Max channels per session exceed");
|
||||
callback({ error: SE.ERROR_GENERIC });
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Bug 1118098 - Integrate with ACE module
|
||||
let connector = getConnector(msg.type);
|
||||
if (!connector) {
|
||||
debug("No SE connector available");
|
||||
callback({ error: SE.ERROR_NOTPRESENT });
|
||||
return;
|
||||
}
|
||||
|
||||
connector.openChannel(SEUtils.byteArrayToHexString(msg.aid), {
|
||||
notifyOpenChannelSuccess: (channelNumber, openResponse) => {
|
||||
// Add the new 'channel' to the map upon success
|
||||
let channelToken =
|
||||
gMap.addChannel(msg.appId, msg.type, msg.aid, channelNumber);
|
||||
if (channelToken) {
|
||||
callback({
|
||||
error: SE.ERROR_NONE,
|
||||
channelToken: channelToken,
|
||||
isBasicChannel: (channelNumber === SE.BASIC_CHANNEL),
|
||||
openResponse: SEUtils.hexStringToByteArray(openResponse)
|
||||
});
|
||||
} else {
|
||||
callback({ error: SE.ERROR_GENERIC });
|
||||
}
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Failed to open the channel to AID : " +
|
||||
SEUtils.byteArrayToHexString(msg.aid) +
|
||||
", Rejected with Reason : " + reason);
|
||||
callback({ error: SE.ERROR_GENERIC, reason: reason, response: [] });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_handleTransmit: function(msg, callback) {
|
||||
let channel = gMap.getChannel(msg.appId, msg.channelToken);
|
||||
if (!channel) {
|
||||
debug("Invalid token:" + msg.channelToken + ", appId: " + msg.appId);
|
||||
callback({ error: SE.ERROR_GENERIC });
|
||||
return;
|
||||
}
|
||||
|
||||
let connector = getConnector(channel.seType);
|
||||
if (!connector) {
|
||||
debug("No SE connector available");
|
||||
callback({ error: SE.ERROR_NOTPRESENT });
|
||||
return;
|
||||
}
|
||||
|
||||
connector.exchangeAPDU(channel.channelNumber, msg.apdu.cla, msg.apdu.ins,
|
||||
msg.apdu.p1, msg.apdu.p2,
|
||||
SEUtils.byteArrayToHexString(msg.apdu.data),
|
||||
msg.apdu.le, {
|
||||
notifyExchangeAPDUResponse: (sw1, sw2, response) => {
|
||||
callback({
|
||||
error: SE.ERROR_NONE,
|
||||
sw1: sw1,
|
||||
sw2: sw2,
|
||||
response: SEUtils.hexStringToByteArray(response)
|
||||
});
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Transmit failed, rejected with Reason : " + reason);
|
||||
callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_handleCloseChannel: function(msg, callback) {
|
||||
let channel = gMap.getChannel(msg.appId, msg.channelToken);
|
||||
if (!channel) {
|
||||
debug("Invalid token:" + msg.channelToken + ", appId:" + msg.appId);
|
||||
callback({ error: SE.ERROR_GENERIC });
|
||||
return;
|
||||
}
|
||||
|
||||
let connector = getConnector(channel.seType);
|
||||
if (!connector) {
|
||||
debug("No SE connector available");
|
||||
callback({ error: SE.ERROR_NOTPRESENT });
|
||||
return;
|
||||
}
|
||||
|
||||
connector.closeChannel(channel.channelNumber, {
|
||||
notifyCloseChannelSuccess: () => {
|
||||
gMap.removeChannel(msg.appId, msg.channelToken);
|
||||
callback({ error: SE.ERROR_NONE });
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Failed to close channel with token: " + msg.channelToken +
|
||||
", reason: "+ reason);
|
||||
callback({ error: SE.ERROR_BADSTATE, reason: reason });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_handleGetSEReadersRequest: function(msg, target, callback) {
|
||||
// TODO: Bug 1118101 Get supported readerTypes based on the permissions
|
||||
// available for the given application.
|
||||
let seReaderTypes = this._getAvailableReaderTypes();
|
||||
gMap.registerSecureElementTarget(msg.appId, seReaderTypes, target);
|
||||
callback({ readerTypes: seReaderTypes, error: SE.ERROR_NONE });
|
||||
},
|
||||
|
||||
_handleChildProcessShutdown: function(target) {
|
||||
let channels = gMap.getChannelsByTarget(target);
|
||||
|
||||
let createCb = (seType, channelNumber) => {
|
||||
return {
|
||||
notifyCloseChannelSuccess: () => {
|
||||
debug("closed " + seType + ", channel " + channelNumber);
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Failed to close " + seType + " channel " +
|
||||
channelNumber + ", reason: " + reason);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
channels.forEach((channel) => {
|
||||
let connector = getConnector(channel.seType);
|
||||
if (!connector) {
|
||||
return;
|
||||
}
|
||||
|
||||
connector.closeChannel(channel.channelNumber,
|
||||
createCb(channel.seType, channel.channelNumber));
|
||||
});
|
||||
|
||||
gMap.unregisterSecureElementTarget(target);
|
||||
},
|
||||
|
||||
_sendSEResponse: function(msg, result) {
|
||||
let promiseStatus = (result.error === SE.ERROR_NONE) ? "Resolved" : "Rejected";
|
||||
result.resolverId = msg.data.resolverId;
|
||||
msg.target.sendAsyncMessage(msg.name + promiseStatus, {result: result});
|
||||
},
|
||||
|
||||
_isValidMessage: function(msg) {
|
||||
let appIdValid = gMap.isAppIdRegistered(msg.data.appId);
|
||||
return msg.name === "SE:GetSEReaders" ? true : appIdValid;
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIMessageListener interface methods.
|
||||
*/
|
||||
|
||||
receiveMessage: function(msg) {
|
||||
DEBUG && debug("Received '" + msg.name + "' message from content process" +
|
||||
": " + JSON.stringify(msg.data));
|
||||
|
||||
if (msg.name === "child-process-shutdown") {
|
||||
this._handleChildProcessShutdown(msg.target);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (SE_IPC_SECUREELEMENT_MSG_NAMES.indexOf(msg.name) !== -1) {
|
||||
if (!msg.target.assertPermission("secureelement-manage")) {
|
||||
debug("SecureElement message " + msg.name + " from a content process " +
|
||||
"with no 'secureelement-manage' privileges.");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
debug("Ignoring unknown message type: " + msg.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
let callback = (result) => this._sendSEResponse(msg, result);
|
||||
if (!this._isValidMessage(msg)) {
|
||||
debug("Message not valid");
|
||||
callback({ error: SE.ERROR_GENERIC });
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (msg.name) {
|
||||
case "SE:GetSEReaders":
|
||||
this._handleGetSEReadersRequest(msg.data, msg.target, callback);
|
||||
break;
|
||||
case "SE:OpenChannel":
|
||||
this._handleOpenChannel(msg.data, callback);
|
||||
break;
|
||||
case "SE:CloseChannel":
|
||||
this._handleCloseChannel(msg.data, callback);
|
||||
break;
|
||||
case "SE:TransmitAPDU":
|
||||
this._handleTransmit(msg.data, callback);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver interface methods.
|
||||
*/
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) {
|
||||
this._shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElementManager]);
|
18
dom/secureelement/gonk/SecureElement.manifest
Normal file
18
dom/secureelement/gonk/SecureElement.manifest
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# SecureElementManager
|
||||
component {48f4e650-28d2-11e4-8c21-0800200c9a66} SecureElement.js
|
||||
contract @mozilla.org/secureelement/parent-manager;1 {48f4e650-28d2-11e4-8c21-0800200c9a66}
|
||||
category profile-after-change SecureElementManager @mozilla.org/secureelement/parent-manager;1
|
326
dom/secureelement/gonk/UiccConnector.js
Normal file
326
dom/secureelement/gonk/UiccConnector.js
Normal file
@ -0,0 +1,326 @@
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Copyright © 2014, Deutsche Telekom, Inc. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* globals Components, XPCOMUtils, SE, dump, libcutils, Services,
|
||||
iccProvider, SEUtils */
|
||||
|
||||
const { interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SE", function() {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/se_consts.js", obj);
|
||||
return obj;
|
||||
});
|
||||
|
||||
// set to true in se_consts.js to see debug messages
|
||||
let DEBUG = SE.DEBUG_CONNECTOR;
|
||||
function debug(s) {
|
||||
if (DEBUG) {
|
||||
dump("-*- UiccConnector: " + s + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SEUtils",
|
||||
"resource://gre/modules/SEUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
|
||||
"@mozilla.org/ril/content-helper;1",
|
||||
"nsIIccProvider");
|
||||
|
||||
const UICCCONNECTOR_CONTRACTID =
|
||||
"@mozilla.org/secureelement/connector/uicc;1";
|
||||
const UICCCONNECTOR_CID =
|
||||
Components.ID("{8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}");
|
||||
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
|
||||
|
||||
// TODO: Bug 1118099 - Add multi-sim support.
|
||||
// In the Multi-sim, there is more than one client.
|
||||
// For now, use default clientID as 0. Ideally, SE parent process would like to
|
||||
// know which clients (uicc slot) are connected to CLF over SWP interface.
|
||||
const PREFERRED_UICC_CLIENTID =
|
||||
libcutils.property_get("ro.moz.se.def_client_id", "0");
|
||||
|
||||
/**
|
||||
* 'UiccConnector' object is a wrapper over iccProvider's channel management
|
||||
* related interfaces that implements nsISecureElementConnector interface.
|
||||
*/
|
||||
function UiccConnector() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
UiccConnector.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISecureElementConnector]),
|
||||
classID: UICCCONNECTOR_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: UICCCONNECTOR_CID,
|
||||
contractID: UICCCONNECTOR_CONTRACTID,
|
||||
classDescription: "UiccConnector",
|
||||
interfaces: [Ci.nsISecureElementConnector,
|
||||
Ci.nsIIccListener,
|
||||
Ci.nsIObserver]
|
||||
}),
|
||||
|
||||
_isPresent: false,
|
||||
|
||||
_init: function() {
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
iccProvider.registerIccMsg(PREFERRED_UICC_CLIENTID, this);
|
||||
|
||||
// Update the state in order to avoid race condition.
|
||||
// By this time, 'notifyCardStateChanged (with proper card state)'
|
||||
// may have occurred already before this module initialization.
|
||||
this._updatePresenceState();
|
||||
},
|
||||
|
||||
_shutdown: function() {
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
iccProvider.unregisterIccMsg(PREFERRED_UICC_CLIENTID, this);
|
||||
},
|
||||
|
||||
_updatePresenceState: function() {
|
||||
// Consider following Card states as not quite ready for performing
|
||||
// IccChannel* related commands
|
||||
let notReadyStates = [
|
||||
"unknown",
|
||||
"illegal",
|
||||
"personalizationInProgress",
|
||||
"permanentBlocked",
|
||||
];
|
||||
let cardState = iccProvider.getCardState(PREFERRED_UICC_CLIENTID);
|
||||
this._isPresent = cardState !== null &&
|
||||
notReadyStates.indexOf(cardState) == -1;
|
||||
},
|
||||
|
||||
// See GP Spec, 11.1.4 Class Byte Coding
|
||||
_setChannelToCLAByte: function(cla, channel) {
|
||||
if (channel < SE.LOGICAL_CHANNEL_NUMBER_LIMIT) {
|
||||
// b7 = 0 indicates the first interindustry class byte coding
|
||||
cla = (cla & 0x9C) & 0xFF | channel;
|
||||
} else if (channel < SE.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT) {
|
||||
// b7 = 1 indicates the further interindustry class byte coding
|
||||
cla = (cla & 0xB0) & 0xFF | 0x40 | (channel - SE.LOGICAL_CHANNEL_NUMBER_LIMIT);
|
||||
} else {
|
||||
debug("Channel number must be within [0..19]");
|
||||
return SE.ERROR_GENERIC;
|
||||
}
|
||||
return cla;
|
||||
},
|
||||
|
||||
_doGetOpenResponse: function(channel, length, callback) {
|
||||
// Le value is set. It means that this is a request for all available
|
||||
// response bytes.
|
||||
let cla = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, channel);
|
||||
this.exchangeAPDU(channel, cla, SE.INS_GET_RESPONSE, 0x00, 0x00,
|
||||
null, length, {
|
||||
notifyExchangeAPDUResponse: function(sw1, sw2, response) {
|
||||
debug("GET Response : " + response);
|
||||
if (callback) {
|
||||
callback({
|
||||
error: SE.ERROR_NONE,
|
||||
sw1: sw1,
|
||||
sw2: sw2,
|
||||
response: response
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
notifyError: function(reason) {
|
||||
debug("Failed to get open response: " +
|
||||
", Rejected with Reason : " + reason);
|
||||
if (callback) {
|
||||
callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_doIccExchangeAPDU: function(channel, cla, ins, p1, p2, p3,
|
||||
data, appendResp, callback) {
|
||||
iccProvider.iccExchangeAPDU(PREFERRED_UICC_CLIENTID, channel, cla & 0xFC,
|
||||
ins, p1, p2, p3, data, {
|
||||
notifyExchangeAPDUResponse: (sw1, sw2, response) => {
|
||||
debug("sw1 : " + sw1 + ", sw2 : " + sw2 + ", response : " + response);
|
||||
|
||||
// According to ETSI TS 102 221 , Section 7.2.2.3.1,
|
||||
// Enforce 'Procedure bytes' checks before notifying the callback.
|
||||
// Note that 'Procedure bytes'are special cases.
|
||||
// There is no need to handle '0x60' procedure byte as it implies
|
||||
// no-action from SE stack perspective. This procedure byte is not
|
||||
// notified to application layer.
|
||||
if (sw1 === 0x6C) {
|
||||
// Use the previous command header with length as second procedure
|
||||
// byte (SW2) as received and repeat the procedure.
|
||||
|
||||
// Recursive! and Pass empty response '' as args, since '0x6C'
|
||||
// procedure does not have to deal with appended responses.
|
||||
this._doIccExchangeAPDU(channel, cla, ins, p1, p2,
|
||||
sw2, data, "", callback);
|
||||
} else if (sw1 === 0x61) {
|
||||
// Since the terminal waited for a second procedure byte and
|
||||
// received it (sw2), send a GET RESPONSE command header to the UICC
|
||||
// with a maximum length of 'XX', where 'XX' is the value of the
|
||||
// second procedure byte (SW2).
|
||||
|
||||
let claWithChannel = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE,
|
||||
channel);
|
||||
|
||||
// Recursive, with GET RESPONSE bytes and '0x61' procedure IS interested
|
||||
// in appended responses. Pass appended response and note that p3=sw2.
|
||||
this._doIccExchangeAPDU(channel, claWithChannel, SE.INS_GET_RESPONSE,
|
||||
0x00, 0x00, sw2, null,
|
||||
(response ? response + appendResp : appendResp),
|
||||
callback);
|
||||
} else if (callback) {
|
||||
callback.notifyExchangeAPDUResponse(sw1, sw2, response);
|
||||
}
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Failed to trasmit C-APDU over the channel # : " + channel +
|
||||
", Rejected with Reason : " + reason);
|
||||
if (callback) {
|
||||
callback.notifyError(reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* nsISecureElementConnector interface methods.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opens a channel on a default clientId
|
||||
*/
|
||||
openChannel: function(aid, callback) {
|
||||
if (!this._isPresent) {
|
||||
callback.notifyError(SE.ERROR_NOTPRESENT);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Bug 1118106: Handle Resource management / leaks by persisting
|
||||
// the newly opened channel in some persistent storage so that when this
|
||||
// module gets restarted (say after opening a channel) in the event of
|
||||
// some erroneous conditions such as gecko restart /, crash it can read
|
||||
// the persistent storage to check if there are any held resources
|
||||
// (opened channels) and close them.
|
||||
iccProvider.iccOpenChannel(PREFERRED_UICC_CLIENTID, aid, {
|
||||
notifyOpenChannelSuccess: (channel) => {
|
||||
this._doGetOpenResponse(channel, 0x00, function(result) {
|
||||
if (callback) {
|
||||
callback.notifyOpenChannelSuccess(channel, result.response);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
notifyError: (reason) => {
|
||||
debug("Failed to open the channel to AID : " + aid +
|
||||
", Rejected with Reason : " + reason);
|
||||
if (callback) {
|
||||
callback.notifyError(reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Transmit the C-APDU (command) on default clientId.
|
||||
*/
|
||||
exchangeAPDU: function(channel, cla, ins, p1, p2, data, le, callback) {
|
||||
if (!this._isPresent) {
|
||||
callback.notifyError(SE.ERROR_NOTPRESENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data && data.length % 2 !== 0) {
|
||||
callback.notifyError("Data should be a hex string with length % 2 === 0");
|
||||
return;
|
||||
}
|
||||
|
||||
cla = this._setChannelToCLAByte(cla, channel);
|
||||
let lc = data ? data.length / 2 : 0;
|
||||
let p3 = lc || le;
|
||||
|
||||
if (lc && (le !== -1)) {
|
||||
data += SEUtils.byteArrayToHexString([le]);
|
||||
}
|
||||
|
||||
// Pass empty response '' as args as we are not interested in appended
|
||||
// responses yet!
|
||||
debug("exchangeAPDU on Channel # " + channel);
|
||||
this._doIccExchangeAPDU(channel, cla, ins, p1, p2, p3, data, "",
|
||||
callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the channel on default clientId.
|
||||
*/
|
||||
closeChannel: function(channel, callback) {
|
||||
if (!this._isPresent) {
|
||||
callback.notifyError(SE.ERROR_NOTPRESENT);
|
||||
return;
|
||||
}
|
||||
|
||||
iccProvider.iccCloseChannel(PREFERRED_UICC_CLIENTID, channel, {
|
||||
notifyCloseChannelSuccess: function() {
|
||||
debug("closeChannel successfully closed the channel # : " + channel);
|
||||
if (callback) {
|
||||
callback.notifyCloseChannelSuccess();
|
||||
}
|
||||
},
|
||||
|
||||
notifyError: function(reason) {
|
||||
debug("Failed to close the channel # : " + channel +
|
||||
", Rejected with Reason : " + reason);
|
||||
if (callback) {
|
||||
callback.notifyError(reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIIccListener interface methods.
|
||||
*/
|
||||
notifyStkCommand: function() {},
|
||||
|
||||
notifyStkSessionEnd: function() {},
|
||||
|
||||
notifyIccInfoChanged: function() {},
|
||||
|
||||
notifyCardStateChanged: function() {
|
||||
this._updatePresenceState();
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver interface methods.
|
||||
*/
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) {
|
||||
this._shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UiccConnector]);
|
17
dom/secureelement/gonk/UiccConnector.manifest
Normal file
17
dom/secureelement/gonk/UiccConnector.manifest
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# UiccConnector
|
||||
component {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} UiccConnector.js
|
||||
contract @mozilla.org/secureelement/connector/uicc;1 {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}
|
104
dom/secureelement/gonk/nsISecureElementConnector.idl
Normal file
104
dom/secureelement/gonk/nsISecureElementConnector.idl
Normal file
@ -0,0 +1,104 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(1ff3f35a-1b6f-4e65-a89e-a363b8604cd7)]
|
||||
interface nsISEChannelCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function to notify on successfully opening a logical channel.
|
||||
*
|
||||
* @param channel
|
||||
* The Channel Number/Handle that is successfully opened.
|
||||
* @param openResponse
|
||||
* Response from SE for OpenChannel operation.
|
||||
*/
|
||||
void notifyOpenChannelSuccess(in long channel, in DOMString openResponse);
|
||||
|
||||
/**
|
||||
* Callback function to notify on successfully closing the logical channel.
|
||||
*
|
||||
*/
|
||||
void notifyCloseChannelSuccess();
|
||||
|
||||
/**
|
||||
* Callback function to notify the status of 'seExchangeAPDU' command.
|
||||
*
|
||||
* @param sw1
|
||||
* Response's First Status Byte
|
||||
* @param sw2
|
||||
* Response's Second Status Byte
|
||||
* @param data
|
||||
* Response's data
|
||||
*/
|
||||
void notifyExchangeAPDUResponse(in octet sw1,
|
||||
in octet sw2,
|
||||
in DOMString data);
|
||||
|
||||
/**
|
||||
* Callback function to notify error
|
||||
*
|
||||
* @param error
|
||||
* Error describing the reason for failure.
|
||||
*/
|
||||
void notifyError(in DOMString error);
|
||||
};
|
||||
|
||||
[scriptable, uuid(88e23684-0de3-4792-83a0-0eb67a6ca448)]
|
||||
interface nsISecureElementConnector : nsISupports
|
||||
{
|
||||
/**
|
||||
* Open a logical communication channel with the specific secure element type
|
||||
*
|
||||
* @param aid
|
||||
* Application Identifier of the Card Applet on the secure element.
|
||||
* @param callback
|
||||
* callback to notify the result of the operation.
|
||||
*/
|
||||
void openChannel(in DOMString aid,
|
||||
in nsISEChannelCallback callback);
|
||||
|
||||
/**
|
||||
* Exchanges APDU channel with the specific secure element type
|
||||
*
|
||||
* @param channel
|
||||
* Channel on which C-APDU to be transmitted.
|
||||
* @param cla
|
||||
Class Byte.
|
||||
* @param ins
|
||||
Instruction Byte
|
||||
* @param p1
|
||||
Reference parameter first byte
|
||||
* @param p2
|
||||
Reference parameter second byte
|
||||
* Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases.
|
||||
* @param data
|
||||
Sequence of C-APDU data octets
|
||||
* @param le [optional]
|
||||
* le is the length of expected response. If the response is not expected,
|
||||
it should be explicitly set to -1.
|
||||
* @param callback
|
||||
* callback to notify the result of the operation.
|
||||
*/
|
||||
void exchangeAPDU(in long channel,
|
||||
in octet cla,
|
||||
in octet ins,
|
||||
in octet p1,
|
||||
in octet p2,
|
||||
in DOMString data,
|
||||
in short le,
|
||||
in nsISEChannelCallback callback);
|
||||
|
||||
/**
|
||||
* Closes the logical communication channel to the specific secure element type
|
||||
*
|
||||
* @param channel
|
||||
* Channel to be closed.
|
||||
* @param callback
|
||||
* callback to notify the result of the operation.
|
||||
*/
|
||||
void closeChannel(in long channel,
|
||||
in nsISEChannelCallback callback);
|
||||
};
|
66
dom/secureelement/gonk/se_consts.js
Normal file
66
dom/secureelement/gonk/se_consts.js
Normal file
@ -0,0 +1,66 @@
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Copyright © 2014, Deutsche Telekom, Inc. */
|
||||
|
||||
// Set to true to debug SecureElement (SE) stack
|
||||
this.DEBUG_ALL = false;
|
||||
|
||||
// Set individually to debug specific layers
|
||||
this.DEBUG_CONNECTOR = DEBUG_ALL || false;
|
||||
this.DEBUG_SE = DEBUG_ALL || false ;
|
||||
|
||||
// Maximun logical channels per session.
|
||||
// For 'uicc' SE type this value is 3, as opening a basic channel' : 0
|
||||
// is not allowed for security reasons. In such scenarios, possible
|
||||
// supplementary logical channels available are : [1, 2, or 3].
|
||||
// However,Other SE types may support upto max 4 (including '0').
|
||||
this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4;
|
||||
|
||||
this.BASIC_CHANNEL = 0;
|
||||
|
||||
// According GPCardSpec 2.2
|
||||
this.MAX_APDU_LEN = 255; // including APDU header
|
||||
|
||||
// CLA (1 byte) + INS (1 byte) + P1 (1 byte) + P2 (1 byte)
|
||||
this.APDU_HEADER_LEN = 4;
|
||||
|
||||
this.LOGICAL_CHANNEL_NUMBER_LIMIT = 4;
|
||||
this.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT = 20;
|
||||
|
||||
this.MIN_AID_LEN = 5;
|
||||
this.MAX_AID_LEN = 16;
|
||||
|
||||
this.CLA_GET_RESPONSE = 0x00;
|
||||
|
||||
this.INS_SELECT = 0xA4;
|
||||
this.INS_MANAGE_CHANNEL = 0x70;
|
||||
this.INS_GET_RESPONSE = 0xC0;
|
||||
|
||||
// Match the following errors with SecureElement.webidl's SEError enum values
|
||||
this.ERROR_NONE = "";
|
||||
this.ERROR_SECURITY = "SESecurityError";
|
||||
this.ERROR_IO = "SEIoError";
|
||||
this.ERROR_BADSTATE = "SEBadStateError";
|
||||
this.ERROR_INVALIDCHANNEL = "SEInvalidChannelError";
|
||||
this.ERROR_INVALIDAPPLICATION = "SEInvalidApplicationError";
|
||||
this.ERROR_GENERIC = "SEGenericError";
|
||||
this.ERROR_NOTPRESENT = "SENotPresentError";
|
||||
|
||||
this.TYPE_UICC = "uicc";
|
||||
this.TYPE_ESE = "eSE";
|
||||
|
||||
// Allow this file to be imported via Components.utils.import().
|
||||
this.EXPORTED_SYMBOLS = Object.keys(this);
|
39
dom/secureelement/moz.build
Normal file
39
dom/secureelement/moz.build
Normal file
@ -0,0 +1,39 @@
|
||||
# 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/.
|
||||
#
|
||||
# Copyright © 2014 Deutsche Telekom, Inc.
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'DOMSecureElement.js',
|
||||
'DOMSecureElement.manifest',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_SECUREELEMENT']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'gonk/SecureElement.js',
|
||||
'gonk/SecureElement.manifest',
|
||||
]
|
||||
XPIDL_MODULE = 'dom_secureelement'
|
||||
XPIDL_SOURCES += [
|
||||
'gonk/nsISecureElementConnector.idl',
|
||||
]
|
||||
EXTRA_JS_MODULES += [
|
||||
'gonk/se_consts.js',
|
||||
'SEUtils.jsm'
|
||||
]
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
'tests/unit/xpcshell.ini'
|
||||
]
|
||||
if CONFIG['MOZ_B2G_RIL']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'gonk/UiccConnector.js',
|
||||
'gonk/UiccConnector.manifest',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
68
dom/secureelement/tests/unit/test_SEUtils.js
Normal file
68
dom/secureelement/tests/unit/test_SEUtils.js
Normal file
@ -0,0 +1,68 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* globals run_next_test, add_test, ok, Components, SEUtils */
|
||||
/* exported run_test */
|
||||
|
||||
Components.utils.import("resource://gre/modules/SEUtils.jsm");
|
||||
|
||||
const VALID_HEX_STR = "0123456789ABCDEF";
|
||||
const VALID_BYTE_ARR = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
|
||||
|
||||
function run_test() {
|
||||
ok(!!SEUtils, "SEUtils should be available");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_byteArrayToHexString() {
|
||||
let hexStr = SEUtils.byteArrayToHexString(VALID_BYTE_ARR);
|
||||
ok(hexStr === VALID_HEX_STR,
|
||||
"should convert byte Array to uppercased hex string");
|
||||
|
||||
[[], null, undefined].forEach((input) => {
|
||||
hexStr = SEUtils.byteArrayToHexString(input);
|
||||
ok(hexStr === "", "invalid arg:" + input + " should return empty string");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_hexStringToByteArray() {
|
||||
let byteArr = SEUtils.hexStringToByteArray(VALID_HEX_STR);
|
||||
ok(SEUtils.arraysEqual(byteArr, VALID_BYTE_ARR),
|
||||
"should convert uppercased string to byte Array");
|
||||
|
||||
byteArr = SEUtils.hexStringToByteArray(VALID_HEX_STR.toLowerCase());
|
||||
ok(SEUtils.arraysEqual(byteArr, VALID_BYTE_ARR),
|
||||
"should convert lowercased string to byte Array");
|
||||
|
||||
["", null, undefined, "123"].forEach((input) => {
|
||||
byteArr = SEUtils.hexStringToByteArray(input);
|
||||
ok(Array.isArray(byteArr) && byteArr.length === 0,
|
||||
"invalid arg: " + input + " should be empty Array");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_arraysEqual() {
|
||||
ok(SEUtils.arraysEqual([1, 2, 3], [1, 2, 3]),
|
||||
"should return true on equal Arrays");
|
||||
|
||||
[[1], [1, 2, 4], [3, 2, 1]].forEach((input) => {
|
||||
ok(!SEUtils.arraysEqual([1, 2, 3], input),
|
||||
"should return false when Arrays not equal");
|
||||
});
|
||||
|
||||
[null, undefined].forEach((input) => {
|
||||
ok(!SEUtils.arraysEqual([1, 2, 3], input),
|
||||
"should return false when comparing Array with invalid argument");
|
||||
|
||||
ok(!SEUtils.arraysEqual(input, input),
|
||||
"should return false when both args are invalid");
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
5
dom/secureelement/tests/unit/xpcshell.ini
Normal file
5
dom/secureelement/tests/unit/xpcshell.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_SEUtils.js]
|
@ -135,6 +135,7 @@ function RILContentHelper() {
|
||||
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
|
||||
this._windowsMap = [];
|
||||
this._iccListeners = [];
|
||||
this._iccChannelCallback = [];
|
||||
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
|
||||
@ -593,6 +594,8 @@ RILContentHelper.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_iccChannelCallback: null,
|
||||
|
||||
_addIccChannelCallback: function(requestId, channelCb) {
|
||||
let cbInterfaces = this._iccChannelCallback;
|
||||
if (!cbInterfaces[requestId] && channelCb) {
|
||||
|
@ -531,10 +531,20 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
|
||||
// for more details). Therefore we should hangup all active voice calls
|
||||
// first. And considering some DSDS architecture, toggling one radio may
|
||||
// toggle both, so we send hangUpAll to all clients.
|
||||
for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) {
|
||||
let iface = _ril.getRadioInterface(i);
|
||||
iface.workerMessenger.send("hangUpAll");
|
||||
}
|
||||
let hangUpCallback = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyCallback]),
|
||||
notifySuccess: function() {},
|
||||
notifyError: function() {}
|
||||
};
|
||||
|
||||
gTelephonyService.enumerateCalls({
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]),
|
||||
enumerateCallState: function(aInfo) {
|
||||
gTelephonyService.hangUpCall(aInfo.clientId, aInfo.callIndex,
|
||||
hangUpCallback);
|
||||
},
|
||||
enumerateCallStateComplete: function() {}
|
||||
});
|
||||
|
||||
// In some DSDS architecture with only one modem, toggling one radio may
|
||||
// toggle both. Therefore, for safely turning off, we should first
|
||||
|
@ -1556,15 +1556,6 @@ RilObject.prototype = {
|
||||
Buf.sendParcel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hang up all calls
|
||||
*/
|
||||
hangUpAll: function() {
|
||||
for (let callIndex in this.currentCalls) {
|
||||
this.hangUpCall({callIndex: callIndex});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hang up the phone.
|
||||
*
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/dom/telephony/TelephonyCallback.h"
|
||||
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include "Telephony.h"
|
||||
#include "TelephonyCallGroup.h"
|
||||
@ -69,30 +70,28 @@ TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents)
|
||||
|
||||
nsString stateString;
|
||||
switch (aCallState) {
|
||||
// These states are used internally to mark this call is currently being
|
||||
// controlled, and we should block consecutive requests of the same type
|
||||
// according to these states.
|
||||
case nsITelephonyService::CALL_STATE_CONNECTING:
|
||||
case nsITelephonyService::CALL_STATE_DISCONNECTING:
|
||||
case nsITelephonyService::CALL_STATE_HOLDING:
|
||||
case nsITelephonyService::CALL_STATE_RESUMING:
|
||||
break;
|
||||
// These states will be translated into literal strings which are used to
|
||||
// show the current status of this call.
|
||||
case nsITelephonyService::CALL_STATE_DIALING:
|
||||
stateString.AssignLiteral("dialing");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_ALERTING:
|
||||
stateString.AssignLiteral("alerting");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_CONNECTING:
|
||||
stateString.AssignLiteral("connecting");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_CONNECTED:
|
||||
stateString.AssignLiteral("connected");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_HOLDING:
|
||||
stateString.AssignLiteral("holding");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_HELD:
|
||||
stateString.AssignLiteral("held");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_RESUMING:
|
||||
stateString.AssignLiteral("resuming");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_DISCONNECTING:
|
||||
stateString.AssignLiteral("disconnecting");
|
||||
break;
|
||||
case nsITelephonyService::CALL_STATE_DISCONNECTED:
|
||||
stateString.AssignLiteral("disconnected");
|
||||
break;
|
||||
@ -103,8 +102,10 @@ TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents)
|
||||
NS_NOTREACHED("Unknown state!");
|
||||
}
|
||||
|
||||
mState = stateString;
|
||||
mCallState = aCallState;
|
||||
if (!stateString.IsEmpty()) {
|
||||
mState = stateString;
|
||||
}
|
||||
|
||||
if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
|
||||
NS_ASSERTION(mLive, "Should be live!");
|
||||
@ -156,6 +157,23 @@ TelephonyCall::DispatchCallEvent(const nsAString& aType,
|
||||
return DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
TelephonyCall::CreatePromise(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TelephonyCall::NotifyError(const nsAString& aError)
|
||||
{
|
||||
@ -231,17 +249,14 @@ TelephonyCall::GetGroup() const
|
||||
already_AddRefed<Promise>
|
||||
TelephonyCall::Answer(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
nsRefPtr<Promise> promise = CreatePromise(aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
if (mCallState != nsITelephonyService::CALL_STATE_INCOMING) {
|
||||
NS_WARNING("Answer on non-incoming call is rejected!");
|
||||
NS_WARNING(nsPrintfCString("Answer on non-incoming call is rejected!"
|
||||
" (State: %u)", mCallState).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
@ -250,25 +265,22 @@ TelephonyCall::Answer(ErrorResult& aRv)
|
||||
aRv = mTelephony->Service()->AnswerCall(mServiceId, mCallIndex, callback);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_CONNECTING, true);
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_CONNECTING, false);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
TelephonyCall::HangUp(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
nsRefPtr<Promise> promise = CreatePromise(aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
if (mCallState == nsITelephonyService::CALL_STATE_DISCONNECTING ||
|
||||
mCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
|
||||
NS_WARNING("HangUp on previously disconnected call is rejected!");
|
||||
NS_WARNING(nsPrintfCString("HangUp on previously disconnected call"
|
||||
" is rejected! (State: %u)", mCallState).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
@ -279,24 +291,21 @@ TelephonyCall::HangUp(ErrorResult& aRv)
|
||||
mTelephony->Service()->HangUpCall(mServiceId, mCallIndex, callback);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_DISCONNECTING, true);
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_DISCONNECTING, false);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
TelephonyCall::Hold(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
nsRefPtr<Promise> promise = CreatePromise(aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
|
||||
NS_WARNING("Hold non-connected call is rejected!");
|
||||
NS_WARNING(nsPrintfCString("Hold non-connected call is rejected!"
|
||||
" (State: %u)", mCallState).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
@ -324,24 +333,21 @@ TelephonyCall::Hold(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_HOLDING, true);
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_HOLDING, false);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
TelephonyCall::Resume(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
nsRefPtr<Promise> promise = CreatePromise(aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
|
||||
NS_WARNING("Resume non-held call is rejected!");
|
||||
NS_WARNING(nsPrintfCString("Resume non-held call is rejected!"
|
||||
" (State: %u)", mCallState).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
@ -362,6 +368,6 @@ TelephonyCall::Resume(ErrorResult& aRv)
|
||||
aRv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, callback);
|
||||
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
||||
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_RESUMING, true);
|
||||
ChangeStateInternal(nsITelephonyService::CALL_STATE_RESUMING, false);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -105,13 +105,9 @@ public:
|
||||
IMPL_EVENT_HANDLER(statechange)
|
||||
IMPL_EVENT_HANDLER(dialing)
|
||||
IMPL_EVENT_HANDLER(alerting)
|
||||
IMPL_EVENT_HANDLER(connecting)
|
||||
IMPL_EVENT_HANDLER(connected)
|
||||
IMPL_EVENT_HANDLER(disconnecting)
|
||||
IMPL_EVENT_HANDLER(disconnected)
|
||||
IMPL_EVENT_HANDLER(holding)
|
||||
IMPL_EVENT_HANDLER(held)
|
||||
IMPL_EVENT_HANDLER(resuming)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
IMPL_EVENT_HANDLER(groupchange)
|
||||
|
||||
@ -183,6 +179,9 @@ private:
|
||||
nsresult
|
||||
DispatchCallEvent(const nsAString& aType,
|
||||
TelephonyCall* aCall);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreatePromise(ErrorResult& aRv);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -501,11 +501,6 @@ let emulator = (function() {
|
||||
|
||||
let promises = [];
|
||||
|
||||
let promise = waitForNamedStateEvent(call, "connecting")
|
||||
.then(() => waitForNamedStateEvent(call, "connected"));
|
||||
|
||||
promises.push(promise);
|
||||
|
||||
// incoming call triggers conference state change. We should wait for
|
||||
// |conference.onstatechange| before checking the state of the conference
|
||||
// call.
|
||||
@ -520,8 +515,8 @@ let emulator = (function() {
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
promise = call.answer();
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "connected"));
|
||||
promises.push(call.answer());
|
||||
|
||||
return Promise.all(promises).then(() => call);
|
||||
}
|
||||
@ -538,12 +533,8 @@ let emulator = (function() {
|
||||
|
||||
let promises = [];
|
||||
|
||||
let promise = waitForNamedStateEvent(call, "holding")
|
||||
.then(() => waitForNamedStateEvent(call, "held"));
|
||||
promises.push(promise);
|
||||
|
||||
promise = call.hold();
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "held"));
|
||||
promises.push(call.hold());
|
||||
|
||||
return Promise.all(promises).then(() => call);
|
||||
}
|
||||
@ -560,12 +551,8 @@ let emulator = (function() {
|
||||
|
||||
let promises = [];
|
||||
|
||||
let promise = waitForNamedStateEvent(call, "resuming")
|
||||
.then(() => waitForNamedStateEvent(call, "connected"));
|
||||
promises.push(promise);
|
||||
|
||||
promise = call.resume();
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "connected"));
|
||||
promises.push(call.resume());
|
||||
|
||||
return Promise.all(promises).then(() => call);
|
||||
}
|
||||
@ -582,12 +569,8 @@ let emulator = (function() {
|
||||
|
||||
let promises = [];
|
||||
|
||||
let promise = waitForNamedStateEvent(call, "disconnecting")
|
||||
.then(() => waitForNamedStateEvent(call, "disconnected"));
|
||||
promises.push(promise);
|
||||
|
||||
promise = call.hangUp();
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "disconnected"));
|
||||
promises.push(call.hangUp());
|
||||
|
||||
return Promise.all(promises).then(() => call);
|
||||
}
|
||||
@ -728,9 +711,7 @@ let emulator = (function() {
|
||||
let promises = [];
|
||||
|
||||
for (let call of callsInConference) {
|
||||
let promise = waitForNamedStateEvent(call, "holding")
|
||||
.then(() => waitForNamedStateEvent(call, "held"));
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "held"));
|
||||
}
|
||||
|
||||
let promise = waitForNamedStateEvent(conference, "holding")
|
||||
@ -763,9 +744,7 @@ let emulator = (function() {
|
||||
let promises = [];
|
||||
|
||||
for (let call of callsInConference) {
|
||||
let promise = waitForNamedStateEvent(call, "resuming")
|
||||
.then(() => waitForNamedStateEvent(call, "connected"));
|
||||
promises.push(promise);
|
||||
promises.push(waitForNamedStateEvent(call, "connected"));
|
||||
}
|
||||
|
||||
let promise = waitForNamedStateEvent(conference, "resuming")
|
||||
|
@ -29,7 +29,6 @@ qemu = true
|
||||
[test_incoming_already_held.js]
|
||||
[test_incoming_answer_hangup_oncallschanged.js]
|
||||
[test_incoming_basic_operations.js]
|
||||
[test_incoming_connecting_hangup.js]
|
||||
[test_incoming_onstatechange.js]
|
||||
[test_mmi.js]
|
||||
[test_mmi_call_forwarding.js]
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const inNumber = "5555552222";
|
||||
const inInfo = gInCallStrPool(inNumber);
|
||||
let inCall;
|
||||
|
||||
function incoming() {
|
||||
return gRemoteDial(inNumber)
|
||||
.then(call => inCall = call)
|
||||
.then(() => gCheckAll(null, [inCall], "", [], [inInfo.incoming]));
|
||||
}
|
||||
|
||||
function connecting() {
|
||||
let promises = [
|
||||
gWaitForNamedStateEvent(inCall, "connecting"),
|
||||
inCall.answer()
|
||||
];
|
||||
return Promise.all(promises).then(() => inCall);
|
||||
}
|
||||
|
||||
function hangUp() {
|
||||
return gHangUp(inCall)
|
||||
.then(() => gCheckAll(null, [], "", [], []));
|
||||
}
|
||||
|
||||
function remoteHangUp() {
|
||||
return gRemoteHangUp(inCall)
|
||||
.then(() => gCheckAll(null, [], "", [], []));
|
||||
}
|
||||
|
||||
// Test cases.
|
||||
|
||||
function testConnectingHangUp() {
|
||||
log("= testConnectingHangUp =");
|
||||
return incoming()
|
||||
.then(() => connecting())
|
||||
.then(() => hangUp());
|
||||
}
|
||||
|
||||
function testConnectingRemoteHangUp() {
|
||||
log("= testConnectingRemoteHangUp =");
|
||||
return incoming()
|
||||
.then(() => connecting())
|
||||
.then(() => remoteHangUp());
|
||||
}
|
||||
|
||||
startTest(function() {
|
||||
Promise.resolve()
|
||||
.then(() => testConnectingHangUp())
|
||||
.then(() => testConnectingRemoteHangUp())
|
||||
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
@ -14,39 +14,19 @@ startTest(function() {
|
||||
.then(() => gCheckAll(null, [inCall], "", [], [inInfo.incoming]))
|
||||
|
||||
// Answer incoming call
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(inCall, "connecting")
|
||||
.then(() => gWaitForStateChangeEvent(inCall, "connected"));
|
||||
let p2 = gAnswer(inCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gAnswer(inCall))
|
||||
.then(() => gCheckAll(inCall, [inCall], "", [], [inInfo.active]))
|
||||
|
||||
// Hold the call.
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(inCall, "holding")
|
||||
.then(() => gWaitForStateChangeEvent(inCall, "held"));
|
||||
let p2 = gHold(inCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gHold(inCall))
|
||||
.then(() => gCheckAll(null, [inCall], "", [], [inInfo.held]))
|
||||
|
||||
// Resume the call.
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(inCall, "resuming")
|
||||
.then(() => gWaitForStateChangeEvent(inCall, "connected"));
|
||||
let p2 = gResume(inCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gResume(inCall))
|
||||
.then(() => gCheckAll(inCall, [inCall], "", [], [inInfo.active]))
|
||||
|
||||
// Hang-up call
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(inCall, "disconnecting")
|
||||
.then(() => gWaitForStateChangeEvent(inCall, "disconnected"));
|
||||
let p2 = gHangUp(inCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gHangUp(inCall))
|
||||
.then(() => gCheckAll(null, [], "", [], []))
|
||||
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
|
@ -22,30 +22,15 @@ startTest(function() {
|
||||
.then(() => gCheckAll(outCall, [outCall], "", [], [outInfo.active]))
|
||||
|
||||
// Hold the call.
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(outCall, "holding")
|
||||
.then(() => gWaitForStateChangeEvent(outCall, "held"));
|
||||
let p2 = gHold(outCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gHold(outCall))
|
||||
.then(() => gCheckAll(null, [outCall], "", [], [outInfo.held]))
|
||||
|
||||
// Resume the call.
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(outCall, "resuming")
|
||||
.then(() => gWaitForStateChangeEvent(outCall, "connected"));
|
||||
let p2 = gResume(outCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gResume(outCall))
|
||||
.then(() => gCheckAll(outCall, [outCall], "", [], [outInfo.active]))
|
||||
|
||||
// Hang-up call
|
||||
.then(() => {
|
||||
let p1 = gWaitForStateChangeEvent(outCall, "disconnecting")
|
||||
.then(() => gWaitForStateChangeEvent(outCall, "disconnected"));
|
||||
let p2 = gHangUp(outCall);
|
||||
return Promise.all([p1, p2]);
|
||||
})
|
||||
.then(() => gHangUp(outCall))
|
||||
.then(() => gCheckAll(null, [], "", [], []))
|
||||
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
|
@ -8,23 +8,17 @@ const inNumber = "5555552222";
|
||||
const inInfo = gInCallStrPool(inNumber);
|
||||
let inCall;
|
||||
|
||||
function error(event, action) {
|
||||
ok(false, "Received '" + event + "' event when " + action);
|
||||
function error(aEvent, aAction) {
|
||||
ok(false, "Received '" + aEvent + "' event when " + aAction);
|
||||
}
|
||||
|
||||
function checkUnexpected(msg, call, event1, event2, actionCallback) {
|
||||
let error1 = error.bind(this, event1, msg);
|
||||
let error2 = error.bind(this, event2, msg);
|
||||
function checkUnexpected(aMsg, aCall, aEvent, aActionCallback) {
|
||||
let handler = error.bind(this, aEvent, aMsg);
|
||||
aCall.addEventListener(aEvent, handler);
|
||||
|
||||
call.addEventListener(event1, error1);
|
||||
call.addEventListener(event2, error2);
|
||||
|
||||
return actionCallback().then(
|
||||
return aActionCallback().then(
|
||||
() => ok(false, msg + "should be rejected."),
|
||||
() => gDelay(2000).then(() => {
|
||||
call.removeEventListener(event1, error1);
|
||||
call.removeEventListener(event2, error2);
|
||||
}));
|
||||
() => gDelay(2000).then(() => aCall.removeEventListener(aEvent, handler)));
|
||||
}
|
||||
|
||||
startTest(function() {
|
||||
@ -32,36 +26,24 @@ startTest(function() {
|
||||
.then(call => inCall = call)
|
||||
.then(() => gAnswer(inCall))
|
||||
.then(() => checkUnexpected("answered an active call", inCall,
|
||||
"connecting", "connected",
|
||||
() => inCall.answer()))
|
||||
|
||||
"connected", () => inCall.answer()))
|
||||
.then(() => gHold(inCall))
|
||||
.then(() => checkUnexpected("held a held call", inCall,
|
||||
"holding", "held",
|
||||
() => inCall.hold()))
|
||||
"held", () => inCall.hold()))
|
||||
.then(() => checkUnexpected("answered a held call", inCall,
|
||||
"connecting", "connected",
|
||||
() => inCall.answer()))
|
||||
|
||||
"connected", () => inCall.answer()))
|
||||
.then(() => gResume(inCall))
|
||||
.then(() => checkUnexpected("resumed non-held call", inCall,
|
||||
"resuming", "connected",
|
||||
() => inCall.resume()))
|
||||
|
||||
"connected", () => inCall.resume()))
|
||||
.then(() => gHangUp(inCall))
|
||||
.then(() => checkUnexpected("answered a disconnected call", inCall,
|
||||
"connecting", "connected",
|
||||
() => inCall.answer()))
|
||||
"connected", () => inCall.answer()))
|
||||
.then(() => checkUnexpected("held a disconnected call", inCall,
|
||||
"holding", "held",
|
||||
() => inCall.hold()))
|
||||
"held", () => inCall.hold()))
|
||||
.then(() => checkUnexpected("resumed a disconnected call", inCall,
|
||||
"resuming", "connected",
|
||||
() => inCall.resume()))
|
||||
"connected", () => inCall.resume()))
|
||||
.then(() => checkUnexpected("hang-up a disconnected call", inCall,
|
||||
"disconnecting", "disconnected",
|
||||
() => inCall.hangUp()))
|
||||
|
||||
"disconnected", () => inCall.hangUp()))
|
||||
.catch(error => ok(false, "Promise reject: " + error))
|
||||
.then(finish);
|
||||
});
|
||||
|
160
dom/webidl/SecureElement.webidl
Normal file
160
dom/webidl/SecureElement.webidl
Normal file
@ -0,0 +1,160 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2014 Deutsche Telekom, Inc. */
|
||||
|
||||
enum SEType {
|
||||
"uicc",
|
||||
"eSE"
|
||||
};
|
||||
|
||||
enum SEError {
|
||||
"SESecurityError", // Requested operation does not match the access control rules of the application.
|
||||
"SEIoError", // I/O Error while communicating with the secure element.
|
||||
"SEBadStateError", // Error occuring as a result of bad state.
|
||||
"SEInvalidChannelError", // Opening a channel failed because no channel is available.
|
||||
"SEInvalidApplicationError", // The requested application was not found on the secure element.
|
||||
"SEGenericError" // Generic failures.
|
||||
};
|
||||
|
||||
enum SEChannelType {
|
||||
"basic",
|
||||
"logical"
|
||||
};
|
||||
|
||||
// Dictionary that represents an APDU command to be sent to a secure element.
|
||||
dictionary SECommand {
|
||||
required octet cla; // Class Byte
|
||||
required octet ins; // Instruction Byte
|
||||
required octet p1; // First Octet of Parameters Byte
|
||||
required octet p2; // Second Octet of Parameters Byte
|
||||
sequence<octet>? data = null; // Sequence of octets
|
||||
short le = -1; // The length of the expected
|
||||
// response data or -1 if none is expected
|
||||
};
|
||||
|
||||
[Pref="dom.secureelement.enabled",
|
||||
CheckPermissions="secureelement-manage",
|
||||
AvailableIn="CertifiedApps",
|
||||
JSImplementation="@mozilla.org/secureelement/reader;1"]
|
||||
interface SEReader {
|
||||
|
||||
// 'true' if a secure element is present
|
||||
readonly attribute boolean isSEPresent;
|
||||
|
||||
// Type of SecureElement
|
||||
readonly attribute SEType type;
|
||||
|
||||
/**
|
||||
* Opens a session with the Secure Element.
|
||||
* Note that a reader may have several opened sessions.
|
||||
*
|
||||
* @return If the operation is successful the promise is resolved with an instance of SESession.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<SESession> openSession();
|
||||
|
||||
/**
|
||||
* Closes all sessions associated with this Reader and its associated channels.
|
||||
*
|
||||
*/
|
||||
[Throws]
|
||||
Promise<void> closeAll();
|
||||
};
|
||||
|
||||
[Pref="dom.secureelement.enabled",
|
||||
CheckPermissions="secureelement-manage",
|
||||
AvailableIn="CertifiedApps",
|
||||
JSImplementation="@mozilla.org/secureelement/session;1"]
|
||||
interface SESession {
|
||||
|
||||
// 'reader' that provides this session
|
||||
readonly attribute SEReader reader;
|
||||
|
||||
// Status of current session
|
||||
readonly attribute boolean isClosed;
|
||||
|
||||
/**
|
||||
* Opens a communication logical channel to an application on Secure Element identified by the AID.
|
||||
* The 'aid' can be null for some secure elements.
|
||||
*
|
||||
* @param aid
|
||||
* Application Identifier of the Card Applet on the secure element.
|
||||
* If the 'aid' is null :
|
||||
* For secure element type 'eSE', the default applet is selected.
|
||||
* For secure element type 'uicc', the request will be immediately rejected.
|
||||
* Note that the length of 'aid should be between 5 and 16.
|
||||
*
|
||||
* @return If the operation is successful the promise is resolved with an instance of SEChannel.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<SEChannel> openLogicalChannel(Uint8Array? aid);
|
||||
|
||||
/**
|
||||
* Close all active channels associated with this session.
|
||||
*
|
||||
*/
|
||||
[Throws]
|
||||
Promise<void> closeAll();
|
||||
};
|
||||
|
||||
[Pref="dom.secureelement.enabled",
|
||||
CheckPermissions="secureelement-manage",
|
||||
AvailableIn="CertifiedApps",
|
||||
JSImplementation="@mozilla.org/secureelement/channel;1"]
|
||||
interface SEChannel {
|
||||
|
||||
// 'session' obj this channel is bound to
|
||||
readonly attribute SESession session;
|
||||
|
||||
// response to openBasicChannel / openLogicalChannel operation
|
||||
[Constant, Cached] readonly attribute Uint8Array? openResponse;
|
||||
|
||||
// Status of channel
|
||||
readonly attribute boolean isClosed;
|
||||
|
||||
// Type of channel
|
||||
readonly attribute SEChannelType type;
|
||||
|
||||
/**
|
||||
* Transmits the APDU command to the secure element. This is an atomic operation that transmits
|
||||
* an APDU command (as per ISO7816-4) to the secure element (UICC / eSE). Upon receiving response
|
||||
* to the transmit apdu command, it is propogated to the applications using SEResponse object.
|
||||
*
|
||||
* @param command
|
||||
* SECommand to be sent to secure element
|
||||
*
|
||||
* @return If success, the promise is resolved with the new created
|
||||
* SEResponse object. Otherwise, rejected with the error of type 'SEError'.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<SEResponse> transmit(optional SECommand command);
|
||||
|
||||
/**
|
||||
* Closes the active channel.
|
||||
*
|
||||
*/
|
||||
[Throws]
|
||||
Promise<void> close();
|
||||
};
|
||||
|
||||
[Pref="dom.secureelement.enabled",
|
||||
CheckPermissions="secureelement-manage",
|
||||
AvailableIn="CertifiedApps",
|
||||
JSImplementation="@mozilla.org/secureelement/response;1"]
|
||||
interface SEResponse {
|
||||
// Response received on this 'channel' object.
|
||||
[Constant] readonly attribute SEChannel channel;
|
||||
|
||||
// First octet of response's status word
|
||||
[Constant] readonly attribute octet sw1;
|
||||
|
||||
// Second octet of response's status word
|
||||
[Constant] readonly attribute octet sw2;
|
||||
|
||||
// The response's data field bytes
|
||||
[Cached, Pure] readonly attribute sequence<octet>? data;
|
||||
|
||||
};
|
||||
|
23
dom/webidl/SecureElementManager.webidl
Normal file
23
dom/webidl/SecureElementManager.webidl
Normal file
@ -0,0 +1,23 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Copyright © 2014 Deutsche Telekom, Inc. */
|
||||
|
||||
[Pref="dom.secureelement.enabled",
|
||||
CheckPermissions="secureelement-manage",
|
||||
AvailableIn="CertifiedApps",
|
||||
JSImplementation="@mozilla.org/secureelement/manager;1",
|
||||
NavigatorProperty="seManager",
|
||||
NoInterfaceObject]
|
||||
interface SEManager {
|
||||
|
||||
/**
|
||||
* Retrieves all the readers available on the device.
|
||||
*
|
||||
* @return If success, the promise is resolved to a sequence
|
||||
* of SEReaders Otherwise, rejected with an error.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<sequence<SEReader>> getSEReaders();
|
||||
};
|
@ -45,13 +45,9 @@ interface TelephonyCall : EventTarget {
|
||||
attribute EventHandler onstatechange;
|
||||
attribute EventHandler ondialing;
|
||||
attribute EventHandler onalerting;
|
||||
attribute EventHandler onconnecting;
|
||||
attribute EventHandler onconnected;
|
||||
attribute EventHandler ondisconnecting;
|
||||
attribute EventHandler ondisconnected;
|
||||
attribute EventHandler onholding;
|
||||
attribute EventHandler onheld;
|
||||
attribute EventHandler onresuming;
|
||||
attribute EventHandler onerror;
|
||||
|
||||
// Fired whenever the group attribute changes.
|
||||
|
@ -661,6 +661,12 @@ if CONFIG['MOZ_NFC']:
|
||||
'NfcOptions.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
WEBIDL_FILES += [
|
||||
'SecureElement.webidl',
|
||||
'SecureElementManager.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
WEBIDL_FILES += [
|
||||
'MozNetworkStats.webidl',
|
||||
|
@ -119,4 +119,9 @@ if CONFIG['MOZ_WEBSPEECH']:
|
||||
if CONFIG['MOZ_GSTREAMER']:
|
||||
CXXFLAGS += CONFIG['GSTREAMER_CFLAGS']
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/secureelement',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -4565,3 +4565,8 @@ pref("reader.toolbar.vertical", true);
|
||||
// loaded without sandboxing even if this pref is changed.
|
||||
pref("media.gmp.insecure.allow", false);
|
||||
#endif
|
||||
|
||||
// Secure Element API
|
||||
#ifdef MOZ_SECUREELEMENT
|
||||
pref("dom.secureelement.enabled", false);
|
||||
#endif
|
||||
|
@ -399,7 +399,8 @@ Classifier::RegenActiveTables()
|
||||
ScanStoreDir(foundTables);
|
||||
|
||||
for (uint32_t i = 0; i < foundTables.Length(); i++) {
|
||||
HashStore store(nsCString(foundTables[i]), mStoreDirectory);
|
||||
nsCString table(foundTables[i]);
|
||||
HashStore store(table, mStoreDirectory);
|
||||
|
||||
nsresult rv = store.Open();
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
// that the listmanagers tables are properly written on updates
|
||||
|
||||
// Log only if browser.safebrowsing.debug is true
|
||||
function log(...stuff) {
|
||||
this.log = function log(...stuff) {
|
||||
var prefs_ = new G_Preferences();
|
||||
var debug = prefs_.getPref("browser.safebrowsing.debug");
|
||||
if (!debug) {
|
||||
@ -29,7 +29,7 @@ function log(...stuff) {
|
||||
dump(msg + "\n");
|
||||
}
|
||||
|
||||
function QueryAdapter(callback) {
|
||||
this.QueryAdapter = function QueryAdapter(callback) {
|
||||
this.callback_ = callback;
|
||||
};
|
||||
|
||||
@ -43,7 +43,7 @@ QueryAdapter.prototype.handleResponse = function(value) {
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function PROT_ListManager() {
|
||||
this.PROT_ListManager = function PROT_ListManager() {
|
||||
log("Initializing list manager");
|
||||
this.prefs_ = new G_Preferences();
|
||||
this.updateInterval = this.prefs_.getPref("urlclassifier.updateinterval", 30 * 60) * 1000;
|
||||
|
@ -39,6 +39,7 @@
|
||||
* @param opt_maxTimes Number indicating a maximum number of times to
|
||||
* repeat (obviously only useful when opt_repeating==true)
|
||||
*/
|
||||
this.G_Alarm =
|
||||
function G_Alarm(callback, delayMS, opt_repeating, opt_maxTimes) {
|
||||
this.debugZone = "alarm";
|
||||
this.callback_ = callback;
|
||||
@ -124,11 +125,19 @@ G_Alarm.prototype.QueryInterface = function(iid) {
|
||||
*
|
||||
* For parameter documentation, see G_Alarm
|
||||
*/
|
||||
this.G_ConditionalAlarm =
|
||||
function G_ConditionalAlarm(callback, delayMS, opt_repeating, opt_maxTimes) {
|
||||
G_Alarm.call(this, callback, delayMS, opt_repeating, opt_maxTimes);
|
||||
this.debugZone = "conditionalalarm";
|
||||
}
|
||||
|
||||
G_ConditionalAlarm.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
|
||||
G_ConditionalAlarm.inherits(G_Alarm);
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,7 @@
|
||||
/**
|
||||
* Instantiate a new hasher. You must explicitly call init() before use!
|
||||
*/
|
||||
this.G_CryptoHasher =
|
||||
function G_CryptoHasher() {
|
||||
this.debugZone = "cryptohasher";
|
||||
this.hasher_ = null;
|
||||
@ -146,7 +147,7 @@ G_CryptoHasher.prototype.toHex_ = function(str) {
|
||||
/**
|
||||
* Lame unittest function
|
||||
*/
|
||||
function TEST_G_CryptoHasher() {
|
||||
this.TEST_G_CryptoHasher = function TEST_G_CryptoHasher() {
|
||||
if (G_GDEBUG) {
|
||||
var z = "cryptohasher UNITTEST";
|
||||
G_debugService.enableZone(z);
|
||||
|
@ -78,7 +78,7 @@ if (typeof G_GDEBUG == "undefined") {
|
||||
* zone to which this message belongs
|
||||
* @param msg Message to output
|
||||
*/
|
||||
function G_Debug(who, msg) {
|
||||
this.G_Debug = function G_Debug(who, msg) {
|
||||
if (G_GDEBUG) {
|
||||
G_GetDebugZone(who).debug(msg);
|
||||
}
|
||||
@ -87,7 +87,7 @@ function G_Debug(who, msg) {
|
||||
/**
|
||||
* Debugs loudly
|
||||
*/
|
||||
function G_DebugL(who, msg) {
|
||||
this.G_DebugL = function G_DebugL(who, msg) {
|
||||
if (G_GDEBUG) {
|
||||
var zone = G_GetDebugZone(who);
|
||||
|
||||
@ -110,7 +110,7 @@ function G_DebugL(who, msg) {
|
||||
* zone to which this message belongs
|
||||
* @param msg Message to output
|
||||
*/
|
||||
function G_TraceCall(who, msg) {
|
||||
this.G_TraceCall = function G_TraceCall(who, msg) {
|
||||
if (G_GDEBUG) {
|
||||
if (G_debugService.callTracingEnabled()) {
|
||||
G_debugService.dump(msg + "\n");
|
||||
@ -125,7 +125,7 @@ function G_TraceCall(who, msg) {
|
||||
* zone to which this message belongs
|
||||
* @param msg Message to output
|
||||
*/
|
||||
function G_Error(who, msg) {
|
||||
this.G_Error = function G_Error(who, msg) {
|
||||
if (G_GDEBUG) {
|
||||
G_GetDebugZone(who).error(msg);
|
||||
}
|
||||
@ -139,7 +139,7 @@ function G_Error(who, msg) {
|
||||
* @param condition Boolean condition to test
|
||||
* @param msg Message to output
|
||||
*/
|
||||
function G_Assert(who, condition, msg) {
|
||||
this.G_Assert = function G_Assert(who, condition, msg) {
|
||||
if (G_GDEBUG) {
|
||||
G_GetDebugZone(who).assert(condition, msg);
|
||||
}
|
||||
@ -153,7 +153,7 @@ function G_Assert(who, condition, msg) {
|
||||
* likely an object that has .debugZone property, or a string.
|
||||
* @returns The DebugZone object corresponding to the input
|
||||
*/
|
||||
function G_GetDebugZone(who) {
|
||||
this.G_GetDebugZone = function G_GetDebugZone(who) {
|
||||
if (G_GDEBUG) {
|
||||
var zone = "?";
|
||||
|
||||
@ -184,7 +184,7 @@ function G_GetDebugZone(who) {
|
||||
* when creating preferences to control this zone
|
||||
* @param zone String indicating the name of the zone
|
||||
*/
|
||||
function G_DebugZone(service, prefix, zone) {
|
||||
this.G_DebugZone = function G_DebugZone(service, prefix, zone) {
|
||||
if (G_GDEBUG) {
|
||||
this.debugService_ = service;
|
||||
this.prefix_ = prefix;
|
||||
@ -277,7 +277,7 @@ G_DebugZone.prototype.assert = function(condition, msg) {
|
||||
* @param opt_prefix Optional string indicating the unique prefix we should
|
||||
* use when creating preferences
|
||||
*/
|
||||
function G_DebugService(opt_prefix) {
|
||||
this.G_DebugService = function G_DebugService(opt_prefix) {
|
||||
if (G_GDEBUG) {
|
||||
this.prefix_ = opt_prefix ? opt_prefix : "safebrowsing-debug-service";
|
||||
this.consoleEnabledPrefName_ = this.prefix_ + ".alsologtoconsole";
|
||||
@ -628,7 +628,7 @@ G_DebugService.prototype.reportScriptError_ = function(message, sourceName,
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function G_Loggifier() {
|
||||
this.G_Loggifier = function G_Loggifier() {
|
||||
if (G_GDEBUG) {
|
||||
// Careful not to loggify ourselves!
|
||||
this.mark_(this);
|
||||
@ -795,7 +795,7 @@ G_Loggifier.prototype.loggify = function(obj) {
|
||||
* preferences tree. If a setting isn't in the preferences tree, then we grab it
|
||||
* from the defaults.
|
||||
*/
|
||||
function G_DebugSettings() {
|
||||
this.G_DebugSettings = function G_DebugSettings() {
|
||||
this.defaults_ = {};
|
||||
this.prefs_ = new G_Preferences();
|
||||
}
|
||||
@ -835,9 +835,9 @@ if (G_GDEBUG) {
|
||||
// Stubs for the debugging aids scattered through this component.
|
||||
// They will be expanded if you compile yourself a debug build.
|
||||
|
||||
function G_Debug(who, msg) { }
|
||||
function G_Assert(who, condition, msg) { }
|
||||
function G_Error(who, msg) { }
|
||||
var G_debugService = { __noSuchMethod__: function() { } };
|
||||
this.G_Debug = function G_Debug(who, msg) { }
|
||||
this.G_Assert = function G_Assert(who, condition, msg) { }
|
||||
this.G_Error = function G_Error(who, msg) { }
|
||||
this.G_debugService = { __noSuchMethod__: function() { } };
|
||||
|
||||
#endif
|
||||
|
@ -27,7 +27,7 @@
|
||||
*
|
||||
* @returns {function} A partially-applied form of the speficied function.
|
||||
*/
|
||||
function BindToObject(fn, self, opt_args) {
|
||||
this.BindToObject = function BindToObject(fn, self, opt_args) {
|
||||
var boundargs = fn.boundArgs_ || [];
|
||||
boundargs = boundargs.concat(Array.slice(arguments, 2, arguments.length));
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function G_ObserverWrapper(topic, observeFunction) {
|
||||
this.G_ObserverWrapper = function G_ObserverWrapper(topic, observeFunction) {
|
||||
this.debugZone = "observer";
|
||||
this.topic_ = topic;
|
||||
this.observeFunction_ = observeFunction;
|
||||
@ -70,6 +70,7 @@ G_ObserverWrapper.prototype.observe = function(subject, topic, data) {
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
this.G_ObserverServiceObserver =
|
||||
function G_ObserverServiceObserver(topic, observeFunction, opt_onlyOnce) {
|
||||
this.debugZone = "observerserviceobserver";
|
||||
this.topic_ = topic;
|
||||
@ -101,7 +102,7 @@ G_ObserverServiceObserver.prototype.observe_ = function(subject, topic, data) {
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
function TEST_G_Observer() {
|
||||
this.TEST_G_Observer = function TEST_G_Observer() {
|
||||
if (G_GDEBUG) {
|
||||
|
||||
var z = "observer UNITTEST";
|
||||
|
@ -46,6 +46,7 @@
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
this.G_Preferences =
|
||||
function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
|
||||
this.debugZone = "prefs";
|
||||
this.observers_ = {};
|
||||
@ -196,6 +197,7 @@ G_Preferences.prototype.removeAllObservers = function() {
|
||||
* @constructor
|
||||
* @param callback Function to call when the preference changes
|
||||
*/
|
||||
this.G_PreferenceObserver =
|
||||
function G_PreferenceObserver(callback) {
|
||||
this.debugZone = "prefobserver";
|
||||
this.callback_ = callback;
|
||||
@ -231,7 +233,7 @@ G_PreferenceObserver.prototype.QueryInterface = function(iid) {
|
||||
|
||||
#ifdef DEBUG
|
||||
// UNITTESTS
|
||||
function TEST_G_Preferences() {
|
||||
this.TEST_G_Preferences = function TEST_G_Preferences() {
|
||||
if (G_GDEBUG) {
|
||||
var z = "preferences UNITTEST";
|
||||
G_debugService.enableZone(z);
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function G_Protocol4Parser() {
|
||||
this.G_Protocol4Parser = function G_Protocol4Parser() {
|
||||
this.debugZone = "protocol4";
|
||||
|
||||
this.protocol4RegExp_ = new RegExp("([^:]+):\\d+:(.*)$");
|
||||
@ -80,7 +80,7 @@ G_Protocol4Parser.prototype.serialize = function(map) {
|
||||
/**
|
||||
* Cheesey unittests
|
||||
*/
|
||||
function TEST_G_Protocol4Parser() {
|
||||
this.TEST_G_Protocol4Parser = function TEST_G_Protocol4Parser() {
|
||||
if (G_GDEBUG) {
|
||||
var z = "protocol4 UNITTEST";
|
||||
G_debugService.enableZone(z);
|
||||
|
@ -15,6 +15,7 @@
|
||||
* @param callback Function callback function that takes true if the condition
|
||||
* passes.
|
||||
*/
|
||||
this.MultiQuerier =
|
||||
function MultiQuerier(tokens, tableName, callback) {
|
||||
this.tokens_ = tokens;
|
||||
this.tableName_ = tableName;
|
||||
@ -65,10 +66,18 @@ MultiQuerier.prototype.condition_ = function(value) {
|
||||
/**
|
||||
* Concrete MultiQuerier that stops if the key exists in the db.
|
||||
*/
|
||||
this.ExistsMultiQuerier =
|
||||
function ExistsMultiQuerier(tokens, tableName, callback) {
|
||||
MultiQuerier.call(this, tokens, tableName, callback);
|
||||
this.debugZone = "existsMultiQuerier";
|
||||
}
|
||||
|
||||
ExistsMultiQuerier.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
ExistsMultiQuerier.inherits(MultiQuerier);
|
||||
|
||||
ExistsMultiQuerier.prototype.condition_ = function(value) {
|
||||
@ -81,12 +90,20 @@ ExistsMultiQuerier.prototype.condition_ = function(value) {
|
||||
* checks the the resulting regular expressions for a match.
|
||||
* @param tokens Array of hosts
|
||||
*/
|
||||
this.EnchashMultiQuerier =
|
||||
function EnchashMultiQuerier(tokens, tableName, callback, url) {
|
||||
MultiQuerier.call(this, tokens, tableName, callback);
|
||||
this.url_ = url;
|
||||
this.enchashDecrypter_ = new PROT_EnchashDecrypter();
|
||||
this.debugZone = "enchashMultiQuerier";
|
||||
}
|
||||
|
||||
EnchashMultiQuerier.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
EnchashMultiQuerier.inherits(MultiQuerier);
|
||||
|
||||
EnchashMultiQuerier.prototype.run = function() {
|
||||
|
@ -12,9 +12,9 @@
|
||||
|
||||
// HTTP responses that count as an error. We also include any 5xx response
|
||||
// as an error.
|
||||
const HTTP_FOUND = 302;
|
||||
const HTTP_SEE_OTHER = 303;
|
||||
const HTTP_TEMPORARY_REDIRECT = 307;
|
||||
this.HTTP_FOUND = 302;
|
||||
this.HTTP_SEE_OTHER = 303;
|
||||
this.HTTP_TEMPORARY_REDIRECT = 307;
|
||||
|
||||
/**
|
||||
* @param maxErrors Number of times to request before backing off.
|
||||
@ -26,6 +26,7 @@ const HTTP_TEMPORARY_REDIRECT = 307;
|
||||
* we double this time for consecutive errors
|
||||
* @param maxTimeout Number time (ms) maximum timeout period
|
||||
*/
|
||||
this.RequestBackoff =
|
||||
function RequestBackoff(maxErrors, retryIncrement,
|
||||
maxRequests, requestPeriod,
|
||||
timeoutIncrement, maxTimeout) {
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Abstract base class for a lookup table.
|
||||
* @construction
|
||||
*/
|
||||
function UrlClassifierTable() {
|
||||
this.UrlClassifierTable = function UrlClassifierTable() {
|
||||
this.debugZone = "urlclassifier-table";
|
||||
this.name = '';
|
||||
this.needsUpdate = false;
|
||||
@ -34,9 +34,16 @@ UrlClassifierTable.prototype.exists = function(url, callback) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Url table implementation
|
||||
function UrlClassifierTableUrl() {
|
||||
this.UrlClassifierTableUrl = function UrlClassifierTableUrl() {
|
||||
UrlClassifierTable.call(this);
|
||||
}
|
||||
|
||||
UrlClassifierTableUrl.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
UrlClassifierTableUrl.inherits(UrlClassifierTable);
|
||||
|
||||
/**
|
||||
@ -63,12 +70,19 @@ UrlClassifierTableUrl.prototype.exists = function(url, callback) {
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Domain table implementation
|
||||
|
||||
function UrlClassifierTableDomain() {
|
||||
this.UrlClassifierTableDomain = function UrlClassifierTableDomain() {
|
||||
UrlClassifierTable.call(this);
|
||||
this.debugZone = "urlclassifier-table-domain";
|
||||
this.ioService_ = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
}
|
||||
|
||||
UrlClassifierTableDomain.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
UrlClassifierTableDomain.inherits(UrlClassifierTable);
|
||||
|
||||
/**
|
||||
@ -120,10 +134,17 @@ UrlClassifierTableDomain.prototype.exists = function(url, callback) {
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Enchash table implementation
|
||||
|
||||
function UrlClassifierTableEnchash() {
|
||||
this.UrlClassifierTableEnchash = function UrlClassifierTableEnchash() {
|
||||
UrlClassifierTable.call(this);
|
||||
this.debugZone = "urlclassifier-table-enchash";
|
||||
}
|
||||
|
||||
UrlClassifierTableEnchash.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
}
|
||||
UrlClassifierTableEnchash.inherits(UrlClassifierTable);
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,7 @@
|
||||
* that the table is a differential from the curent table the extension
|
||||
* has. Its absence means that this is a full, new table.
|
||||
*/
|
||||
this.PROT_VersionParser =
|
||||
function PROT_VersionParser(type, opt_major, opt_minor, opt_requireMac) {
|
||||
this.debugZone = "versionparser";
|
||||
this.type = type;
|
||||
@ -202,7 +203,7 @@ PROT_VersionParser.prototype.processOptTokens_ = function(line) {
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
function TEST_PROT_WireFormat() {
|
||||
this.TEST_PROT_WireFormat = function TEST_PROT_WireFormat() {
|
||||
if (G_GDEBUG) {
|
||||
var z = "versionparser UNITTEST";
|
||||
G_Debug(z, "Starting");
|
||||
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* @return XMLHttpRequest object
|
||||
*/
|
||||
function PROT_NewXMLHttpRequest() {
|
||||
this.PROT_NewXMLHttpRequest = function PROT_NewXMLHttpRequest() {
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
@ -37,7 +37,7 @@ function PROT_NewXMLHttpRequest() {
|
||||
* appId.
|
||||
* @constructor
|
||||
*/
|
||||
function PROT_XMLFetcher() {
|
||||
this.PROT_XMLFetcher = function PROT_XMLFetcher() {
|
||||
this.debugZone = "xmlfetcher";
|
||||
this._request = PROT_NewXMLHttpRequest();
|
||||
// implements nsILoadContext
|
||||
|
@ -14,7 +14,12 @@ function Init() {
|
||||
// Pull the library in.
|
||||
var jslib = Cc["@mozilla.org/url-classifier/jslib;1"]
|
||||
.getService().wrappedJSObject;
|
||||
Function.prototype.inherits = jslib.Function.prototype.inherits;
|
||||
Function.prototype.inherits = function(parentCtor) {
|
||||
var tempCtor = function(){};
|
||||
tempCtor.prototype = parentCtor.prototype;
|
||||
this.superClass_ = parentCtor.prototype;
|
||||
this.prototype = new tempCtor();
|
||||
},
|
||||
modScope.G_Preferences = jslib.G_Preferences;
|
||||
modScope.G_PreferenceObserver = jslib.G_PreferenceObserver;
|
||||
modScope.G_ObserverServiceObserver = jslib.G_ObserverServiceObserver;
|
||||
|
Loading…
Reference in New Issue
Block a user