Merge b2g-inbound to m-c. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2015-02-13 12:24:27 -05:00
commit f0ac763ef5
70 changed files with 2746 additions and 398 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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() {

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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 -->

View File

@ -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"
}

View File

@ -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 -->

View File

@ -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"/>

View File

@ -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

View File

@ -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

View File

@ -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 ========================================================

View File

@ -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
}
};

View File

@ -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

View File

@ -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
}

View File

@ -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)
{

View File

@ -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)

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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']

View File

@ -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',

View 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
]);

View 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}

View 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"];

View 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]);

View 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

View 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]);

View 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}

View 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);
};

View 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);

View 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'

View 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();
});

View File

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_SEUtils.js]

View File

@ -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) {

View File

@ -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

View File

@ -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.
*

View File

@ -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();
}

View File

@ -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

View File

@ -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")

View File

@ -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]

View File

@ -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);
});

View File

@ -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))

View File

@ -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))

View File

@ -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);
});

View 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;
};

View 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();
};

View File

@ -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.

View File

@ -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',

View File

@ -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'

View File

@ -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

View File

@ -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))

View File

@ -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;

View File

@ -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);
/**

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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";

View File

@ -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);

View File

@ -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);

View File

@ -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() {

View File

@ -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) {

View File

@ -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);
/**

View File

@ -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");

View File

@ -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

View File

@ -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;