mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound, a=merge
This commit is contained in:
commit
38f28af2e3
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -110,7 +110,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -115,7 +115,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
|
||||
<project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
|
||||
@ -117,7 +117,7 @@
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -115,7 +115,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
|
||||
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -127,7 +127,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -109,7 +109,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "e0fbadeb78a96137f071d9be7a47ef9fe882d17f",
|
||||
"git_revision": "65369b217faac7d70c1a29100c4208c6d1db16e3",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "aa2355f8f650e320a73584dfd2c5a4932577f6ea",
|
||||
"revision": "268edde8a1fcf00d4f4fbf9296f72d89ee754916",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
|
||||
@ -117,7 +117,7 @@
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e0fbadeb78a96137f071d9be7a47ef9fe882d17f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="65369b217faac7d70c1a29100c4208c6d1db16e3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -127,7 +127,7 @@
|
||||
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
|
||||
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
|
||||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
|
||||
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
|
||||
|
@ -1747,13 +1747,9 @@ pref("loop.contextInConversations.enabled", true);
|
||||
|
||||
pref("social.sidebar.unload_timeout_ms", 10000);
|
||||
|
||||
// activation from inside of share panel is possible if activationPanelEnabled
|
||||
// Activation from inside of share panel is possible if activationPanelEnabled
|
||||
// is true. Pref'd off for release while usage testing is done through beta.
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("social.share.activationPanelEnabled", true);
|
||||
#else
|
||||
pref("social.share.activationPanelEnabled", false);
|
||||
#endif
|
||||
pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
|
||||
|
||||
pref("dom.identity.enabled", false);
|
||||
|
@ -304,9 +304,12 @@ SocialActivationListener = {
|
||||
// and has never been visible, so we check the widget directly. If
|
||||
// there is no area for the widget we move it into the toolbar.
|
||||
let widget = CustomizableUI.getWidget("social-share-button");
|
||||
if (!widget.areaType) {
|
||||
// If the panel is already open, we can be sure that the provider can
|
||||
// already be accessed, possibly anchored to another toolbar button.
|
||||
// In that case we don't move the widget.
|
||||
if (!widget.areaType && SocialShare.panel.state != "open") {
|
||||
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
|
||||
// ensure correct state
|
||||
// Ensure correct state.
|
||||
SocialUI.onCustomizeEnd(window);
|
||||
}
|
||||
|
||||
@ -473,6 +476,9 @@ SocialShare = {
|
||||
let widget = CustomizableUI.getWidget("social-share-button");
|
||||
return widget.forWindow(window).anchor;
|
||||
},
|
||||
// Holds the anchor node in use whilst the panel is open, because it may vary.
|
||||
_currentAnchor: null,
|
||||
|
||||
get panel() {
|
||||
return document.getElementById("social-share-panel");
|
||||
},
|
||||
@ -578,12 +584,13 @@ SocialShare = {
|
||||
},
|
||||
|
||||
onShowing: function() {
|
||||
this.anchor.setAttribute("open", "true");
|
||||
(this._currentAnchor || this.anchor).setAttribute("open", "true");
|
||||
this.iframe.addEventListener("click", this._onclick, true);
|
||||
},
|
||||
|
||||
onHidden: function() {
|
||||
this.anchor.removeAttribute("open");
|
||||
(this._currentAnchor || this.anchor).removeAttribute("open");
|
||||
this._currentAnchor = null;
|
||||
this.iframe.removeEventListener("click", this._onclick, true);
|
||||
this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
|
||||
// make sure that the frame is unloaded after it is hidden
|
||||
@ -597,7 +604,7 @@ SocialShare = {
|
||||
}
|
||||
},
|
||||
|
||||
sharePage: function(providerOrigin, graphData, target) {
|
||||
sharePage: function(providerOrigin, graphData, target, anchor) {
|
||||
// if providerOrigin is undefined, we use the last-used provider, or the
|
||||
// current/default provider. The provider selection in the share panel
|
||||
// will call sharePage with an origin for us to switch to.
|
||||
@ -630,7 +637,7 @@ SocialShare = {
|
||||
pageData[p] = graphData[p];
|
||||
}
|
||||
}
|
||||
this.sharePage(providerOrigin, pageData, target);
|
||||
this.sharePage(providerOrigin, pageData, target, anchor);
|
||||
});
|
||||
gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData");
|
||||
return;
|
||||
@ -640,7 +647,7 @@ SocialShare = {
|
||||
messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => {
|
||||
messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn);
|
||||
pageData.microdata = msg.data;
|
||||
this.sharePage(providerOrigin, pageData, target);
|
||||
this.sharePage(providerOrigin, pageData, target, anchor);
|
||||
});
|
||||
gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, { target });
|
||||
return;
|
||||
@ -653,7 +660,7 @@ SocialShare = {
|
||||
else
|
||||
provider = this.getSelectedProvider();
|
||||
if (!provider || !provider.shareURL) {
|
||||
this.showDirectory();
|
||||
this.showDirectory(anchor);
|
||||
return;
|
||||
}
|
||||
// check the menu button
|
||||
@ -713,10 +720,10 @@ SocialShare = {
|
||||
let uri = Services.io.newURI(shareEndpoint, null, null);
|
||||
iframe.setAttribute("origin", provider.origin);
|
||||
iframe.setAttribute("src", shareEndpoint);
|
||||
this._openPanel();
|
||||
this._openPanel(anchor);
|
||||
},
|
||||
|
||||
showDirectory: function() {
|
||||
showDirectory: function(anchor) {
|
||||
this._createFrame();
|
||||
let iframe = this.iframe;
|
||||
if (iframe.getAttribute("src") == "about:providerdirectory")
|
||||
@ -740,11 +747,12 @@ SocialShare = {
|
||||
}, true);
|
||||
}, true);
|
||||
iframe.setAttribute("src", "about:providerdirectory");
|
||||
this._openPanel();
|
||||
this._openPanel(anchor);
|
||||
},
|
||||
|
||||
_openPanel: function() {
|
||||
let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
|
||||
_openPanel: function(anchor) {
|
||||
this._currentAnchor = anchor || this.anchor;
|
||||
anchor = document.getAnonymousElementByAttribute(this._currentAnchor, "class", "toolbarbutton-icon");
|
||||
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
|
||||
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
|
||||
}
|
||||
|
@ -77,7 +77,6 @@ loop.store = loop.store || {};
|
||||
* @type {Array}
|
||||
*/
|
||||
actions: [
|
||||
"addSocialShareButton",
|
||||
"addSocialShareProvider",
|
||||
"createRoom",
|
||||
"createdRoom",
|
||||
@ -375,15 +374,6 @@ loop.store = loop.store || {};
|
||||
this._mozLoop.notifyUITour("Loop:RoomURLShared");
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the Social Share button to the browser toolbar.
|
||||
*
|
||||
* @param {sharedActions.AddSocialShareButton} actionData The action data.
|
||||
*/
|
||||
addSocialShareButton: function(actionData) {
|
||||
this._mozLoop.addSocialShareButton();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the share panel to add a Social share provider.
|
||||
*
|
||||
|
@ -79,16 +79,9 @@ loop.roomViews = (function(mozL10n) {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomUrl: React.PropTypes.string,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
socialShareButtonAvailable: React.PropTypes.bool,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
handleToolbarAddButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.AddSocialShareButton());
|
||||
},
|
||||
|
||||
handleAddServiceClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@ -121,34 +114,9 @@ loop.roomViews = (function(mozL10n) {
|
||||
"share-service-dropdown": true,
|
||||
"dropdown-menu": true,
|
||||
"visually-hidden": true,
|
||||
"share-button-unavailable": !this.props.socialShareButtonAvailable,
|
||||
"hide": !this.props.show
|
||||
});
|
||||
|
||||
// When the button is not yet available, we offer to put it in the navbar
|
||||
// for the user.
|
||||
if (!this.props.socialShareButtonAvailable) {
|
||||
return (
|
||||
React.createElement("div", {className: shareDropdown},
|
||||
React.createElement("div", {className: "share-panel-header"},
|
||||
mozL10n.get("share_panel_header")
|
||||
),
|
||||
React.createElement("div", {className: "share-panel-body"},
|
||||
|
||||
mozL10n.get("share_panel_body", {
|
||||
brandShortname: mozL10n.get("brandShortname"),
|
||||
clientSuperShortname: mozL10n.get("clientSuperShortname")
|
||||
})
|
||||
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info btn-toolbar-add",
|
||||
onClick: this.handleToolbarAddButtonClick},
|
||||
mozL10n.get("add_to_toolbar_button")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("ul", {className: shareDropdown},
|
||||
React.createElement("li", {className: "dropdown-menu-item", onClick: this.handleAddServiceClick},
|
||||
@ -188,7 +156,8 @@ loop.roomViews = (function(mozL10n) {
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
showContext: React.PropTypes.bool.isRequired
|
||||
showContext: React.PropTypes.bool.isRequired,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -223,6 +192,14 @@ loop.roomViews = (function(mozL10n) {
|
||||
handleShareButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var providers = this.props.socialShareProviders;
|
||||
// If there are no providers available currently, save a click by dispatching
|
||||
// the 'AddSocialShareProvider' right away.
|
||||
if (!providers || !providers.length) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleDropdownMenu();
|
||||
},
|
||||
|
||||
@ -280,7 +257,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
dispatcher: this.props.dispatcher,
|
||||
roomUrl: this.props.roomData.roomUrl,
|
||||
show: this.state.showMenu,
|
||||
socialShareButtonAvailable: this.props.socialShareButtonAvailable,
|
||||
socialShareProviders: this.props.socialShareProviders,
|
||||
ref: "menu"}),
|
||||
React.createElement(DesktopRoomContextView, {
|
||||
@ -709,7 +685,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
savingContext: this.state.savingContext,
|
||||
show: shouldRenderInvitationOverlay,
|
||||
showContext: shouldRenderContextView,
|
||||
socialShareButtonAvailable: this.state.socialShareButtonAvailable,
|
||||
socialShareProviders: this.state.socialShareProviders}),
|
||||
React.createElement("div", {className: "video-layout-wrapper"},
|
||||
React.createElement("div", {className: "conversation room-conversation"},
|
||||
|
@ -79,16 +79,9 @@ loop.roomViews = (function(mozL10n) {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomUrl: React.PropTypes.string,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
socialShareButtonAvailable: React.PropTypes.bool,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
handleToolbarAddButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.AddSocialShareButton());
|
||||
},
|
||||
|
||||
handleAddServiceClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@ -121,34 +114,9 @@ loop.roomViews = (function(mozL10n) {
|
||||
"share-service-dropdown": true,
|
||||
"dropdown-menu": true,
|
||||
"visually-hidden": true,
|
||||
"share-button-unavailable": !this.props.socialShareButtonAvailable,
|
||||
"hide": !this.props.show
|
||||
});
|
||||
|
||||
// When the button is not yet available, we offer to put it in the navbar
|
||||
// for the user.
|
||||
if (!this.props.socialShareButtonAvailable) {
|
||||
return (
|
||||
<div className={shareDropdown}>
|
||||
<div className="share-panel-header">
|
||||
{mozL10n.get("share_panel_header")}
|
||||
</div>
|
||||
<div className="share-panel-body">
|
||||
{
|
||||
mozL10n.get("share_panel_body", {
|
||||
brandShortname: mozL10n.get("brandShortname"),
|
||||
clientSuperShortname: mozL10n.get("clientSuperShortname")
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<button className="btn btn-info btn-toolbar-add"
|
||||
onClick={this.handleToolbarAddButtonClick}>
|
||||
{mozL10n.get("add_to_toolbar_button")}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className={shareDropdown}>
|
||||
<li className="dropdown-menu-item" onClick={this.handleAddServiceClick}>
|
||||
@ -188,7 +156,8 @@ loop.roomViews = (function(mozL10n) {
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
showContext: React.PropTypes.bool.isRequired
|
||||
showContext: React.PropTypes.bool.isRequired,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -223,6 +192,14 @@ loop.roomViews = (function(mozL10n) {
|
||||
handleShareButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var providers = this.props.socialShareProviders;
|
||||
// If there are no providers available currently, save a click by dispatching
|
||||
// the 'AddSocialShareProvider' right away.
|
||||
if (!providers || !providers.length) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleDropdownMenu();
|
||||
},
|
||||
|
||||
@ -280,7 +257,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
dispatcher={this.props.dispatcher}
|
||||
roomUrl={this.props.roomData.roomUrl}
|
||||
show={this.state.showMenu}
|
||||
socialShareButtonAvailable={this.props.socialShareButtonAvailable}
|
||||
socialShareProviders={this.props.socialShareProviders}
|
||||
ref="menu" />
|
||||
<DesktopRoomContextView
|
||||
@ -709,7 +685,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
savingContext={this.state.savingContext}
|
||||
show={shouldRenderInvitationOverlay}
|
||||
showContext={shouldRenderContextView}
|
||||
socialShareButtonAvailable={this.state.socialShareButtonAvailable}
|
||||
socialShareProviders={this.state.socialShareProviders} />
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation room-conversation">
|
||||
|
@ -944,40 +944,12 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||
-moz-padding-end: 20px;
|
||||
}
|
||||
|
||||
.share-service-dropdown.share-button-unavailable {
|
||||
width: 230px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.share-service-dropdown > .dropdown-menu-item > .icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.share-service-dropdown .share-panel-header {
|
||||
background-image: url("../img/icons-16x16.svg#share-darkgrey");
|
||||
background-size: 3em 3em;
|
||||
background-repeat: no-repeat;
|
||||
min-height: 3em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1em;
|
||||
padding-left: 4.5em;
|
||||
}
|
||||
|
||||
body[dir=rtl] .share-service-dropdown .share-panel-header {
|
||||
background-position: top right;
|
||||
padding-left: 0;
|
||||
padding-right: 4.5em;
|
||||
}
|
||||
|
||||
.share-service-dropdown .btn-toolbar-add {
|
||||
padding: 4px 2px;
|
||||
border-radius: 2px;
|
||||
margin-top: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu-item > .icon-add-share-service {
|
||||
background-image: url("../img/icons-16x16.svg#add");
|
||||
background-repeat: no-repeat;
|
||||
|
@ -400,13 +400,6 @@ loop.shared.actions = (function() {
|
||||
roomUrl: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Add the Social Share button to the browser toolbar.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
AddSocialShareButton: Action.define("addSocialShareButton", {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Open the share panel to add a Social share provider.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
@ -436,7 +429,6 @@ loop.shared.actions = (function() {
|
||||
roomOwner: String,
|
||||
roomToken: String,
|
||||
roomUrl: String,
|
||||
socialShareButtonAvailable: Boolean,
|
||||
socialShareProviders: Array
|
||||
}),
|
||||
|
||||
@ -460,7 +452,6 @@ loop.shared.actions = (function() {
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
UpdateSocialShareInfo: Action.define("updateSocialShareInfo", {
|
||||
socialShareButtonAvailable: Boolean,
|
||||
socialShareProviders: Array
|
||||
}),
|
||||
|
||||
|
@ -115,8 +115,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
roomInfoFailure: null,
|
||||
// The name of the room.
|
||||
roomName: null,
|
||||
// Social API state.
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: null
|
||||
};
|
||||
},
|
||||
@ -218,7 +216,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
roomName: roomData.decryptedContext.roomName,
|
||||
roomOwner: roomData.roomOwner,
|
||||
roomUrl: roomData.roomUrl,
|
||||
socialShareButtonAvailable: this._mozLoop.isSocialShareButtonAvailable(),
|
||||
socialShareProviders: this._mozLoop.getSocialShareProviders()
|
||||
}));
|
||||
|
||||
@ -337,7 +334,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
roomState: ROOM_STATES.READY,
|
||||
roomToken: actionData.roomToken,
|
||||
roomUrl: actionData.roomUrl,
|
||||
socialShareButtonAvailable: actionData.socialShareButtonAvailable,
|
||||
socialShareProviders: actionData.socialShareProviders
|
||||
});
|
||||
|
||||
@ -379,7 +375,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
*/
|
||||
updateSocialShareInfo: function(actionData) {
|
||||
this.setStoreState({
|
||||
socialShareButtonAvailable: actionData.socialShareButtonAvailable,
|
||||
socialShareProviders: actionData.socialShareProviders
|
||||
});
|
||||
},
|
||||
@ -418,7 +413,6 @@ loop.store.ActiveRoomStore = (function() {
|
||||
*/
|
||||
_handleSocialShareUpdate: function() {
|
||||
this.dispatchAction(new sharedActions.UpdateSocialShareInfo({
|
||||
socialShareButtonAvailable: this._mozLoop.isSocialShareButtonAvailable(),
|
||||
socialShareProviders: this._mozLoop.getSocialShareProviders()
|
||||
}));
|
||||
},
|
||||
|
@ -969,58 +969,6 @@ function injectLoopAPI(targetWindow) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the Social Share widget is available in any of the registered
|
||||
* widget areas (navbar, MenuPanel, etc).
|
||||
*
|
||||
* @return {Boolean} `true` if the widget is available and `false` when it's
|
||||
* still in the Customization palette.
|
||||
*/
|
||||
isSocialShareButtonAvailable: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function() {
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!win || !win.CustomizableUI) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let widget = win.CustomizableUI.getWidget(kShareWidgetId);
|
||||
if (widget) {
|
||||
if (!socialShareButtonListenersAdded) {
|
||||
let eventName = "social:" + kShareWidgetId;
|
||||
Services.obs.addObserver(onShareWidgetChanged, eventName + "-added", false);
|
||||
Services.obs.addObserver(onShareWidgetChanged, eventName + "-removed", false);
|
||||
socialShareButtonListenersAdded = true;
|
||||
}
|
||||
return !!widget.areaType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the Social Share widget to the navbar area, but only when it's not
|
||||
* located anywhere else than the Customization palette.
|
||||
*/
|
||||
addSocialShareButton: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function() {
|
||||
// Don't do anything if the button is already available.
|
||||
if (api.isSocialShareButtonAvailable.value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!win || !win.CustomizableUI) {
|
||||
return;
|
||||
}
|
||||
win.CustomizableUI.addWidgetToArea(kShareWidgetId, win.CustomizableUI.AREA_NAVBAR);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Activates the Social Share panel with the Social Provider panel opened
|
||||
* when the popup open.
|
||||
@ -1029,23 +977,18 @@ function injectLoopAPI(targetWindow) {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function() {
|
||||
// Don't do anything if the button is _not_ available.
|
||||
if (!api.isSocialShareButtonAvailable.value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!win || !win.SocialShare) {
|
||||
return;
|
||||
}
|
||||
win.SocialShare.showDirectory();
|
||||
win.SocialShare.showDirectory(win.LoopUI.toolbarButton.anchor);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a sorted list of Social Providers that can share URLs. See
|
||||
* `updateSocialProvidersCache()` for more information.
|
||||
*
|
||||
*
|
||||
* @return {Array} Sorted list of share-capable Social Providers.
|
||||
*/
|
||||
getSocialShareProviders: {
|
||||
@ -1087,7 +1030,8 @@ function injectLoopAPI(targetWindow) {
|
||||
if (body) {
|
||||
graphData.body = body;
|
||||
}
|
||||
win.SocialShare.sharePage(providerOrigin, graphData);
|
||||
win.SocialShare.sharePage(providerOrigin, graphData, null,
|
||||
win.LoopUI.toolbarButton.anchor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -447,16 +447,6 @@ describe("loop.store.RoomStore", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#addSocialShareButton", function() {
|
||||
it("should invoke to the correct mozLoop function", function() {
|
||||
fakeMozLoop.addSocialShareButton = sinon.stub();
|
||||
|
||||
store.addSocialShareButton(new sharedActions.AddSocialShareButton());
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.addSocialShareButton);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#addSocialShareProvider", function() {
|
||||
it("should invoke to the correct mozLoop function", function() {
|
||||
fakeMozLoop.addSocialShareProvider = sinon.stub();
|
||||
|
@ -28,7 +28,6 @@ describe("loop.roomViews", function () {
|
||||
previews: [],
|
||||
title: ""
|
||||
}),
|
||||
isSocialShareButtonAvailable: sinon.stub(),
|
||||
rooms: {
|
||||
get: sinon.stub().callsArgWith(1, null, {
|
||||
roomToken: "fakeToken",
|
||||
@ -211,11 +210,27 @@ describe("loop.roomViews", function () {
|
||||
});
|
||||
|
||||
describe("Share button", function() {
|
||||
beforeEach(function() {
|
||||
it("should dispatch a AddSocialShareProvider action when the share button is clicked", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
var shareBtn = view.getDOMNode().querySelector(".btn-share");
|
||||
|
||||
React.addons.TestUtils.Simulate.click(shareBtn);
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWith(dispatcher.dispatch,
|
||||
new sharedActions.AddSocialShareProvider());
|
||||
});
|
||||
|
||||
it("should toggle the share dropdown when the share button is clicked", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareProviders: [{
|
||||
name: "foo",
|
||||
origin: "https://foo",
|
||||
iconURL: "http://example.com/foo.png"
|
||||
}]
|
||||
});
|
||||
|
||||
var shareBtn = view.getDOMNode().querySelector(".btn-share");
|
||||
|
||||
React.addons.TestUtils.Simulate.click(shareBtn);
|
||||
@ -552,18 +567,8 @@ describe("loop.roomViews", function () {
|
||||
expect(view.getDOMNode()).to.eql(null);
|
||||
});
|
||||
|
||||
it("should show different contents when the Share XUL button is not available", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareProviders: []
|
||||
});
|
||||
|
||||
var node = view.getDOMNode();
|
||||
expect(node.querySelector(".share-panel-header")).to.not.eql(null);
|
||||
});
|
||||
|
||||
it("should show an empty list when no Social Providers are available", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareButtonAvailable: true,
|
||||
socialShareProviders: []
|
||||
});
|
||||
|
||||
@ -574,7 +579,6 @@ describe("loop.roomViews", function () {
|
||||
|
||||
it("should show a list of available Social Providers", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareButtonAvailable: true,
|
||||
socialShareProviders: [fakeProvider]
|
||||
});
|
||||
|
||||
@ -590,26 +594,10 @@ describe("loop.roomViews", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#handleToolbarAddButtonClick", function() {
|
||||
it("should dispatch an action when the 'add to toolbar' button is clicked", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareProviders: []
|
||||
});
|
||||
|
||||
var addButton = view.getDOMNode().querySelector(".btn-toolbar-add");
|
||||
React.addons.TestUtils.Simulate.click(addButton);
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.AddSocialShareButton());
|
||||
});
|
||||
});
|
||||
|
||||
describe("#handleAddServiceClick", function() {
|
||||
it("should dispatch an action when the 'add provider' item is clicked", function() {
|
||||
view = mountTestComponent({
|
||||
socialShareProviders: [],
|
||||
socialShareButtonAvailable: true
|
||||
socialShareProviders: []
|
||||
});
|
||||
|
||||
var addItem = view.getDOMNode().querySelector(".dropdown-menu-item:first-child");
|
||||
@ -625,7 +613,6 @@ describe("loop.roomViews", function () {
|
||||
it("should dispatch an action when a provider item is clicked", function() {
|
||||
view = mountTestComponent({
|
||||
roomUrl: "http://example.com",
|
||||
socialShareButtonAvailable: true,
|
||||
socialShareProviders: [fakeProvider]
|
||||
});
|
||||
|
||||
|
@ -13,7 +13,6 @@ const {SocialService} = Cu.import("resource://gre/modules/SocialService.jsm", {}
|
||||
|
||||
add_task(loadLoopPanel);
|
||||
|
||||
const kShareWidgetId = "social-share-button";
|
||||
const kShareProvider = {
|
||||
name: "provider 1",
|
||||
origin: "https://example.com",
|
||||
@ -32,51 +31,7 @@ registerCleanupFunction(function* () {
|
||||
SocialShare.uninit();
|
||||
});
|
||||
|
||||
add_task(function* test_mozLoop_isSocialShareButtonAvailable() {
|
||||
Assert.ok(gMozLoopAPI, "mozLoop should exist");
|
||||
|
||||
// First make sure the Social Share button is not available. This is probably
|
||||
// already the case, but make it explicit here.
|
||||
CustomizableUI.removeWidgetFromArea(kShareWidgetId);
|
||||
|
||||
Assert.ok(!gMozLoopAPI.isSocialShareButtonAvailable(),
|
||||
"Social Share button should not be available");
|
||||
|
||||
// Add the widget to the navbar.
|
||||
CustomizableUI.addWidgetToArea(kShareWidgetId, CustomizableUI.AREA_NAVBAR);
|
||||
|
||||
Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
|
||||
"Social Share button should be available");
|
||||
|
||||
// Add the widget to the MenuPanel.
|
||||
CustomizableUI.addWidgetToArea(kShareWidgetId, CustomizableUI.AREA_PANEL);
|
||||
|
||||
Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
|
||||
"Social Share button should still be available");
|
||||
|
||||
// Test button removal during the same session.
|
||||
CustomizableUI.removeWidgetFromArea(kShareWidgetId);
|
||||
|
||||
Assert.ok(!gMozLoopAPI.isSocialShareButtonAvailable(),
|
||||
"Social Share button should not be available");
|
||||
});
|
||||
|
||||
add_task(function* test_mozLoop_addSocialShareButton() {
|
||||
gMozLoopAPI.addSocialShareButton();
|
||||
|
||||
Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
|
||||
"Social Share button should be available");
|
||||
|
||||
let widget = CustomizableUI.getWidget(kShareWidgetId);
|
||||
Assert.strictEqual(widget.areaType, CustomizableUI.TYPE_TOOLBAR,
|
||||
"Social Share button should be placed in the navbar");
|
||||
|
||||
CustomizableUI.removeWidgetFromArea(kShareWidgetId);
|
||||
});
|
||||
|
||||
add_task(function* test_mozLoop_addSocialShareProvider() {
|
||||
gMozLoopAPI.addSocialShareButton();
|
||||
|
||||
gMozLoopAPI.addSocialShareProvider();
|
||||
|
||||
yield promiseWaitForCondition(() => SocialShare.panel.state == "open");
|
||||
@ -85,7 +40,6 @@ add_task(function* test_mozLoop_addSocialShareProvider() {
|
||||
"Provider directory page should be visible");
|
||||
|
||||
SocialShare.panel.hidePopup();
|
||||
CustomizableUI.removeWidgetFromArea(kShareWidgetId);
|
||||
});
|
||||
|
||||
add_task(function* test_mozLoop_getSocialShareProviders() {
|
||||
@ -131,8 +85,6 @@ add_task(function* test_mozLoop_getSocialShareProviders() {
|
||||
});
|
||||
|
||||
add_task(function* test_mozLoop_socialShareRoom() {
|
||||
gMozLoopAPI.addSocialShareButton();
|
||||
|
||||
gMozLoopAPI.socialShareRoom(kShareProvider.origin, "https://someroom.com", "Some Title");
|
||||
|
||||
yield promiseWaitForCondition(() => SocialShare.panel.state == "open");
|
||||
@ -143,5 +95,4 @@ add_task(function* test_mozLoop_socialShareRoom() {
|
||||
"Provider's share page should be displayed");
|
||||
|
||||
SocialShare.panel.hidePopup();
|
||||
CustomizableUI.removeWidgetFromArea(kShareWidgetId);
|
||||
});
|
||||
|
@ -37,7 +37,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
},
|
||||
setScreenShareState: sinon.stub(),
|
||||
getActiveTabWindowId: sandbox.stub().callsArgWith(0, null, 42),
|
||||
isSocialShareButtonAvailable: sinon.stub().returns(false),
|
||||
getSocialShareProviders: sinon.stub().returns([])
|
||||
};
|
||||
|
||||
@ -289,7 +288,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
roomName: fakeRoomData.decryptedContext.roomName,
|
||||
roomOwner: fakeRoomData.roomOwner,
|
||||
roomUrl: fakeRoomData.roomUrl,
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: []
|
||||
}));
|
||||
});
|
||||
@ -550,7 +548,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
roomOwner: "Me",
|
||||
roomToken: "fakeToken",
|
||||
roomUrl: "http://invalid",
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: []
|
||||
};
|
||||
});
|
||||
@ -569,7 +566,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
expect(state.roomOwner).eql(fakeRoomInfo.roomOwner);
|
||||
expect(state.roomToken).eql(fakeRoomInfo.roomToken);
|
||||
expect(state.roomUrl).eql(fakeRoomInfo.roomUrl);
|
||||
expect(state.socialShareButtonAvailable).eql(false);
|
||||
expect(state.socialShareProviders).eql([]);
|
||||
});
|
||||
});
|
||||
@ -606,7 +602,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
|
||||
beforeEach(function() {
|
||||
fakeSocialShareInfo = {
|
||||
socialShareButtonAvailable: true,
|
||||
socialShareProviders: [{
|
||||
name: "foo",
|
||||
origin: "https://example.com",
|
||||
@ -619,8 +614,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
store.updateSocialShareInfo(new sharedActions.UpdateSocialShareInfo(fakeSocialShareInfo));
|
||||
|
||||
var state = store.getStoreState();
|
||||
expect(state.socialShareButtonAvailable)
|
||||
.eql(fakeSocialShareInfo.socialShareButtonAvailable);
|
||||
expect(state.socialShareProviders)
|
||||
.eql(fakeSocialShareInfo.socialShareProviders);
|
||||
});
|
||||
@ -1368,7 +1361,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.UpdateSocialShareInfo({
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: []
|
||||
}));
|
||||
});
|
||||
@ -1376,7 +1368,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
it("should call respective mozLoop methods", function() {
|
||||
store._handleSocialShareUpdate();
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.isSocialShareButtonAvailable);
|
||||
sinon.assert.calledOnce(fakeMozLoop.getSocialShareProviders);
|
||||
});
|
||||
});
|
||||
@ -1389,7 +1380,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
roomOwner: "Me",
|
||||
roomToken: "fakeToken",
|
||||
roomUrl: "http://invalid",
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: []
|
||||
}));
|
||||
});
|
||||
@ -1438,7 +1428,6 @@ describe("loop.store.ActiveRoomStore", function () {
|
||||
beforeEach(function() {
|
||||
store.setupRoomInfo(new sharedActions.SetupRoomInfo(
|
||||
_.extend(fakeRoomData, {
|
||||
socialShareButtonAvailable: false,
|
||||
socialShareProviders: []
|
||||
})
|
||||
));
|
||||
|
@ -32,8 +32,9 @@
|
||||
"brace-style": [2, "1tbs", {"allowSingleLine": false}],
|
||||
// Require camel case names
|
||||
"camelcase": 2,
|
||||
// Disallow trailing commas. Not valid JSON notation.
|
||||
"comma-dangle": 1,
|
||||
// Allow trailing commas for easy list extension. Having them does not
|
||||
// impair readability, but also not required either.
|
||||
"comma-dangle": 0,
|
||||
// Enforce spacing before and after comma
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
// Enforce one true comma style.
|
||||
|
@ -1910,16 +1910,6 @@ Breakpoints.prototype = {
|
||||
// editor itself.
|
||||
let breakpointClient = yield this.addBreakpoint(location, { noEditorUpdate: true });
|
||||
|
||||
// If the breakpoint client has a "requestedLocation" attached, then
|
||||
// the original requested placement for the breakpoint wasn't accepted.
|
||||
// In this case, we need to update the editor with the new location.
|
||||
if (breakpointClient.requestedLocation) {
|
||||
DebuggerView.editor.moveBreakpoint(
|
||||
breakpointClient.requestedLocation.line - 1,
|
||||
breakpointClient.location.line - 1
|
||||
);
|
||||
}
|
||||
|
||||
// Notify that we've shown a breakpoint in the source editor.
|
||||
window.emit(EVENTS.BREAKPOINT_SHOWN_IN_EDITOR);
|
||||
}),
|
||||
@ -2030,11 +2020,40 @@ Breakpoints.prototype = {
|
||||
source.setBreakpoint(aLocation, Task.async(function*(aResponse, aBreakpointClient) {
|
||||
// If the breakpoint response has an "actualLocation" attached, then
|
||||
// the original requested placement for the breakpoint wasn't accepted.
|
||||
if (aResponse.actualLocation) {
|
||||
// Remember the initialization promise for the new location instead.
|
||||
let actualLocation = aResponse.actualLocation;
|
||||
if (actualLocation) {
|
||||
// Update the editor to reflect the new location of the breakpoint. We
|
||||
// always need to do this, even when we already have a breakpoint for
|
||||
// the actual location, because the editor already as already shown the
|
||||
// breakpoint at the original location at this point. Calling
|
||||
// moveBreakpoint will hide the breakpoint at the original location, and
|
||||
// show it at the actual location, if necessary.
|
||||
//
|
||||
// FIXME: The call to moveBreakpoint triggers another call to remove-
|
||||
// and addBreakpoint, respectively. These calls do not have any effect,
|
||||
// because there is no breakpoint to remove at the old location, and
|
||||
// the breakpoint is already being added at the new location, but they
|
||||
// are redundant and confusing.
|
||||
DebuggerView.editor.moveBreakpoint(
|
||||
aBreakpointClient.location.line - 1,
|
||||
actualLocation.line - 1
|
||||
);
|
||||
|
||||
aBreakpointClient.location = actualLocation;
|
||||
aBreakpointClient.location.actor = actualLocation.source
|
||||
? actualLocation.source.actor
|
||||
: null;
|
||||
|
||||
let oldIdentifier = identifier;
|
||||
let newIdentifier = identifier = this.getIdentifier(aResponse.actualLocation);
|
||||
this._added.delete(oldIdentifier);
|
||||
|
||||
if ((addedPromise = this._getAdded(actualLocation))) {
|
||||
deferred.resolve(addedPromise);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remember the initialization promise for the new location instead.
|
||||
let newIdentifier = identifier = this.getIdentifier(actualLocation);
|
||||
this._added.set(newIdentifier, deferred.promise);
|
||||
}
|
||||
|
||||
@ -2055,15 +2074,6 @@ Breakpoints.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (aResponse.actualLocation) {
|
||||
// Store the originally requested location in case it's ever needed
|
||||
// and update the breakpoint client with the actual location.
|
||||
let actualLoc = aResponse.actualLocation;
|
||||
aBreakpointClient.requestedLocation = aLocation;
|
||||
aBreakpointClient.location = actualLoc;
|
||||
aBreakpointClient.location.actor = actualLoc.source ? actualLoc.source.actor : null;
|
||||
}
|
||||
|
||||
// Preserve information about the breakpoint's line text, to display it
|
||||
// in the sources pane without requiring fetching the source (for example,
|
||||
// after the target navigated). Note that this will get out of sync
|
||||
@ -2071,8 +2081,7 @@ Breakpoints.prototype = {
|
||||
let line = aBreakpointClient.location.line - 1;
|
||||
aBreakpointClient.text = DebuggerView.editor.getText(line).trim();
|
||||
|
||||
// Show the breakpoint in the editor and breakpoints pane, and
|
||||
// resolve.
|
||||
// Show the breakpoint in the breakpoints pane, and resolve.
|
||||
yield this._showBreakpoint(aBreakpointClient, aOptions);
|
||||
|
||||
// Notify that we've added a breakpoint.
|
||||
|
@ -49,11 +49,6 @@ function test() {
|
||||
is(aBreakpointClient.location.line, 6,
|
||||
"Breakpoint client line is new.");
|
||||
|
||||
is(aBreakpointClient.requestedLocation.actor, gSources.selectedValue,
|
||||
"Requested location url is correct");
|
||||
is(aBreakpointClient.requestedLocation.line, 4,
|
||||
"Requested location line is correct");
|
||||
|
||||
onBpDebuggerAdd = true;
|
||||
maybeFinish();
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ function test() {
|
||||
actor: gSources.selectedValue,
|
||||
line: 17
|
||||
});
|
||||
|
||||
testMovedLocation(movedBpClient);
|
||||
|
||||
yield resumeAndTestBreakpoint(19);
|
||||
@ -93,10 +94,5 @@ function test() {
|
||||
"Breakpoint client url is the same.");
|
||||
is(breakpointClient.location.line, 19,
|
||||
"Breakpoint client line is new.");
|
||||
|
||||
is(breakpointClient.requestedLocation.actor, gSources.selectedValue,
|
||||
"Requested location url is correct");
|
||||
is(breakpointClient.requestedLocation.line, 17,
|
||||
"Requested location line is correct");
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ FontInspector.prototype = {
|
||||
init: function() {
|
||||
this.update = this.update.bind(this);
|
||||
this.onNewNode = this.onNewNode.bind(this);
|
||||
this.onThemeChanged = this.onThemeChanged.bind(this);
|
||||
this.inspector.selection.on("new-node", this.onNewNode);
|
||||
this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
|
||||
this.showAll = this.showAll.bind(this);
|
||||
@ -36,6 +37,10 @@ FontInspector.prototype = {
|
||||
this.previewTextChanged = this.previewTextChanged.bind(this);
|
||||
this.previewInput = this.chromeDoc.getElementById("preview-text-input");
|
||||
this.previewInput.addEventListener("input", this.previewTextChanged);
|
||||
|
||||
// Listen for theme changes as the color of the previews depend on the theme
|
||||
gDevTools.on("theme-switched", this.onThemeChanged);
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
@ -57,6 +62,8 @@ FontInspector.prototype = {
|
||||
this.showAllButton.removeEventListener("click", this.showAll);
|
||||
this.previewInput.removeEventListener("input", this.previewTextChanged);
|
||||
|
||||
gDevTools.off("theme-switched", this.onThemeChanged);
|
||||
|
||||
if (this._previewUpdateTimeout) {
|
||||
clearTimeout(this._previewUpdateTimeout);
|
||||
}
|
||||
@ -103,6 +110,15 @@ FontInspector.prototype = {
|
||||
}, PREVIEW_UPDATE_DELAY);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the theme-switched event.
|
||||
*/
|
||||
onThemeChanged: function(event, frame) {
|
||||
if (frame === this.chromeDoc.defaultView) {
|
||||
this.update(this._lastUpdateShowedAllFonts);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the font list. No node are selected.
|
||||
*/
|
||||
|
@ -11,3 +11,4 @@ support-files =
|
||||
[browser_fontinspector.js]
|
||||
[browser_fontinspector_edit-previews.js]
|
||||
[browser_fontinspector_edit-previews-show-all.js]
|
||||
[browser_fontinspector_theme-change.js]
|
||||
|
@ -0,0 +1,53 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that the preview images are updated when the theme changes.
|
||||
|
||||
const { getTheme, setTheme } = devtools.require("devtools/shared/theme");
|
||||
|
||||
const TEST_URI = BASE_URI + "browser_fontinspector.html";
|
||||
const originalTheme = getTheme();
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
info(`Restoring theme to '${originalTheme}.`);
|
||||
setTheme(originalTheme);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, fontInspector } = yield openFontInspectorForURL(TEST_URI);
|
||||
let { chromeDoc: doc } = fontInspector;
|
||||
|
||||
yield selectNode(".normal-text", inspector);
|
||||
|
||||
// Store the original preview URI for later comparison.
|
||||
let originalURI = doc.querySelector("#all-fonts .font-preview").src;
|
||||
let newTheme = originalTheme === "light" ? "dark" : "light";
|
||||
|
||||
info(`Original theme was '${originalTheme}'.`);
|
||||
|
||||
yield setThemeAndWaitForUpdate(newTheme, inspector);
|
||||
isnot(doc.querySelector("#all-fonts .font-preview").src, originalURI,
|
||||
"The preview image changed with the theme.");
|
||||
|
||||
yield setThemeAndWaitForUpdate(originalTheme, inspector);
|
||||
is(doc.querySelector("#all-fonts .font-preview").src, originalURI,
|
||||
"The preview image is correct after the original theme was restored.");
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the current theme and waits for fontinspector-updated event.
|
||||
*
|
||||
* @param {String} theme - the new theme
|
||||
* @param {Object} inspector - the inspector panel
|
||||
*/
|
||||
function* setThemeAndWaitForUpdate(theme, inspector) {
|
||||
let onUpdated = inspector.once("fontinspector-updated");
|
||||
|
||||
info(`Setting theme to '${theme}'.`);
|
||||
setTheme(theme);
|
||||
|
||||
info("Waiting for font-inspector to update.");
|
||||
yield onUpdated;
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
* theme on load, and rerenders when changed.
|
||||
*/
|
||||
|
||||
const { setTheme } = devtools.require("devtools/shared/theme");
|
||||
|
||||
const LIGHT_BG = "#fcfcfc";
|
||||
const DARK_BG = "#14171a";
|
||||
|
||||
@ -70,19 +72,3 @@ function* spawnTest() {
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics selecting the theme selector in the toolbox;
|
||||
* sets the preference and emits an event on gDevTools to trigger
|
||||
* the themeing.
|
||||
*/
|
||||
function setTheme (newTheme) {
|
||||
let oldTheme = Services.prefs.getCharPref("devtools.theme");
|
||||
info("Setting `devtools.theme` to \"" + newTheme + "\"");
|
||||
Services.prefs.setCharPref("devtools.theme", newTheme);
|
||||
gDevTools.emit("pref-changed", {
|
||||
pref: "devtools.theme",
|
||||
newValue: newTheme,
|
||||
oldValue: oldTheme
|
||||
});
|
||||
}
|
||||
|
@ -27,6 +27,14 @@ function testGetTheme () {
|
||||
|
||||
function testSetTheme () {
|
||||
let originalTheme = getTheme();
|
||||
gDevTools.once("pref-changed", (_, { pref, oldValue, newValue }) => {
|
||||
is(pref, "devtools.theme",
|
||||
"The 'pref-changed' event triggered by setTheme has correct pref.");
|
||||
is(oldValue, originalTheme,
|
||||
"The 'pref-changed' event triggered by setTheme has correct oldValue.");
|
||||
is(newValue, "dark",
|
||||
"The 'pref-changed' event triggered by setTheme has correct newValue.");
|
||||
});
|
||||
setTheme("dark");
|
||||
is(Services.prefs.getCharPref("devtools.theme"), "dark", "setTheme() correctly sets dark theme.");
|
||||
setTheme("light");
|
||||
|
@ -85,10 +85,12 @@ const getColor = exports.getColor = (type, theme) => {
|
||||
* the themeing.
|
||||
*/
|
||||
const setTheme = exports.setTheme = (newTheme) => {
|
||||
let oldTheme = getTheme();
|
||||
|
||||
Services.prefs.setCharPref("devtools.theme", newTheme);
|
||||
gDevTools.emit("pref-changed", {
|
||||
pref: "devtools.theme",
|
||||
newValue: newTheme,
|
||||
oldValue: getTheme()
|
||||
oldValue: oldTheme
|
||||
});
|
||||
};
|
||||
|
@ -52,7 +52,6 @@ support-files =
|
||||
[browser_styleeditor_autocomplete.js]
|
||||
[browser_styleeditor_autocomplete-disabled.js]
|
||||
[browser_styleeditor_bug_740541_iframes.js]
|
||||
skip-if = os == "linux" || "mac" # bug 949355
|
||||
[browser_styleeditor_bug_851132_middle_click.js]
|
||||
[browser_styleeditor_bug_870339.js]
|
||||
[browser_styleeditor_cmd_edit.js]
|
||||
|
@ -5,6 +5,8 @@
|
||||
* Tests that the SVG marker styling is updated when devtools theme changes.
|
||||
*/
|
||||
|
||||
const { setTheme } = devtools.require("devtools/shared/theme");
|
||||
|
||||
add_task(function*() {
|
||||
let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { panelWin } = panel;
|
||||
@ -57,19 +59,3 @@ add_task(function*() {
|
||||
function getFill (el) {
|
||||
return el.getAttribute("style").match(/(#.*)$/)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics selecting the theme selector in the toolbox;
|
||||
* sets the preference and emits an event on gDevTools to trigger
|
||||
* the themeing.
|
||||
*/
|
||||
function setTheme (newTheme) {
|
||||
let oldTheme = Services.prefs.getCharPref("devtools.theme");
|
||||
info("Setting `devtools.theme` to \"" + newTheme + "\"");
|
||||
Services.prefs.setCharPref("devtools.theme", newTheme);
|
||||
gDevTools.emit("pref-changed", {
|
||||
pref: "devtools.theme",
|
||||
newValue: newTheme,
|
||||
oldValue: oldTheme
|
||||
});
|
||||
}
|
||||
|
@ -74,11 +74,6 @@ share_tweet=Join me for a video conversation on {{clientShortname2}}!
|
||||
|
||||
share_button3=Share Link
|
||||
share_add_service_button=Add a Service
|
||||
add_to_toolbar_button=Add the Share panel to my toolbar
|
||||
share_panel_header=Share the web with your friends!
|
||||
## LOCALIZATION NOTE (share_panel_body): In this item, don't translate the part
|
||||
## between {{..}}.
|
||||
share_panel_body={{brandShortname}}'s new Share panel allows you to quickly share links or {{clientSuperShortname}} invitations with your favourite social networks.
|
||||
copy_url_button2=Copy Link
|
||||
copied_url_button=Copied!
|
||||
|
||||
|
@ -10,12 +10,17 @@
|
||||
color: black;
|
||||
direction: ltr;
|
||||
-moz-control-character-visibility: visible;
|
||||
height: 100%;
|
||||
}
|
||||
#viewsource {
|
||||
font-family: -moz-fixed;
|
||||
font-weight: normal;
|
||||
white-space: pre;
|
||||
counter-reset: line;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
}
|
||||
#viewsource.wrap {
|
||||
white-space: pre-wrap;
|
||||
@ -24,7 +29,7 @@
|
||||
pre {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
white-space: inherit;
|
||||
white-space: inherit;
|
||||
margin: 0 0 0 5ch;
|
||||
}
|
||||
pre[id]:before,
|
||||
|
@ -5,10 +5,10 @@
|
||||
package org.mozilla.gecko.background.common;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
|
||||
/**
|
||||
* Preprocessed class for storing preprocessed values common to all
|
||||
* Android services.
|
||||
* Constant values common to all Android services.
|
||||
*/
|
||||
public class GlobalConstants {
|
||||
public static final String BROWSER_INTENT_PACKAGE = AppConstants.ANDROID_PACKAGE_NAME;
|
||||
@ -35,4 +35,80 @@ public class GlobalConstants {
|
||||
// Common time values.
|
||||
public static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
public static final long MILLISECONDS_PER_SIX_MONTHS = 180 * MILLISECONDS_PER_DAY;
|
||||
|
||||
// Acceptable cipher suites.
|
||||
/**
|
||||
* We support only a very limited range of strong cipher suites and protocols:
|
||||
* no SSLv3 or TLSv1.0 (if we can), no DHE ciphers that might be vulnerable to Logjam
|
||||
* (https://weakdh.org/), no RC4.
|
||||
*
|
||||
* Backstory: Bug 717691 (we no longer support Android 2.2, so the name
|
||||
* workaround is unnecessary), Bug 1081953, Bug 1061273, Bug 1166839.
|
||||
*
|
||||
* See <http://developer.android.com/reference/javax/net/ssl/SSLSocket.html> for
|
||||
* supported Android versions for each set of protocols and cipher suites.
|
||||
*
|
||||
* Note that currently we need to support connections to Sync 1.1 on Mozilla-hosted infra,
|
||||
* as well as connections to FxA and Sync 1.5 on AWS.
|
||||
*
|
||||
* ELB cipher suites:
|
||||
* <http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-security-policy-table.html>
|
||||
*/
|
||||
public static final String[] DEFAULT_CIPHER_SUITES;
|
||||
public static final String[] DEFAULT_PROTOCOLS;
|
||||
|
||||
static {
|
||||
// Prioritize 128 over 256 as a tradeoff between device CPU/battery and the minor
|
||||
// increase in strength.
|
||||
if (Versions.feature20Plus) {
|
||||
DEFAULT_CIPHER_SUITES = new String[]
|
||||
{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 11+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 11+
|
||||
};
|
||||
} else if (Versions.feature11Plus) {
|
||||
DEFAULT_CIPHER_SUITES = new String[]
|
||||
{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 11+
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 11+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 11+
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA", // 9+
|
||||
};
|
||||
} else { // 9+
|
||||
// Fall back to the only half-decent cipher suites supported on Gingerbread.
|
||||
// N.B., there appears to be *no overlap* between the ELB 2015-05 default
|
||||
// suites and Gingerbread. A custom configuration is needed if moving beyond
|
||||
// the 2015-03 defaults.
|
||||
DEFAULT_CIPHER_SUITES = new String[]
|
||||
{
|
||||
// This is for Sync 1.5 on ELB 2015-03.
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
|
||||
|
||||
// This is for Sync 1.1.
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", // 9+
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA", // 9+
|
||||
};
|
||||
}
|
||||
|
||||
if (Versions.feature16Plus) {
|
||||
DEFAULT_PROTOCOLS = new String[]
|
||||
{
|
||||
"TLSv1.2",
|
||||
"TLSv1.1",
|
||||
"TLSv1", // We would like to remove this, and will do so when we can.
|
||||
};
|
||||
} else {
|
||||
// Fall back to TLSv1 if there's nothing better.
|
||||
DEFAULT_PROTOCOLS = new String[]
|
||||
{
|
||||
"TLSv1",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import org.json.JSONArray;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -184,10 +183,10 @@ final class DisplayPortCalculator {
|
||||
float top = metrics.viewportRectTop - margins.top;
|
||||
float right = metrics.viewportRectRight + margins.right;
|
||||
float bottom = metrics.viewportRectBottom + margins.bottom;
|
||||
left = Math.max(metrics.pageRectLeft, TILE_SIZE * FloatMath.floor(left / TILE_SIZE));
|
||||
top = Math.max(metrics.pageRectTop, TILE_SIZE * FloatMath.floor(top / TILE_SIZE));
|
||||
right = Math.min(metrics.pageRectRight, TILE_SIZE * FloatMath.ceil(right / TILE_SIZE));
|
||||
bottom = Math.min(metrics.pageRectBottom, TILE_SIZE * FloatMath.ceil(bottom / TILE_SIZE));
|
||||
left = (float) Math.max(metrics.pageRectLeft, TILE_SIZE * Math.floor(left / TILE_SIZE));
|
||||
top = (float) Math.max(metrics.pageRectTop, TILE_SIZE * Math.floor(top / TILE_SIZE));
|
||||
right = (float) Math.min(metrics.pageRectRight, TILE_SIZE * Math.ceil(right / TILE_SIZE));
|
||||
bottom = (float) Math.min(metrics.pageRectBottom, TILE_SIZE * Math.ceil(bottom / TILE_SIZE));
|
||||
return new DisplayPortMetrics(left, top, right, bottom, zoom);
|
||||
}
|
||||
|
||||
@ -747,7 +746,7 @@ final class DisplayPortCalculator {
|
||||
public boolean drawTimeUpdate(long millis, int pixels) {
|
||||
// calculate the number of frames it took to draw a viewport-sized area
|
||||
float normalizedTime = (float)mPixelArea * millis / pixels;
|
||||
int normalizedFrames = (int)FloatMath.ceil(normalizedTime * 60f / 1000f);
|
||||
int normalizedFrames = (int) Math.ceil(normalizedTime * 60f / 1000f);
|
||||
// broaden our range on how long it takes to draw if the draw falls outside
|
||||
// the range. this allows it to grow gradually. this heuristic may need to
|
||||
// be tweaked into more of a floating window average or something.
|
||||
|
@ -8,8 +8,6 @@ package org.mozilla.gecko.gfx;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.util.FloatMath;
|
||||
|
||||
public class IntSize {
|
||||
public final int width, height;
|
||||
|
||||
@ -75,7 +73,7 @@ public class IntSize {
|
||||
}
|
||||
|
||||
public static int largestPowerOfTwoLessThan(float value) {
|
||||
int val = (int)FloatMath.floor(value);
|
||||
int val = (int) Math.floor(value);
|
||||
if (val <= 0) {
|
||||
throw new IllegalArgumentException("Error: value must be > 0");
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.InputDevice;
|
||||
@ -668,7 +667,7 @@ class JavaPanZoomController
|
||||
private float panDistance(MotionEvent move) {
|
||||
float dx = mX.panDistance(move.getX(0));
|
||||
float dy = mY.panDistance(move.getY(0));
|
||||
return FloatMath.sqrt(dx * dx + dy * dy);
|
||||
return (float) Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
private void track(float x, float y, long time) {
|
||||
@ -801,7 +800,7 @@ class JavaPanZoomController
|
||||
private float getVelocity() {
|
||||
float xvel = mX.getRealVelocity();
|
||||
float yvel = mY.getRealVelocity();
|
||||
return FloatMath.sqrt(xvel * xvel + yvel * yvel);
|
||||
return (float) Math.sqrt(xvel * xvel + yvel * yvel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,9 +6,6 @@ package org.mozilla.gecko.sync;
|
||||
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
|
||||
/**
|
||||
* Preprocessed class for storing preprocessed values specific to Android Sync.
|
||||
*/
|
||||
public class SyncConstants {
|
||||
public static final String GLOBAL_LOG_TAG = "FxSync";
|
||||
public static final String SYNC_MAJOR_VERSION = "1";
|
||||
|
@ -20,6 +20,7 @@ import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
|
||||
@ -215,7 +216,9 @@ public class BaseResource implements Resource {
|
||||
private static ClientConnectionManager enableTLSConnectionManager() throws KeyManagementException, NoSuchAlgorithmException {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, null, new SecureRandom());
|
||||
SSLSocketFactory sf = new TLSSocketFactory(sslContext);
|
||||
|
||||
Logger.debug(LOG_TAG, "Using protocols and cipher suites for Android API " + android.os.Build.VERSION.SDK_INT);
|
||||
SSLSocketFactory sf = new SSLSocketFactory(sslContext, GlobalConstants.DEFAULT_PROTOCOLS, GlobalConstants.DEFAULT_CIPHER_SUITES, null);
|
||||
SchemeRegistry schemeRegistry = new SchemeRegistry();
|
||||
schemeRegistry.register(new Scheme("https", 443, sf));
|
||||
schemeRegistry.register(new Scheme("http", 80, new PlainSocketFactory()));
|
||||
|
@ -10,6 +10,7 @@ import java.net.Socket;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
|
||||
import ch.boye.httpclientandroidlib.conn.ssl.SSLSocketFactory;
|
||||
@ -17,18 +18,9 @@ import ch.boye.httpclientandroidlib.params.HttpParams;
|
||||
|
||||
public class TLSSocketFactory extends SSLSocketFactory {
|
||||
private static final String LOG_TAG = "TLSSocketFactory";
|
||||
private static final String[] DEFAULT_CIPHER_SUITES = new String[] {
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"SSL_RSA_WITH_RC4_128_SHA", // "RC4_SHA"
|
||||
};
|
||||
private static final String[] DEFAULT_PROTOCOLS = new String[] {
|
||||
"SSLv3",
|
||||
"TLSv1"
|
||||
};
|
||||
|
||||
// Guarded by `this`.
|
||||
private static String[] cipherSuites = DEFAULT_CIPHER_SUITES;
|
||||
private static String[] cipherSuites = GlobalConstants.DEFAULT_CIPHER_SUITES;
|
||||
|
||||
public TLSSocketFactory(SSLContext sslContext) {
|
||||
super(sslContext);
|
||||
@ -63,7 +55,7 @@ public class TLSSocketFactory extends SSLSocketFactory {
|
||||
@Override
|
||||
public Socket createSocket(HttpParams params) throws IOException {
|
||||
SSLSocket socket = (SSLSocket) super.createSocket(params);
|
||||
socket.setEnabledProtocols(DEFAULT_PROTOCOLS);
|
||||
socket.setEnabledProtocols(GlobalConstants.DEFAULT_PROTOCOLS);
|
||||
setEnabledCipherSuites(socket);
|
||||
return socket;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import org.mozilla.gecko.gfx.LayerView;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.os.SystemClock;
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
@ -133,7 +132,7 @@ class MotionEventHelper {
|
||||
// will trigger the fling.
|
||||
final float dx = (endX - startX) / 2;
|
||||
final float dy = (endY - startY) / 2;
|
||||
float distance = FloatMath.sqrt((dx * dx) + (dy * dy));
|
||||
float distance = (float) Math.sqrt((dx * dx) + (dy * dy));
|
||||
final long time = (long)(distance / velocity);
|
||||
if (time <= 0) {
|
||||
throw new IllegalArgumentException( "Fling parameters require too small a time period" );
|
||||
|
@ -12,18 +12,26 @@ const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}
|
||||
const { AddonWatcher } = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
|
||||
const { PerformanceStats } = Cu.import("resource://gre/modules/PerformanceStats.jsm", {});
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
|
||||
const UPDATE_TOPIC = "about:performance-update-immediately";
|
||||
// about:performance observes notifications on this topic.
|
||||
// if a notification is sent, this causes the page to be updated immediately,
|
||||
// regardless of whether the page is on pause.
|
||||
const UPDATE_IMMEDIATELY_TOPIC = "about:performance-update-immediately";
|
||||
|
||||
// about:performance posts notifications on this topic whenever the page
|
||||
// is updated.
|
||||
const UPDATE_COMPLETE_TOPIC = "about:performance-update-complete";
|
||||
|
||||
/**
|
||||
* The various measures we display.
|
||||
*/
|
||||
const MEASURES = [
|
||||
{key: "longestDuration", percentOfDeltaT: false, label: "Jank level"},
|
||||
{key: "totalUserTime", percentOfDeltaT: true, label: "User (%)"},
|
||||
{key: "totalSystemTime", percentOfDeltaT: true, label: "System (%)"},
|
||||
{key: "totalCPOWTime", percentOfDeltaT: true, label: "Cross-Process (%)"},
|
||||
{key: "ticks", percentOfDeltaT: false, label: "Activations"},
|
||||
{probe: "jank", key: "longestDuration", percentOfDeltaT: false, label: "Jank level"},
|
||||
{probe: "jank", key: "totalUserTime", percentOfDeltaT: true, label: "User (%)"},
|
||||
{probe: "jank", key: "totalSystemTime", percentOfDeltaT: true, label: "System (%)"},
|
||||
{probe: "cpow", key: "totalCPOWTime", percentOfDeltaT: true, label: "Cross-Process (%)"},
|
||||
{probe: "ticks",key: "ticks", percentOfDeltaT: false, label: "Activations"},
|
||||
];
|
||||
|
||||
/**
|
||||
@ -78,6 +86,8 @@ let AutoUpdate = {
|
||||
};
|
||||
|
||||
let State = {
|
||||
_monitor: PerformanceStats.getMonitor(["jank", "cpow", "ticks"]),
|
||||
|
||||
/**
|
||||
* @type{PerformanceData}
|
||||
*/
|
||||
@ -97,29 +107,31 @@ let State = {
|
||||
/**
|
||||
* Fetch the latest information, compute diffs.
|
||||
*
|
||||
* @return {object} An object with the following fields:
|
||||
* @return {Promise}
|
||||
* @resolve An object with the following fields:
|
||||
* - `components`: an array of `PerformanceDiff` representing
|
||||
* the components, sorted by `longestDuration`, then by `totalUserTime`
|
||||
* - `process`: a `PerformanceDiff` representing the entire process;
|
||||
* - `deltaT`: the number of milliseconds elapsed since the data
|
||||
* was last displayed.
|
||||
*/
|
||||
update: function () {
|
||||
let snapshot = PerformanceStats.getSnapshot();
|
||||
update: Task.async(function*() {
|
||||
let snapshot = yield this._monitor.promiseSnapshot();
|
||||
let newData = new Map();
|
||||
let deltas = [];
|
||||
for (let componentNew of snapshot.componentsData) {
|
||||
let {name, addonId, isSystem} = componentNew;
|
||||
let key = JSON.stringify({name, addonId, isSystem});
|
||||
let componentOld = State._componentsData.get(key);
|
||||
deltas.push(componentNew.substract(componentOld));
|
||||
deltas.push(componentNew.subtract(componentOld));
|
||||
newData.set(key, componentNew);
|
||||
}
|
||||
State._componentsData = newData;
|
||||
let now = window.performance.now();
|
||||
let process = snapshot.processData.subtract(State._processData);
|
||||
let result = {
|
||||
components: deltas.filter(x => x.ticks > 0),
|
||||
process: snapshot.processData.substract(State._processData),
|
||||
components: deltas.filter(x => x.ticks.ticks > 0),
|
||||
process: snapshot.processData.subtract(State._processData),
|
||||
deltaT: now - State._date
|
||||
};
|
||||
result.components.sort((a, b) => {
|
||||
@ -134,19 +146,20 @@ let State = {
|
||||
State._processData = snapshot.processData;
|
||||
State._date = now;
|
||||
return result;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
function update() {
|
||||
updateLiveData();
|
||||
updateSlowAddons();
|
||||
}
|
||||
let update = Task.async(function*() {
|
||||
yield updateLiveData();
|
||||
yield updateSlowAddons();
|
||||
Services.obs.notifyObservers(null, UPDATE_COMPLETE_TOPIC, "");
|
||||
});
|
||||
|
||||
/**
|
||||
* Update the list of slow addons
|
||||
*/
|
||||
function updateSlowAddons() {
|
||||
let updateSlowAddons = Task.async(function*() {
|
||||
try {
|
||||
let data = AddonWatcher.alerts;
|
||||
if (data.size == 0) {
|
||||
@ -218,12 +231,12 @@ function updateSlowAddons() {
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Update the table of live data.
|
||||
*/
|
||||
function updateLiveData() {
|
||||
let updateLiveData = Task.async(function*() {
|
||||
try {
|
||||
let dataElt = document.getElementById("liveData");
|
||||
dataElt.innerHTML = "";
|
||||
@ -239,9 +252,9 @@ function updateLiveData() {
|
||||
headerElt.appendChild(el);
|
||||
}
|
||||
|
||||
let deltas = State.update();
|
||||
let deltas = yield State.update();
|
||||
|
||||
for (let item of deltas.components) {
|
||||
for (let item of [deltas.process, ...deltas.components]) {
|
||||
let row = document.createElement("tr");
|
||||
if (item.addonId) {
|
||||
row.classList.add("addon");
|
||||
@ -253,13 +266,14 @@ function updateLiveData() {
|
||||
dataElt.appendChild(row);
|
||||
|
||||
// Measures
|
||||
for (let {key, percentOfDeltaT} of MEASURES) {
|
||||
for (let {probe, key, percentOfDeltaT} of MEASURES) {
|
||||
let el = document.createElement("td");
|
||||
el.classList.add(key);
|
||||
el.classList.add("contents");
|
||||
row.appendChild(el);
|
||||
|
||||
let value = percentOfDeltaT ? Math.round(item[key] / deltas.deltaT) : item[key];
|
||||
let rawValue = item[probe][key];
|
||||
let value = percentOfDeltaT ? Math.round(rawValue / deltas.deltaT) : rawValue;
|
||||
if (key == "longestDuration") {
|
||||
value += 1;
|
||||
el.classList.add("jank" + value);
|
||||
@ -286,19 +300,21 @@ function updateLiveData() {
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function go() {
|
||||
// Compute initial state immediately, then wait a little
|
||||
// before we start computing diffs and refreshing.
|
||||
document.getElementById("playButton").addEventListener("click", () => AutoUpdate.start());
|
||||
document.getElementById("pauseButton").addEventListener("click", () => AutoUpdate.stop());
|
||||
|
||||
document.getElementById("intervalDropdown").addEventListener("change", () => AutoUpdate.updateRefreshRate());
|
||||
|
||||
// Compute initial state immediately, then wait a little
|
||||
// before we start computing diffs and refreshing.
|
||||
State.update();
|
||||
window.setTimeout(update, 500);
|
||||
|
||||
let observer = update;
|
||||
|
||||
Services.obs.addObserver(update, UPDATE_TOPIC, false);
|
||||
window.addEventListener("unload", () => Services.obs.removeObserver(update, UPDATE_TOPIC));
|
||||
Services.obs.addObserver(update, UPDATE_IMMEDIATELY_TOPIC, false);
|
||||
window.addEventListener("unload", () => Services.obs.removeObserver(update, UPDATE_IMMEDIATELY_TOPIC));
|
||||
}
|
||||
|
@ -21,29 +21,33 @@ function frameScript() {
|
||||
});
|
||||
|
||||
addMessageListener("aboutperformance-test:hasItems", ({data: title}) => {
|
||||
Services.obs.notifyObservers(null, "about:performance-update-immediately", "");
|
||||
let hasPlatform = false;
|
||||
let hasTitle = false;
|
||||
let observer = function() {
|
||||
Services.obs.removeObserver(observer, "about:performance-update-complete");
|
||||
let hasPlatform = false;
|
||||
let hasTitle = false;
|
||||
|
||||
try {
|
||||
let eltData = content.document.getElementById("liveData");
|
||||
if (!eltData) {
|
||||
return;
|
||||
try {
|
||||
let eltData = content.document.getElementById("liveData");
|
||||
if (!eltData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find if we have a row for "platform"
|
||||
hasPlatform = eltData.querySelector("tr.platform") != null;
|
||||
|
||||
// Find if we have a row for our content page
|
||||
let titles = [for (eltContent of eltData.querySelectorAll("td.contents.name")) eltContent.textContent];
|
||||
|
||||
hasTitle = titles.includes(title);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content: " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
} finally {
|
||||
sendAsyncMessage("aboutperformance-test:hasItems", {hasPlatform, hasTitle});
|
||||
}
|
||||
|
||||
// Find if we have a row for "platform"
|
||||
hasPlatform = eltData.querySelector("tr.platform") != null;
|
||||
|
||||
// Find if we have a row for our content page
|
||||
let titles = [for (eltContent of eltData.querySelectorAll("td.contents.name")) eltContent.textContent];
|
||||
|
||||
hasTitle = titles.includes(title);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content: " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
} finally {
|
||||
sendAsyncMessage("aboutperformance-test:hasItems", {hasPlatform, hasTitle});
|
||||
}
|
||||
Services.obs.addObserver(observer, "about:performance-update-complete", false);
|
||||
Services.obs.notifyObservers(null, "about:performance-update-immediately", "");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
|
||||
"resource://gre/modules/Preferences.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PerformanceStats",
|
||||
@ -23,7 +25,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
const FILTERS = ["longestDuration", "totalCPOWTime"];
|
||||
const FILTERS = [
|
||||
{probe: "jank", field: "longestDuration"},
|
||||
{probe: "cpow", field: "totalCPOWTime"},
|
||||
];
|
||||
|
||||
let AddonWatcher = {
|
||||
_previousPerformanceIndicators: {},
|
||||
@ -35,6 +40,12 @@ let AddonWatcher = {
|
||||
_stats: new Map(),
|
||||
_timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
|
||||
_callback: null,
|
||||
/**
|
||||
* A performance monitor used to pull data from SpiderMonkey.
|
||||
*
|
||||
* @type {PerformanceStats Monitor}
|
||||
*/
|
||||
_monitor: null,
|
||||
/**
|
||||
* The interval at which we poll the available performance information
|
||||
* to find out about possibly slow add-ons, in milliseconds.
|
||||
@ -103,8 +114,13 @@ let AddonWatcher = {
|
||||
}
|
||||
if (isPaused) {
|
||||
this._timer.cancel();
|
||||
if (this._monitor) {
|
||||
// We don't need the probes anymore, release them.
|
||||
this._monitor.dispose();
|
||||
}
|
||||
this._monitor = null;
|
||||
} else {
|
||||
PerformanceStats.init();
|
||||
this._monitor = PerformanceStats.getMonitor([for (filter of FILTERS) filter.probe]);
|
||||
this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
}
|
||||
this._isPaused = isPaused;
|
||||
@ -123,94 +139,96 @@ let AddonWatcher = {
|
||||
* slice.
|
||||
*/
|
||||
_checkAddons: function() {
|
||||
try {
|
||||
let snapshot = PerformanceStats.getSnapshot();
|
||||
return Task.spawn(function*() {
|
||||
try {
|
||||
let snapshot = yield this._monitor.promiseSnapshot();
|
||||
|
||||
let limits = {
|
||||
// By default, warn if we have a total time of 1s of CPOW per 15 seconds
|
||||
totalCPOWTime: Math.round(Preferences.get("browser.addon-watch.limits.totalCPOWTime", 1000000) * this._interval / 15000),
|
||||
// By default, warn if we have skipped 4 consecutive frames
|
||||
// at least once during the latest slice.
|
||||
longestDuration: Math.round(Math.log2(Preferences.get("browser.addon-watch.limits.longestDuration", 128))),
|
||||
};
|
||||
let limits = {
|
||||
// By default, warn if we have a total time of 1s of CPOW per 15 seconds
|
||||
totalCPOWTime: Math.round(Preferences.get("browser.addon-watch.limits.totalCPOWTime", 1000000) * this._interval / 15000),
|
||||
// By default, warn if we have skipped 4 consecutive frames
|
||||
// at least once during the latest slice.
|
||||
longestDuration: Math.round(Math.log2(Preferences.get("browser.addon-watch.limits.longestDuration", 128))),
|
||||
};
|
||||
|
||||
// By default, warn only after an add-on has been spotted misbehaving 3 times.
|
||||
let tolerance = Preferences.get("browser.addon-watch.tolerance", 3);
|
||||
// By default, warn only after an add-on has been spotted misbehaving 3 times.
|
||||
let tolerance = Preferences.get("browser.addon-watch.tolerance", 3);
|
||||
|
||||
for (let item of snapshot.componentsData) {
|
||||
let addonId = item.addonId;
|
||||
if (!item.isSystem || !addonId) {
|
||||
// We are only interested in add-ons.
|
||||
continue;
|
||||
}
|
||||
if (this._ignoreList.has(addonId)) {
|
||||
// This add-on has been explicitly put in the ignore list
|
||||
// by the user. Don't waste time with it.
|
||||
continue;
|
||||
}
|
||||
let previous = this._previousPerformanceIndicators[addonId];
|
||||
this._previousPerformanceIndicators[addonId] = item;
|
||||
for (let item of snapshot.componentsData) {
|
||||
let addonId = item.addonId;
|
||||
if (!item.isSystem || !addonId) {
|
||||
// We are only interested in add-ons.
|
||||
continue;
|
||||
}
|
||||
if (this._ignoreList.has(addonId)) {
|
||||
// This add-on has been explicitly put in the ignore list
|
||||
// by the user. Don't waste time with it.
|
||||
continue;
|
||||
}
|
||||
let previous = this._previousPerformanceIndicators[addonId];
|
||||
this._previousPerformanceIndicators[addonId] = item;
|
||||
|
||||
if (!previous) {
|
||||
// This is the first time we see the addon, so we are probably
|
||||
// executed right during/after startup. Performance is always
|
||||
// weird during startup, with the JIT warming up, competition
|
||||
// in disk access, etc. so we do not take this as a reason to
|
||||
// display the slow addon warning.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Report misbehaviors to Telemetry
|
||||
|
||||
let diff = item.substract(previous);
|
||||
if (diff.longestDuration > 5) {
|
||||
Telemetry.getKeyedHistogramById("MISBEHAVING_ADDONS_JANK_LEVEL").
|
||||
add(addonId, diff.longestDuration);
|
||||
}
|
||||
if (diff.totalCPOWTime > 0) {
|
||||
Telemetry.getKeyedHistogramById("MISBEHAVING_ADDONS_CPOW_TIME_MS").
|
||||
add(addonId, diff.totalCPOWTime / 1000);
|
||||
}
|
||||
|
||||
// Store misbehaviors for about:performance and other clients
|
||||
|
||||
let stats = this._stats.get(addonId);
|
||||
if (!stats) {
|
||||
stats = {
|
||||
peaks: {},
|
||||
alerts: {},
|
||||
};
|
||||
this._stats.set(addonId, stats);
|
||||
}
|
||||
|
||||
// Report misbehaviors to the user.
|
||||
|
||||
for (let filter of FILTERS) {
|
||||
let peak = stats.peaks[filter] || 0;
|
||||
stats.peaks[filter] = Math.max(diff[filter], peak);
|
||||
|
||||
if (limits[filter] <= 0 || diff[filter] <= limits[filter]) {
|
||||
if (!previous) {
|
||||
// This is the first time we see the addon, so we are probably
|
||||
// executed right during/after startup. Performance is always
|
||||
// weird during startup, with the JIT warming up, competition
|
||||
// in disk access, etc. so we do not take this as a reason to
|
||||
// display the slow addon warning.
|
||||
continue;
|
||||
}
|
||||
|
||||
stats.alerts[filter] = (stats.alerts[filter] || 0) + 1;
|
||||
// Report misbehaviors to Telemetry
|
||||
|
||||
if (stats.alerts[filter] % tolerance != 0) {
|
||||
continue;
|
||||
let diff = item.subtract(previous);
|
||||
if ("jank" in diff && diff.jank.longestDuration > 5) {
|
||||
Telemetry.getKeyedHistogramById("MISBEHAVING_ADDONS_JANK_LEVEL").
|
||||
add(addonId, diff.jank.longestDuration);
|
||||
}
|
||||
if ("cpow" in diff && diff.cpow.totalCPOWTime > 0) {
|
||||
Telemetry.getKeyedHistogramById("MISBEHAVING_ADDONS_CPOW_TIME_MS").
|
||||
add(addonId, diff.cpow.totalCPOWTime / 1000);
|
||||
}
|
||||
|
||||
try {
|
||||
this._callback(addonId, filter);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in AddonWatcher._checkAddons callback " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
// Store misbehaviors for about:performance and other clients
|
||||
let stats = this._stats.get(addonId);
|
||||
if (!stats) {
|
||||
stats = {
|
||||
peaks: {},
|
||||
alerts: {},
|
||||
};
|
||||
this._stats.set(addonId, stats);
|
||||
}
|
||||
|
||||
// Report misbehaviors to the user.
|
||||
|
||||
for (let {probe, field: filter} of FILTERS) {
|
||||
let peak = stats.peaks[filter] || 0;
|
||||
let value = diff[probe][filter];
|
||||
stats.peaks[filter] = Math.max(value, peak);
|
||||
|
||||
if (limits[filter] <= 0 || value <= limits[filter]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stats.alerts[filter] = (stats.alerts[filter] || 0) + 1;
|
||||
|
||||
if (stats.alerts[filter] % tolerance != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
this._callback(addonId, filter);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in AddonWatcher._checkAddons callback " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in AddonWatcher._checkAddons " + ex);
|
||||
Cu.reportError(Task.Debugging.generateReadableStack(ex.stack));
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in AddonWatcher._checkAddons " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
ignoreAddonForSession: function(addonid) {
|
||||
this._ignoreList.add(addonid);
|
||||
|
@ -12,29 +12,425 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
/**
|
||||
* API for querying and examining performance data.
|
||||
*
|
||||
* The data exposed by this API is computed internally by the JavaScript VM.
|
||||
* See `PerformanceData` for the detail of the information provided by this
|
||||
* API.
|
||||
* This API exposes data from several probes implemented by the JavaScript VM.
|
||||
* See `PerformanceStats.getMonitor()` for information on how to monitor data
|
||||
* from one or more probes and `PerformanceData` for the information obtained
|
||||
* from the probes.
|
||||
*
|
||||
* Data is collected by "Performance Group". Typically, a Performance Group
|
||||
* is an add-on, or a frame, or the internals of the application.
|
||||
*/
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
let performanceStatsService =
|
||||
Cc["@mozilla.org/toolkit/performance-stats-service;1"].
|
||||
getService(Ci.nsIPerformanceStatsService);
|
||||
// The nsIPerformanceStatsService provides lower-level
|
||||
// access to SpiderMonkey and the probes.
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "performanceStatsService",
|
||||
"@mozilla.org/toolkit/performance-stats-service;1",
|
||||
Ci.nsIPerformanceStatsService);
|
||||
|
||||
// The finalizer lets us automatically release (and when possible deactivate)
|
||||
// probes when a monitor is garbage-collected.
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "finalizer",
|
||||
"@mozilla.org/toolkit/finalizationwitness;1",
|
||||
Ci.nsIFinalizationWitnessService
|
||||
);
|
||||
|
||||
|
||||
const PROPERTIES_NUMBERED = ["totalUserTime", "totalSystemTime", "totalCPOWTime", "ticks"];
|
||||
// The topic used to notify that a PerformanceMonitor has been garbage-collected
|
||||
// and that we can release/close the probes it holds.
|
||||
const FINALIZATION_TOPIC = "performancemonitor-finalize";
|
||||
|
||||
const PROPERTIES_META_IMMUTABLE = ["name", "addonId", "isSystem"];
|
||||
const PROPERTIES_META = [...PROPERTIES_META_IMMUTABLE, "windowId", "title"];
|
||||
const PROPERTIES_FLAT = [...PROPERTIES_NUMBERED, ...PROPERTIES_META];
|
||||
|
||||
/**
|
||||
* Information on a single component.
|
||||
* Access to a low-level performance probe.
|
||||
*
|
||||
* Each probe is dedicated to some form of performance monitoring.
|
||||
* As each probe may have a performance impact, a probe is activated
|
||||
* only when a client has requested a PerformanceMonitor for this probe,
|
||||
* and deactivated once all clients are disposed of.
|
||||
*/
|
||||
function Probe(name, impl) {
|
||||
this._name = name;
|
||||
this._counter = 0;
|
||||
this._impl = impl;
|
||||
}
|
||||
Probe.prototype = {
|
||||
/**
|
||||
* Acquire the probe on behalf of a client.
|
||||
*
|
||||
* If the probe was inactive, activate it. Note that activating a probe
|
||||
* can incur a memory or performance cost.
|
||||
*/
|
||||
acquire: function() {
|
||||
if (this._counter == 0) {
|
||||
this._impl.isActive = true;
|
||||
}
|
||||
this._counter++;
|
||||
},
|
||||
|
||||
/**
|
||||
* Release the probe on behalf of a client.
|
||||
*
|
||||
* If this was the last client for this probe, deactivate it.
|
||||
*/
|
||||
release: function() {
|
||||
this._counter--;
|
||||
if (this._counter == 0) {
|
||||
this._impl.isActive = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Obtain data from this probe, once it is available.
|
||||
*
|
||||
* @param {nsIPerformanceStats} xpcom A xpcom object obtained from
|
||||
* SpiderMonkey. Only the fields updated by the low-level probe
|
||||
* are in a specified state.
|
||||
* @return {object} An object containing the data extracted from this
|
||||
* probe. Actual format depends on the probe.
|
||||
*/
|
||||
extract: function(xpcom) {
|
||||
if (!this._impl.isActive) {
|
||||
throw new Error(`Probe is inactive: ${this._name}`);
|
||||
}
|
||||
return this._impl.extract(xpcom);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} a An object returned by `this.extract()`.
|
||||
* @param {object} b An object returned by `this.extract()`.
|
||||
*
|
||||
* @return {true} If `a` and `b` hold identical values.
|
||||
*/
|
||||
isEqual: function(a, b) {
|
||||
if (a == null && b == null) {
|
||||
return true;
|
||||
}
|
||||
if (a != null && b != null) {
|
||||
return this._impl.isEqual(a, b);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} a An object returned by `this.extract()`. May
|
||||
* NOT be `null`.
|
||||
* @param {object} b An object returned by `this.extract()`. May
|
||||
* be `null`.
|
||||
*
|
||||
* @return {object} An object representing `a - b`. If `b` is
|
||||
* `null`, this is `a`.
|
||||
*/
|
||||
substract: function(a, b) {
|
||||
if (a == null) {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return this._impl.substract(a, b);
|
||||
},
|
||||
|
||||
/**
|
||||
* The name of the probe.
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
};
|
||||
|
||||
// Utility function. Return the position of the last non-0 item in an
|
||||
// array, or -1 if there isn't any such item.
|
||||
function lastNonZero(array) {
|
||||
for (let i = array.length - 1; i >= 0; --i) {
|
||||
if (array[i] != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual Probes implemented by SpiderMonkey.
|
||||
*/
|
||||
let Probes = {
|
||||
/**
|
||||
* A probe measuring jank.
|
||||
*
|
||||
* Data provided by this probe uses the following format:
|
||||
*
|
||||
* @field {number} totalCPUTime The total amount of time spent using the
|
||||
* CPU for this performance group, in µs.
|
||||
* @field {number} totalSystemTime The total amount of time spent in the
|
||||
* kernel for this performance group, in µs.
|
||||
* @field {Array<number>} durations An array containing at each position `i`
|
||||
* the number of times execution of this component has lasted at least `2^i`
|
||||
* milliseconds.
|
||||
* @field {number} longestDuration The index of the highest non-0 value in
|
||||
* `durations`.
|
||||
*/
|
||||
jank: new Probe("jank", {
|
||||
set isActive(x) { /* always active in the current implementation */ },
|
||||
get isActive() { return true; },
|
||||
extract: function(xpcom) {
|
||||
let durations = xpcom.getDurations();
|
||||
return {
|
||||
totalUserTime: xpcom.totalUserTime,
|
||||
totalSystemTime: xpcom.totalSystemTime,
|
||||
durations: durations,
|
||||
longestDuration: lastNonZero(durations)
|
||||
}
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
// invariant: `a` and `b` are both non-null
|
||||
if (a.totalUserTime != b.totalUserTime) {
|
||||
return false;
|
||||
}
|
||||
if (a.totalSystemTime != b.totalSystemTime) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.durations.length; ++i) {
|
||||
if (a.durations[i] != b.durations[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
substract: function(a, b) {
|
||||
// invariant: `a` and `b` are both non-null
|
||||
let result = {
|
||||
totalUserTime: a.totalUserTime - b.totalUserTime,
|
||||
totalSystemTime: a.totalSystemTime - b.totalSystemTime,
|
||||
durations: [],
|
||||
longestDuration: -1,
|
||||
};
|
||||
for (let i = 0; i < a.durations.length; ++i) {
|
||||
result.durations[i] = a.durations[i] - b.durations[i];
|
||||
}
|
||||
result.longestDuration = lastNonZero(result.durations);
|
||||
return result;
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* A probe measuring CPOW activity.
|
||||
*
|
||||
* Data provided by this probe uses the following format:
|
||||
*
|
||||
* @field {number} totalCPOWTime The amount of wallclock time
|
||||
* spent executing blocking cross-process calls, in µs.
|
||||
*/
|
||||
cpow: new Probe("cpow", {
|
||||
set isActive(x) { /* always active in the current implementation */ },
|
||||
get isActive() { return true; },
|
||||
extract: function(xpcom) {
|
||||
return {
|
||||
totalCPOWTime: xpcom.totalCPOWTime
|
||||
};
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
return a.totalCPOWTime == b.totalCPOWTime;
|
||||
},
|
||||
substract: function(a, b) {
|
||||
return {
|
||||
totalCPOWTime: a.totalCPOWTime - b.totalCPOWTime
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* A probe measuring activations, i.e. the number
|
||||
* of times code execution has entered a given
|
||||
* PerformanceGroup.
|
||||
*
|
||||
* Note that this probe is always active.
|
||||
*
|
||||
* Data provided by this probe uses the following format:
|
||||
* @type {number} ticks The number of times execution has entered
|
||||
* this performance group.
|
||||
*/
|
||||
ticks: new Probe("ticks", {
|
||||
set isActive(x) { /* this probe cannot be deactivated */ },
|
||||
get isActive() { return true; },
|
||||
extract: function(xpcom) {
|
||||
return {
|
||||
ticks: xpcom.ticks
|
||||
};
|
||||
},
|
||||
isEqual: function(a, b) {
|
||||
return a.ticks == b.ticks;
|
||||
},
|
||||
substract: function(a, b) {
|
||||
return {
|
||||
ticks: a.ticks - b.ticks
|
||||
};
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A monitor for a set of probes.
|
||||
*
|
||||
* Keeping probes active when they are unused is often a bad
|
||||
* idea for performance reasons. Upon destruction, or whenever
|
||||
* a client calls `dispose`, this monitor releases the probes,
|
||||
* which may let the system deactivate them.
|
||||
*/
|
||||
function PerformanceMonitor(probes) {
|
||||
this._probes = probes;
|
||||
|
||||
// Activate low-level features as needed
|
||||
for (let probe of probes) {
|
||||
probe.acquire();
|
||||
}
|
||||
|
||||
// A finalization witness. At some point after the garbage-collection of
|
||||
// `this` object, a notification of `FINALIZATION_TOPIC` will be triggered
|
||||
// with `id` as message.
|
||||
this._id = PerformanceMonitor.makeId();
|
||||
this._finalizer = finalizer.make(FINALIZATION_TOPIC, this._id)
|
||||
PerformanceMonitor._monitors.set(this._id, probes);
|
||||
}
|
||||
PerformanceMonitor.prototype = {
|
||||
/**
|
||||
* Return asynchronously a snapshot with the data
|
||||
* for each probe monitored by this PerformanceMonitor.
|
||||
*
|
||||
* All numeric values are non-negative and can only increase. Depending on
|
||||
* the probe and the underlying operating system, probes may not be available
|
||||
* immediately and may miss some activity.
|
||||
*
|
||||
* Clients should NOT expect that the first call to `promiseSnapshot()`
|
||||
* will return a `Snapshot` in which all values are 0. For most uses,
|
||||
* the appropriate scenario is to perform a first call to `promiseSnapshot()`
|
||||
* to obtain a baseline, and then watch evolution of the values by calling
|
||||
* `promiseSnapshot()` and `substract()`.
|
||||
*
|
||||
* On the other hand, numeric values are also monotonic across several instances
|
||||
* of a PerformanceMonitor with the same probes.
|
||||
* let a = PerformanceStats.getMonitor(someProbes);
|
||||
* let snapshot1 = yield a.promiseSnapshot();
|
||||
*
|
||||
* // ...
|
||||
* let b = PerformanceStats.getMonitor(someProbes); // Same list of probes
|
||||
* let snapshot2 = yield b.promiseSnapshot();
|
||||
*
|
||||
* // all values of `snapshot2` are greater or equal to values of `snapshot1`.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolve {Snapshot}
|
||||
*/
|
||||
promiseSnapshot: function() {
|
||||
if (!this._finalizer) {
|
||||
throw new Error("dispose() has already been called, this PerformanceMonitor is not usable anymore");
|
||||
}
|
||||
// Current implementation is actually synchronous.
|
||||
return Promise.resolve().then(() => new Snapshot({
|
||||
xpcom: performanceStatsService.getSnapshot(),
|
||||
probes: this._probes
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Release the probes used by this monitor.
|
||||
*
|
||||
* Releasing probes as soon as they are unused is a good idea, as some probes
|
||||
* cost CPU and/or memory.
|
||||
*/
|
||||
dispose: function() {
|
||||
if (!this._finalizer) {
|
||||
return;
|
||||
}
|
||||
this._finalizer.forget();
|
||||
PerformanceMonitor.dispose(this._id);
|
||||
|
||||
// As a safeguard against double-release, reset everything to `null`
|
||||
this._probes = null;
|
||||
this._id = null;
|
||||
this._finalizer = null;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @type {Map<string, Array<string>>} A map from id (as produced by `makeId`)
|
||||
* to list of probes. Used to deallocate a list of probes during finalization.
|
||||
*/
|
||||
PerformanceMonitor._monitors = new Map();
|
||||
|
||||
/**
|
||||
* Create a `PerformanceMonitor` for a list of probes, register it for
|
||||
* finalization.
|
||||
*/
|
||||
PerformanceMonitor.make = function(probeNames) {
|
||||
// Sanity checks
|
||||
if (!Array.isArray(probeNames)) {
|
||||
throw new TypeError("Expected an array, got " + probes);
|
||||
}
|
||||
let probes = [];
|
||||
for (let probeName of probeNames) {
|
||||
if (!(probeName in Probes)) {
|
||||
throw new TypeError("Probe not implemented: " + k);
|
||||
}
|
||||
probes.push(Probes[probeName]);
|
||||
}
|
||||
|
||||
return new PerformanceMonitor(probes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of `dispose`.
|
||||
*
|
||||
* The actual implementation of `dispose` is as a method of `PerformanceMonitor`,
|
||||
* rather than `PerformanceMonitor.prototype`, to avoid needing a strong reference
|
||||
* to instances of `PerformanceMonitor`, which would defeat the purpose of
|
||||
* finalization.
|
||||
*/
|
||||
PerformanceMonitor.dispose = function(id) {
|
||||
let probes = PerformanceMonitor._monitors.get(id);
|
||||
if (!probes) {
|
||||
throw new TypeError("`dispose()` has already been called on this monitor");
|
||||
}
|
||||
|
||||
PerformanceMonitor._monitors.delete(id);
|
||||
for (let probe of probes) {
|
||||
probe.release();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a unique id for each PerformanceMonitor. Used during
|
||||
// finalization.
|
||||
PerformanceMonitor._counter = 0;
|
||||
PerformanceMonitor.makeId = function() {
|
||||
return "PerformanceMonitor-" + (this._counter++);
|
||||
}
|
||||
|
||||
// Once a `PerformanceMonitor` has been garbage-collected,
|
||||
// release the probes unless `dispose()` has already been called.
|
||||
Services.obs.addObserver(function(subject, topic, value) {
|
||||
PerformanceMonitor.dispose(value);
|
||||
}, FINALIZATION_TOPIC, false);
|
||||
|
||||
// Public API
|
||||
this.PerformanceStats = {
|
||||
/**
|
||||
* Create a monitor for observing a set of performance probes.
|
||||
*/
|
||||
getMonitor: function(probes) {
|
||||
return PerformanceMonitor.make(probes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Information on a single performance group.
|
||||
*
|
||||
* This offers the following fields:
|
||||
*
|
||||
* @field {string} name The name of the component:
|
||||
* @field {string} name The name of the performance group:
|
||||
* - for the process itself, "<process>";
|
||||
* - for platform code, "<platform>";
|
||||
* - for an add-on, the identifier of the addon (e.g. "myaddon@foo.bar");
|
||||
@ -54,28 +450,22 @@ const PROPERTIES_FLAT = [...PROPERTIES_NUMBERED, ...PROPERTIES_META];
|
||||
* @field {boolean} isSystem `true` if the component is a system component (i.e.
|
||||
* an add-on or platform-code), `false` otherwise (i.e. a webpage).
|
||||
*
|
||||
* @field {number} totalUserTime The total amount of time spent executing code.
|
||||
* @field {object|undefined} activations See the documentation of probe "ticks".
|
||||
* `undefined` if this probe is not active.
|
||||
*
|
||||
* @field {number} totalSystemTime The total amount of time spent executing
|
||||
* system calls.
|
||||
* @field {object|undefined} jank See the documentation of probe "jank".
|
||||
* `undefined` if this probe is not active.
|
||||
*
|
||||
* @field {number} totalCPOWTime The total amount of time spent waiting for
|
||||
* blocking cross-process communications
|
||||
*
|
||||
* @field {number} ticks The number of times the JavaScript VM entered the code
|
||||
* of this component to execute it.
|
||||
*
|
||||
* @field {Array<number>} durations An array containing at each position `i`
|
||||
* the number of times execution of this component has lasted at least `2^i`
|
||||
* milliseconds.
|
||||
*
|
||||
* All numeric values are non-negative and can only increase.
|
||||
* @field {object|undefined} cpow See the documentation of probe "cpow".
|
||||
* `undefined` if this probe is not active.
|
||||
*/
|
||||
function PerformanceData(xpcom) {
|
||||
for (let k of PROPERTIES_FLAT) {
|
||||
function PerformanceData({xpcom, probes}) {
|
||||
for (let k of PROPERTIES_META) {
|
||||
this[k] = xpcom[k];
|
||||
}
|
||||
this.durations = xpcom.getDurations();
|
||||
for (let probe of probes) {
|
||||
this[probe.name] = probe.extract(xpcom);
|
||||
}
|
||||
}
|
||||
PerformanceData.prototype = {
|
||||
/**
|
||||
@ -87,17 +477,12 @@ PerformanceData.prototype = {
|
||||
if (!(to instanceof PerformanceData)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
for (let k of PROPERTIES_FLAT) {
|
||||
if (this[k] != to[k]) {
|
||||
for (let probeName of Object.keys(Probes)) {
|
||||
let probe = Probes[probeName];
|
||||
if (!probe.isEqual(this[probeName], to[probeName])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.durations.length; ++i) {
|
||||
if (to.durations[i] != this.durations[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -108,7 +493,7 @@ PerformanceData.prototype = {
|
||||
*
|
||||
* @return {PerformanceDiff} The performance usage between `to` and `this`.
|
||||
*/
|
||||
substract: function(to = null) {
|
||||
subtract: function(to = null) {
|
||||
return new PerformanceDiff(this, to);
|
||||
}
|
||||
};
|
||||
@ -117,57 +502,16 @@ PerformanceData.prototype = {
|
||||
* The delta between two instances of `PerformanceData`.
|
||||
*
|
||||
* Used to monitor resource usage between two timestamps.
|
||||
*
|
||||
* @field {number} longestDuration An indication of the longest
|
||||
* execution duration between two timestamps:
|
||||
* - -1 == less than 1ms
|
||||
* - 0 == [1, 2[ ms
|
||||
* - 1 == [2, 4[ ms
|
||||
* - 3 == [4, 8[ ms
|
||||
* - 4 == [8, 16[ ms
|
||||
* - ...
|
||||
* - 7 == [128, ...] ms
|
||||
*/
|
||||
function PerformanceDiff(current, old = null) {
|
||||
for (let k of PROPERTIES_META) {
|
||||
this[k] = current[k];
|
||||
}
|
||||
|
||||
if (old) {
|
||||
if (!(old instanceof PerformanceData)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (current.durations.length != old.durations.length) {
|
||||
throw new TypeError("Internal error: mismatched length for `durations`.");
|
||||
}
|
||||
|
||||
this.durations = [];
|
||||
|
||||
this.longestDuration = -1;
|
||||
|
||||
for (let i = 0; i < current.durations.length; ++i) {
|
||||
let delta = current.durations[i] - old.durations[i];
|
||||
this.durations[i] = delta;
|
||||
if (delta > 0) {
|
||||
this.longestDuration = i;
|
||||
}
|
||||
}
|
||||
for (let k of PROPERTIES_NUMBERED) {
|
||||
this[k] = current[k] - old[k];
|
||||
}
|
||||
} else {
|
||||
this.durations = current.durations.slice(0);
|
||||
|
||||
for (let k of PROPERTIES_NUMBERED) {
|
||||
this[k] = current[k];
|
||||
}
|
||||
|
||||
this.longestDuration = -1;
|
||||
for (let i = this.durations.length - 1; i >= 0; --i) {
|
||||
if (this.durations[i] > 0) {
|
||||
this.longestDuration = i;
|
||||
break;
|
||||
}
|
||||
for (let probeName of Object.keys(Probes)) {
|
||||
let other = old ? old[probeName] : null;
|
||||
if (probeName in current) {
|
||||
this[probeName] = Probes[probeName].substract(current[probeName], other);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,41 +519,16 @@ function PerformanceDiff(current, old = null) {
|
||||
/**
|
||||
* A snapshot of the performance usage of the process.
|
||||
*/
|
||||
function Snapshot(xpcom) {
|
||||
function Snapshot({xpcom, probes}) {
|
||||
this.componentsData = [];
|
||||
let enumeration = xpcom.getComponentsData().enumerate();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
let stat = enumeration.getNext().QueryInterface(Ci.nsIPerformanceStats);
|
||||
this.componentsData.push(new PerformanceData(stat));
|
||||
this.componentsData.push(new PerformanceData({xpcom: stat, probes}));
|
||||
}
|
||||
this.processData = new PerformanceData(xpcom.getProcessData());
|
||||
this.processData = new PerformanceData({xpcom: xpcom.getProcessData(), probes});
|
||||
}
|
||||
|
||||
|
||||
this.PerformanceStats = {
|
||||
/**
|
||||
* Activate monitoring.
|
||||
*/
|
||||
init() {
|
||||
//
|
||||
// The implementation actually does nothing, as monitoring is
|
||||
// initiated when loading the module.
|
||||
//
|
||||
// This function is actually provided as a gentle way to ensure
|
||||
// that client code that imports `PerformanceStats` lazily
|
||||
// does not forget to force the import, hence triggering
|
||||
// actual load of the module.
|
||||
//
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a snapshot of the performance usage of the current process.
|
||||
*
|
||||
* @type {Snapshot}
|
||||
*/
|
||||
getSnapshot() {
|
||||
return new Snapshot(performanceStatsService.getSnapshot());
|
||||
},
|
||||
};
|
||||
|
||||
// In the current implementation, all probes are always active.
|
||||
performanceStatsService.isStopwatchActive = true;
|
||||
|
@ -29,9 +29,13 @@ function frameScript() {
|
||||
// Make sure that the stopwatch is now active.
|
||||
performanceStatsService.isStopwatchActive = true;
|
||||
|
||||
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
|
||||
|
||||
addMessageListener("compartments-test:getStatistics", () => {
|
||||
try {
|
||||
sendAsyncMessage("compartments-test:getStatistics", PerformanceStats.getSnapshot());
|
||||
monitor.promiseSnapshot().then(snapshot => {
|
||||
sendAsyncMessage("compartments-test:getStatistics", snapshot);
|
||||
});
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content: " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
@ -99,20 +103,25 @@ function monotinicity_tester(source, testName) {
|
||||
for (let k of ["name", "addonId", "isSystem"]) {
|
||||
SilentAssert.equal(prev[k], next[k], `Sanity check (${testName}): ${k} hasn't changed.`);
|
||||
}
|
||||
for (let k of ["totalUserTime", "totalSystemTime", "totalCPOWTime", "ticks"]) {
|
||||
SilentAssert.equal(typeof next[k], "number", `Sanity check (${testName}): ${k} is a number.`);
|
||||
SilentAssert.leq(prev[k], next[k], `Sanity check (${testName}): ${k} is monotonic.`);
|
||||
SilentAssert.leq(0, next[k], `Sanity check (${testName}): ${k} is >= 0.`)
|
||||
for (let [probe, k] of [
|
||||
["jank", "totalUserTime"],
|
||||
["jank", "totalSystemTime"],
|
||||
["cpow", "totalCPOWTime"],
|
||||
["ticks", "ticks"]
|
||||
]) {
|
||||
SilentAssert.equal(typeof next[probe][k], "number", `Sanity check (${testName}): ${k} is a number.`);
|
||||
SilentAssert.leq(prev[probe][k], next[probe][k], `Sanity check (${testName}): ${k} is monotonic.`);
|
||||
SilentAssert.leq(0, next[probe][k], `Sanity check (${testName}): ${k} is >= 0.`)
|
||||
}
|
||||
SilentAssert.equal(prev.durations.length, next.durations.length);
|
||||
for (let i = 0; i < next.durations.length; ++i) {
|
||||
SilentAssert.ok(typeof next.durations[i] == "number" && next.durations[i] >= 0,
|
||||
SilentAssert.equal(prev.jank.durations.length, next.jank.durations.length);
|
||||
for (let i = 0; i < next.jank.durations.length; ++i) {
|
||||
SilentAssert.ok(typeof next.jank.durations[i] == "number" && next.jank.durations[i] >= 0,
|
||||
`Sanity check (${testName}): durations[${i}] is a non-negative number.`);
|
||||
SilentAssert.leq(prev.durations[i], next.durations[i],
|
||||
`Sanity check (${testName}): durations[${i}] is monotonic.`)
|
||||
SilentAssert.leq(prev.jank.durations[i], next.jank.durations[i],
|
||||
`Sanity check (${testName}): durations[${i}] is monotonic.`);
|
||||
}
|
||||
for (let i = 0; i < next.durations.length - 1; ++i) {
|
||||
SilentAssert.leq(next.durations[i + 1], next.durations[i],
|
||||
for (let i = 0; i < next.jank.durations.length - 1; ++i) {
|
||||
SilentAssert.leq(next.jank.durations[i + 1], next.jank.durations[i],
|
||||
`Sanity check (${testName}): durations[${i}] >= durations[${i + 1}].`)
|
||||
}
|
||||
};
|
||||
@ -138,8 +147,12 @@ function monotinicity_tester(source, testName) {
|
||||
let set = new Set();
|
||||
let map = new Map();
|
||||
for (let item of snapshot.componentsData) {
|
||||
for (let k of ["totalUserTime", "totalSystemTime", "totalCPOWTime"]) {
|
||||
SilentAssert.leq(item[k], snapshot.processData[k],
|
||||
for (let [probe, k] of [
|
||||
["jank", "totalUserTime"],
|
||||
["jank", "totalSystemTime"],
|
||||
["cpow", "totalCPOWTime"]
|
||||
]) {
|
||||
SilentAssert.leq(item[probe][k], snapshot.processData[probe][k],
|
||||
`Sanity check (${testName}): component has a lower ${k} than process`);
|
||||
}
|
||||
|
||||
@ -170,8 +183,10 @@ function monotinicity_tester(source, testName) {
|
||||
}
|
||||
|
||||
add_task(function* test() {
|
||||
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
|
||||
|
||||
info("Extracting initial state");
|
||||
let stats0 = PerformanceStats.getSnapshot();
|
||||
let stats0 = yield monitor.promiseSnapshot();
|
||||
Assert.notEqual(stats0.componentsData.length, 0, "There is more than one component");
|
||||
Assert.ok(!stats0.componentsData.find(stat => stat.name.indexOf(URL) != -1),
|
||||
"The url doesn't appear yet");
|
||||
@ -189,7 +204,7 @@ add_task(function* test() {
|
||||
info("Deactivating sanity checks under Windows (bug 1151240)");
|
||||
} else {
|
||||
info("Setting up sanity checks");
|
||||
monotinicity_tester(() => PerformanceStats.getSnapshot(), "parent process");
|
||||
monotinicity_tester(() => monitor.promiseSnapshot(), "parent process");
|
||||
monotinicity_tester(() => promiseContentResponseOrNull(browser, "compartments-test:getStatistics", null), "content process" );
|
||||
}
|
||||
|
||||
@ -230,11 +245,11 @@ add_task(function* test() {
|
||||
info("Searching by title, we didn't find the main frame");
|
||||
continue;
|
||||
}
|
||||
info("Searching by title, we found the main frame");
|
||||
|
||||
info(`Total user time: ${parent.totalUserTime}`);
|
||||
if (skipTotalUserTime || parent.totalUserTime > 1000) {
|
||||
if (skipTotalUserTime || parent.jank.totalUserTime > 1000) {
|
||||
break;
|
||||
} else {
|
||||
info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,12 @@ function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
let monitor = PerformanceStats.getMonitor(["ticks", "jank", "cpow"]);
|
||||
|
||||
let promiseStatistics = Task.async(function*(name) {
|
||||
yield Promise.resolve(); // Make sure that we wait until
|
||||
// statistics have been updated.
|
||||
let snapshot = PerformanceStats.getSnapshot();
|
||||
do_print("Statistics: " + name);
|
||||
do_print(JSON.stringify(snapshot.processData, null, "\t"));
|
||||
do_print(JSON.stringify(snapshot.componentsData, null, "\t"));
|
||||
return snapshot;
|
||||
return monitor.promiseSnapshot();
|
||||
});
|
||||
|
||||
let promiseSetMonitoring = Task.async(function*(to) {
|
||||
@ -105,13 +103,13 @@ add_task(function* test_measure() {
|
||||
if (skipPrecisionTests) {
|
||||
do_print("Skipping totalUserTime check under Windows XP, as timer is not always updated by the OS.")
|
||||
} else {
|
||||
Assert.ok(process2.totalUserTime - process1.totalUserTime >= 10000, `At least 10ms counted for process time (${process2.totalUserTime - process1.totalUserTime})`);
|
||||
Assert.ok(process2.jank.totalUserTime - process1.jank.totalUserTime >= 10000, `At least 10ms counted for process time (${process2.jank.totalUserTime - process1.jank.totalUserTime})`);
|
||||
}
|
||||
Assert.equal(process2.totalCPOWTime, process1.totalCPOWTime, "We haven't used any CPOW time during the first burn");
|
||||
Assert.equal(process4.totalUserTime, process3.totalUserTime, "After deactivating the stopwatch, we didn't count any time");
|
||||
Assert.equal(process4.totalCPOWTime, process3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time");
|
||||
Assert.equal(process2.jank.totalCPOWTime, process1.jank.totalCPOWTime, "We haven't used any CPOW time during the first burn");
|
||||
Assert.equal(process4.jank.totalUserTime, process3.jank.totalUserTime, "After deactivating the stopwatch, we didn't count any time");
|
||||
Assert.equal(process4.jank.totalCPOWTime, process3.jank.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time");
|
||||
|
||||
let builtin1 = getBuiltinStatistics(stats1) || { totalUserTime: 0, totalCPOWTime: 0 };
|
||||
let builtin1 = getBuiltinStatistics(stats1) || { jank: { totalUserTime: 0 }, cpow: { totalCPOWTime: 0 } };
|
||||
let builtin2 = getBuiltinStatistics(stats2);
|
||||
let builtin3 = getBuiltinStatistics(stats3);
|
||||
let builtin4 = getBuiltinStatistics(stats4);
|
||||
@ -122,10 +120,10 @@ add_task(function* test_measure() {
|
||||
if (skipPrecisionTests) {
|
||||
do_print("Skipping totalUserTime check under Windows XP, as timer is not always updated by the OS.")
|
||||
} else {
|
||||
Assert.ok(builtin2.totalUserTime - builtin1.totalUserTime >= 10000, `At least 10ms counted for built-in statistics (${builtin2.totalUserTime - builtin1.totalUserTime})`);
|
||||
Assert.ok(builtin2.jank.totalUserTime - builtin1.jank.totalUserTime >= 10000, `At least 10ms counted for built-in statistics (${builtin2.jank.totalUserTime - builtin1.jank.totalUserTime})`);
|
||||
}
|
||||
Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "We haven't used any CPOW time during the first burn for the built-in");
|
||||
Assert.equal(builtin2.totalCPOWTime, builtin1.totalCPOWTime, "No CPOW for built-in statistics");
|
||||
Assert.equal(builtin4.totalUserTime, builtin3.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
|
||||
Assert.equal(builtin4.totalCPOWTime, builtin3.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
|
||||
Assert.equal(builtin2.jank.totalCPOWTime, builtin1.jank.totalCPOWTime, "We haven't used any CPOW time during the first burn for the built-in");
|
||||
Assert.equal(builtin2.jank.totalCPOWTime, builtin1.jank.totalCPOWTime, "No CPOW for built-in statistics");
|
||||
Assert.equal(builtin4.jank.totalUserTime, builtin3.jank.totalUserTime, "After deactivating the stopwatch, we didn't count any time for the built-in");
|
||||
Assert.equal(builtin4.jank.totalCPOWTime, builtin3.jank.totalCPOWTime, "After deactivating the stopwatch, we didn't count any CPOW time for the built-in");
|
||||
});
|
||||
|
@ -461,7 +461,7 @@ let Impl = {
|
||||
creationDate: (Policy.now()).toISOString(),
|
||||
version: PING_FORMAT_VERSION,
|
||||
application: this._getApplicationSection(),
|
||||
payload: aPayload,
|
||||
payload: payload,
|
||||
};
|
||||
|
||||
if (aOptions.addClientId) {
|
||||
|
@ -19,6 +19,7 @@ const protocol = require("devtools/server/protocol");
|
||||
const {Arg, Option, method, RetVal, types} = protocol;
|
||||
const {LongStringActor, ShortLongString} = require("devtools/server/actors/string");
|
||||
const {fetch} = require("devtools/toolkit/DevToolsUtils");
|
||||
const {listenOnce} = require("devtools/async-utils");
|
||||
|
||||
loader.lazyGetter(this, "CssLogic", () => require("devtools/styleinspector/css-logic").CssLogic);
|
||||
|
||||
@ -75,56 +76,29 @@ let StyleSheetsActor = exports.StyleSheetsActor = protocol.ActorClass({
|
||||
* Protocol method for getting a list of StyleSheetActors representing
|
||||
* all the style sheets in this document.
|
||||
*/
|
||||
getStyleSheets: method(function() {
|
||||
let deferred = promise.defer();
|
||||
getStyleSheets: method(Task.async(function* () {
|
||||
let documents = [this.document];
|
||||
let actors = [];
|
||||
|
||||
let window = this.window;
|
||||
var domReady = () => {
|
||||
window.removeEventListener("DOMContentLoaded", domReady, true);
|
||||
this._addAllStyleSheets().then(deferred.resolve, Cu.reportError);
|
||||
};
|
||||
for (let doc of documents) {
|
||||
let sheets = yield this._addStyleSheets(doc);
|
||||
actors = actors.concat(sheets);
|
||||
|
||||
if (window.document.readyState === "loading") {
|
||||
window.addEventListener("DOMContentLoaded", domReady, true);
|
||||
} else {
|
||||
domReady();
|
||||
// Recursively handle style sheets of the documents in iframes.
|
||||
for (let iframe of doc.querySelectorAll("iframe, browser, frame")) {
|
||||
if (iframe.contentDocument) {
|
||||
// Sometimes, iframes don't have any document, like the
|
||||
// one that are over deeply nested (bug 285395)
|
||||
documents.push(iframe.contentDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}, {
|
||||
return actors;
|
||||
}), {
|
||||
request: {},
|
||||
response: { styleSheets: RetVal("array:stylesheet") }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Add all the stylesheets in this document and its subframes.
|
||||
* Assumes the document is loaded.
|
||||
*
|
||||
* @return {Promise}
|
||||
* Promise that resolves with an array of StyleSheetActors
|
||||
*/
|
||||
_addAllStyleSheets: function() {
|
||||
return Task.spawn(function*() {
|
||||
let documents = [this.document];
|
||||
let actors = [];
|
||||
|
||||
for (let doc of documents) {
|
||||
let sheets = yield this._addStyleSheets(doc);
|
||||
actors = actors.concat(sheets);
|
||||
|
||||
// Recursively handle style sheets of the documents in iframes.
|
||||
for (let iframe of doc.querySelectorAll("iframe, browser, frame")) {
|
||||
if (iframe.contentDocument) {
|
||||
// Sometimes, iframes don't have any document, like the
|
||||
// one that are over deeply nested (bug 285395)
|
||||
documents.push(iframe.contentDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
return actors;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if we should be showing this stylesheet.
|
||||
*
|
||||
@ -160,6 +134,11 @@ let StyleSheetsActor = exports.StyleSheetsActor = protocol.ActorClass({
|
||||
_addStyleSheets: function(doc)
|
||||
{
|
||||
return Task.spawn(function*() {
|
||||
if (doc.readyState === "loading") {
|
||||
// Wait for the document to load first.
|
||||
yield listenOnce(doc.defaultView, "DOMContentLoaded", true);
|
||||
}
|
||||
|
||||
let isChrome = Services.scriptSecurityManager.isSystemPrincipal(doc.nodePrincipal);
|
||||
let styleSheets = isChrome ? DOMUtils.getAllStyleSheets(doc) : doc.styleSheets;
|
||||
let actors = [];
|
||||
|
@ -74,6 +74,7 @@ const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" +
|
||||
const ERR_RENAME_FILE = "rename_file: failed to rename file";
|
||||
const ERR_UNABLE_OPEN_DEST = "unable to open destination file";
|
||||
const ERR_BACKUP_DISCARD = "backup_discard: unable to remove";
|
||||
const ERR_MOVE_DESTDIR_7 = "Moving destDir to tmpDir failed, err: 7";
|
||||
|
||||
const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result.";
|
||||
|
||||
@ -144,7 +145,6 @@ var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
|
||||
var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX;
|
||||
var gStageUpdate = false;
|
||||
var gSwitchApp = false;
|
||||
var gDisableReplaceFallback = false;
|
||||
var gUseTestAppDir = true;
|
||||
|
||||
var gTimeoutRuns = 0;
|
||||
@ -1584,21 +1584,11 @@ function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
|
||||
}
|
||||
debugDump("running the updater: " + updateBin.path + " " + args.join(" "));
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].
|
||||
getService(Ci.nsIEnvironment);
|
||||
if (gDisableReplaceFallback) {
|
||||
env.set("MOZ_NO_REPLACE_FALLBACK", "1");
|
||||
}
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
process.init(updateBin);
|
||||
process.run(true, args, args.length);
|
||||
|
||||
if (gDisableReplaceFallback) {
|
||||
env.set("MOZ_NO_REPLACE_FALLBACK", "");
|
||||
}
|
||||
|
||||
let status = readStatusFile();
|
||||
if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) {
|
||||
if (process.exitValue != aExpectedExitValue) {
|
||||
@ -2126,7 +2116,7 @@ function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
|
||||
|
||||
gServiceLaunchedCallbackArgs = [
|
||||
"-no-remote",
|
||||
"-process-updates",
|
||||
"-test-process-updates",
|
||||
"-dump-args",
|
||||
appArgsLogPath
|
||||
];
|
||||
@ -2343,7 +2333,6 @@ function setupUpdaterTest(aMarFile) {
|
||||
helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile);
|
||||
helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile);
|
||||
|
||||
let applyToDir = getApplyDirFile(null, true);
|
||||
gTestFiles.forEach(function SUT_TF_FE(aTestFile) {
|
||||
if (aTestFile.originalFile || aTestFile.originalContents) {
|
||||
let testDir = getApplyDirFile(aTestFile.relPathDir, true);
|
||||
@ -3386,8 +3375,8 @@ function createAppInfo(aID, aName, aVersion, aPlatformVersion) {
|
||||
* Command line arguments used when launching the application:
|
||||
* -no-remote prevents shell integration from being affected by an existing
|
||||
* application process.
|
||||
* -process-updates makes the application exits after being relaunched by the
|
||||
* updater.
|
||||
* -test-process-updates makes the application exit after being relaunched by
|
||||
* the updater.
|
||||
* the platform specific string defined by PIPE_TO_NULL to output both stdout
|
||||
* and stderr to null. This is needed to prevent output from the application
|
||||
* from ending up in the xpchsell log.
|
||||
@ -3409,14 +3398,14 @@ function getProcessArgs(aExtraArgs) {
|
||||
launchScript.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY);
|
||||
|
||||
let scriptContents = "#! /bin/sh\n";
|
||||
scriptContents += appBinPath + " -no-remote -process-updates " +
|
||||
scriptContents += appBinPath + " -no-remote -test-process-updates " +
|
||||
aExtraArgs.join(" ") + " " + PIPE_TO_NULL;
|
||||
writeFile(launchScript, scriptContents);
|
||||
debugDump("created " + launchScript.path + " containing:\n" +
|
||||
scriptContents);
|
||||
args = [launchScript.path];
|
||||
} else {
|
||||
args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"].
|
||||
args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-test-process-updates"].
|
||||
concat(aExtraArgs).concat([PIPE_TO_NULL]);
|
||||
}
|
||||
return args;
|
||||
|
@ -1,48 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* Application in use complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
const START_STATE = STATE_APPLIED;
|
||||
const END_STATE = STATE_PENDING;
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Launch the callback helper application so it is in use during the update.
|
||||
let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let callbackAppProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
callbackAppProcess.init(callbackApp);
|
||||
callbackAppProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, START_STATE, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, END_STATE, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
/* Application in use complete MAR file staged patch apply failure test */
|
||||
|
||||
const START_STATE = STATE_APPLIED;
|
||||
const END_STATE = STATE_FAILED_WRITE_ERROR;
|
||||
const END_STATE = STATE_PENDING;
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
@ -33,7 +33,6 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, END_STATE, checkUpdateApplied);
|
||||
}
|
||||
|
||||
@ -42,8 +41,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let fileInUseBin = getApplyDirFile(gTestFiles[13].relPathDir +
|
||||
gTestFiles[13].fileName);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, STATE_APPLIED, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use partial MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let fileInUseBin = getApplyDirFile(gTestFiles[11].relPathDir +
|
||||
gTestFiles[11].fileName);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, STATE_APPLIED, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -31,8 +31,7 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -40,8 +39,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -31,8 +31,7 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -40,8 +39,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File locked complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Exclusively lock an existing file so it is in use during the update.
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let helperDestDir = getApplyDirFile(DIR_RESOURCES);
|
||||
helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
|
||||
helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN);
|
||||
// Strip off the first two directories so the path has to be from the helper's
|
||||
// working directory.
|
||||
let lockFileRelPath = gTestFiles[3].relPathDir.split("/");
|
||||
if (IS_MACOSX) {
|
||||
lockFileRelPath = lockFileRelPath.slice(2);
|
||||
}
|
||||
lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[3].fileName;
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT, lockFileRelPath];
|
||||
let lockFileProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
lockFileProcess.init(helperBin);
|
||||
lockFileProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File locked partial MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
// Exclusively lock an existing file so it is in use during the update.
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let helperDestDir = getApplyDirFile(DIR_RESOURCES);
|
||||
helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
|
||||
helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN);
|
||||
// Strip off the first two directories so the path has to be from the helper's
|
||||
// working directory.
|
||||
let lockFileRelPath = gTestFiles[2].relPathDir.split("/");
|
||||
if (IS_MACOSX) {
|
||||
lockFileRelPath = lockFileRelPath.slice(2);
|
||||
}
|
||||
lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[2].fileName;
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT, lockFileRelPath];
|
||||
let lockFileProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
lockFileProcess.init(helperBin);
|
||||
lockFileProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -40,8 +40,7 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -49,8 +48,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -49,8 +48,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,57 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use inside removed dir complete MAR file staged patch apply failure
|
||||
fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
let fileInUseBin = getApplyDirFile(gTestDirs[4].relPathDir +
|
||||
gTestDirs[4].subDirs[0] +
|
||||
gTestDirs[4].subDirFiles[0]);
|
||||
// Remove the empty file created for the test so the helper application can
|
||||
// replace it.
|
||||
fileInUseBin.remove(false);
|
||||
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let fileInUseDir = getApplyDirFile(gTestDirs[4].relPathDir +
|
||||
gTestDirs[4].subDirs[0]);
|
||||
helperBin.copyTo(fileInUseDir, gTestDirs[4].subDirFiles[0]);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, STATE_APPLIED, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use inside removed dir partial MAR file staged patch apply failure
|
||||
fallback test */
|
||||
|
||||
function run_test() {
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
let fileInUseBin = getApplyDirFile(gTestDirs[2].relPathDir +
|
||||
gTestDirs[2].files[0]);
|
||||
// Remove the empty file created for the test so the helper application can
|
||||
// replace it.
|
||||
fileInUseBin.remove(false);
|
||||
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let fileInUseDir = getApplyDirFile(gTestDirs[2].relPathDir);
|
||||
helperBin.copyTo(fileInUseDir, gTestDirs[2].files[0]);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, STATE_APPLIED, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -35,15 +35,13 @@ function run_test() {
|
||||
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdate(0, STATE_APPLIED, null);
|
||||
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -51,8 +49,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ function doUpdate() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -49,8 +48,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -39,8 +39,6 @@ skip-if = os == 'win' || toolkit == 'gonk'
|
||||
reason = bug 1164150
|
||||
[marAppInUseStageFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marAppInUseFallbackStageFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileLockedFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileLockedFailurePartial_win.js]
|
||||
@ -50,10 +48,6 @@ skip-if = os != 'win'
|
||||
run-sequentially = Bug 1156446
|
||||
[marFileLockedStageFailurePartial_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileLockedFallbackStageFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileLockedFallbackStageFailurePartial_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileInUseSuccessComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileInUseSuccessPartial_win.js]
|
||||
@ -70,14 +64,6 @@ skip-if = os != 'win'
|
||||
skip-if = os != 'win'
|
||||
[marRMRFDirFileInUseStageFailurePartial_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileInUseFallbackStageFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marFileInUseFallbackStageFailurePartial_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marRMRFDirFileInUseFallbackStageFailureComplete_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marRMRFDirFileInUseFallbackStageFailurePartial_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marAppApplyDirLockedStageFailure_win.js]
|
||||
skip-if = os != 'win'
|
||||
[marAppApplyUpdateAppBinInUseStageSuccess_win.js]
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* Application in use complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
const START_STATE = STATE_PENDING_SVC;
|
||||
const END_STATE = STATE_PENDING;
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Launch the callback helper application so it is in use during the update.
|
||||
let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let callbackAppProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
callbackAppProcess.init(callbackApp);
|
||||
callbackAppProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(START_STATE, STATE_APPLIED);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, END_STATE, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
/* Application in use complete MAR file staged patch apply failure test */
|
||||
|
||||
const START_STATE = STATE_PENDING_SVC;
|
||||
const END_STATE = STATE_FAILED_WRITE_ERROR;
|
||||
const END_STATE = STATE_PENDING;
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
@ -43,7 +43,6 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, END_STATE, checkUpdateApplied);
|
||||
}
|
||||
|
||||
@ -52,8 +51,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let fileInUseBin = getApplyDirFile(gTestFiles[13].relPathDir +
|
||||
gTestFiles[13].fileName);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use partial MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let fileInUseBin = getApplyDirFile(gTestFiles[11].relPathDir +
|
||||
gTestFiles[11].fileName);
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -41,8 +41,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -50,8 +49,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -50,8 +49,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File locked complete MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
// Exclusively lock an existing file so it is in use during the update.
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let helperDestDir = getApplyDirFile(DIR_RESOURCES);
|
||||
helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
|
||||
helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN);
|
||||
// Strip off the first two directories so the path has to be from the helper's
|
||||
// working directory.
|
||||
let lockFileRelPath = gTestFiles[3].relPathDir.split("/");
|
||||
if (IS_MACOSX) {
|
||||
lockFileRelPath = lockFileRelPath.slice(2);
|
||||
}
|
||||
lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[3].fileName;
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT, lockFileRelPath];
|
||||
let lockFileProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
lockFileProcess.init(helperBin);
|
||||
lockFileProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_FAILED_WRITE_ERROR_FILE_COPY);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File locked partial MAR file staged patch apply failure fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
// Exclusively lock an existing file so it is in use during the update.
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let helperDestDir = getApplyDirFile(DIR_RESOURCES);
|
||||
helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
|
||||
helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN);
|
||||
// Strip off the first two directories so the path has to be from the helper's
|
||||
// working directory.
|
||||
let lockFileRelPath = gTestFiles[2].relPathDir.split("/");
|
||||
if (IS_MACOSX) {
|
||||
lockFileRelPath = lockFileRelPath.slice(2);
|
||||
}
|
||||
lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[2].fileName;
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT, lockFileRelPath];
|
||||
let lockFileProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
lockFileProcess.init(helperBin);
|
||||
lockFileProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_FAILED_WRITE_ERROR_FILE_COPY);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -50,8 +50,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -59,8 +58,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -59,8 +58,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use inside removed dir complete MAR file staged patch apply failure
|
||||
fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesCompleteSuccess;
|
||||
gTestDirs = gTestDirsCompleteSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_COMPLETE_MAR);
|
||||
|
||||
let fileInUseBin = getApplyDirFile(gTestDirs[4].relPathDir +
|
||||
gTestDirs[4].subDirs[0] +
|
||||
gTestDirs[4].subDirFiles[0]);
|
||||
// Remove the empty file created for the test so the helper application can
|
||||
// replace it.
|
||||
fileInUseBin.remove(false);
|
||||
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let fileInUseDir = getApplyDirFile(gTestDirs[4].relPathDir +
|
||||
gTestDirs[4].subDirs[0]);
|
||||
helperBin.copyTo(fileInUseDir, gTestDirs[4].subDirFiles[0]);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* File in use inside removed dir partial MAR file staged patch apply failure
|
||||
fallback test */
|
||||
|
||||
function run_test() {
|
||||
if (!shouldRunServiceTest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gStageUpdate = true;
|
||||
setupTestCommon();
|
||||
gTestFiles = gTestFilesPartialSuccess;
|
||||
gTestDirs = gTestDirsPartialSuccess;
|
||||
setTestFilesAndDirsForFailure();
|
||||
setupUpdaterTest(FILE_PARTIAL_MAR);
|
||||
|
||||
let fileInUseBin = getApplyDirFile(gTestDirs[2].relPathDir +
|
||||
gTestDirs[2].files[0]);
|
||||
// Remove the empty file created for the test so the helper application can
|
||||
// replace it.
|
||||
fileInUseBin.remove(false);
|
||||
|
||||
let helperBin = getTestDirFile(FILE_HELPER_BIN);
|
||||
let fileInUseDir = getApplyDirFile(gTestDirs[2].relPathDir);
|
||||
helperBin.copyTo(fileInUseDir, gTestDirs[2].files[0]);
|
||||
|
||||
// Launch an existing file so it is in use during the update.
|
||||
let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s",
|
||||
HELPER_SLEEP_TIMEOUT];
|
||||
let fileInUseProcess = Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(Ci.nsIProcess);
|
||||
fileInUseProcess.init(fileInUseBin);
|
||||
fileInUseProcess.run(false, args, args.length);
|
||||
|
||||
setupAppFilesAsync();
|
||||
}
|
||||
|
||||
function setupAppFilesFinished() {
|
||||
do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
|
||||
}
|
||||
|
||||
function doUpdate() {
|
||||
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED);
|
||||
}
|
||||
|
||||
function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
setupHelperFinish();
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
@ -52,8 +52,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -61,8 +60,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ function checkUpdateFinished() {
|
||||
// Switch the application to the staged application that was updated.
|
||||
gStageUpdate = false;
|
||||
gSwitchApp = true;
|
||||
gDisableReplaceFallback = true;
|
||||
runUpdate(1, STATE_FAILED_WRITE_ERROR, checkUpdateApplied);
|
||||
runUpdate(1, STATE_PENDING, checkUpdateApplied);
|
||||
}
|
||||
|
||||
function checkUpdateApplied() {
|
||||
@ -59,8 +58,9 @@ function checkUpdateApplied() {
|
||||
}
|
||||
|
||||
function checkUpdate() {
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, true, false);
|
||||
checkFilesAfterUpdateFailure(getApplyDirFile, false, false);
|
||||
checkUpdateLogContains(ERR_RENAME_FILE);
|
||||
checkUpdateLogContains(ERR_MOVE_DESTDIR_7);
|
||||
standardInit();
|
||||
checkCallbackAppLog();
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ function run_test() {
|
||||
|
||||
// Don't test symlinks on Mac OS X in this test since it tends to timeout.
|
||||
// It is tested on Mac OS X in marAppInUseStageSuccessComplete_unix.js
|
||||
if (IS_UNIX && !IS_MACOSX) {
|
||||
// The tests don't support symlinks on gonk.
|
||||
if (IS_UNIX && !IS_MACOSX && !IS_TOOLKIT_GONK) {
|
||||
removeSymlink();
|
||||
createSymlink();
|
||||
do_register_cleanup(removeSymlink);
|
||||
@ -97,7 +98,8 @@ function finishCheckUpdateApplied() {
|
||||
checkUpdateLogContains("removing old distribution directory");
|
||||
}
|
||||
|
||||
if (IS_UNIX && !IS_MACOSX) {
|
||||
// The tests don't support symlinks on gonk.
|
||||
if (IS_UNIX && !IS_MACOSX && !IS_TOOLKIT_GONK) {
|
||||
checkSymlink();
|
||||
}
|
||||
checkAppBundleModTime();
|
||||
|
@ -35,8 +35,6 @@ run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marAppInUseStageFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marAppInUseFallbackStageFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileLockedFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileLockedFailurePartialSvc_win.js]
|
||||
@ -45,10 +43,6 @@ run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileLockedStageFailurePartialSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileLockedFallbackStageFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileLockedFallbackStageFailurePartialSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileInUseSuccessCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileInUseSuccessPartialSvc_win.js]
|
||||
@ -65,14 +59,6 @@ run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marRMRFDirFileInUseStageFailurePartialSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileInUseFallbackStageFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marFileInUseFallbackStageFailurePartialSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marRMRFDirFileInUseFallbackStageFailureCompleteSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marRMRFDirFileInUseFallbackStageFailurePartialSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marAppApplyDirLockedStageFailureSvc_win.js]
|
||||
run-sequentially = Uses the Mozilla Maintenance Service.
|
||||
[marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js]
|
||||
|
@ -345,6 +345,13 @@ mstrtok(const NS_tchar *delims, NS_tchar **str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
EnvHasValue(const char *name)
|
||||
{
|
||||
const char *val = getenv(name);
|
||||
return (val && *val);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
/**
|
||||
* Coverts a relative update path to a full path for Windows.
|
||||
@ -2266,7 +2273,7 @@ UpdateThreadFunc(void *param)
|
||||
// The MOZ_TEST_SKIP_UPDATE_STAGE environment variable prevents copying
|
||||
// the files in dist/bin in the test updater when staging an update since
|
||||
// this can cause tests to timeout.
|
||||
if (getenv("MOZ_TEST_SKIP_UPDATE_STAGE")) {
|
||||
if (EnvHasValue("MOZ_TEST_SKIP_UPDATE_STAGE")) {
|
||||
rv = OK;
|
||||
} else {
|
||||
rv = CopyInstallDirToDestDir();
|
||||
@ -2286,8 +2293,7 @@ UpdateThreadFunc(void *param)
|
||||
}
|
||||
}
|
||||
|
||||
bool reportRealResults = true;
|
||||
if (sReplaceRequest && rv && !getenv("MOZ_NO_REPLACE_FALLBACK")) {
|
||||
if (sReplaceRequest && rv) {
|
||||
// When attempting to replace the application, we should fall back
|
||||
// to non-staged updates in case of a failure. We do this by
|
||||
// setting the status to pending, exiting the updater, and
|
||||
@ -2295,22 +2301,16 @@ UpdateThreadFunc(void *param)
|
||||
// startup path will see the pending status, and will start the
|
||||
// updater application again in order to apply the update without
|
||||
// staging.
|
||||
// The MOZ_NO_REPLACE_FALLBACK environment variable is used to
|
||||
// bypass this fallback, and is used in the updater tests.
|
||||
// The only special thing which we should do here is to remove the
|
||||
// staged directory as it won't be useful any more.
|
||||
ensure_remove_recursive(gWorkingDirPath);
|
||||
WriteStatusFile(sUsingService ? "pending-service" : "pending");
|
||||
// We need to use --process-updates again in the tests
|
||||
putenv(const_cast<char*>("MOZ_PROCESS_UPDATES="));
|
||||
reportRealResults = false; // pretend success
|
||||
}
|
||||
|
||||
if (reportRealResults) {
|
||||
#ifdef TEST_UPDATER
|
||||
// Some tests need to use --test-process-updates again.
|
||||
putenv(const_cast<char*>("MOZ_TEST_PROCESS_UPDATES="));
|
||||
#endif
|
||||
} else {
|
||||
if (rv) {
|
||||
LOG(("failed: %d", rv));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
#ifdef XP_MACOSX
|
||||
// If the update was successful we need to update the timestamp on the
|
||||
// top-level Mac OS X bundle directory so that Mac OS X's Launch Services
|
||||
@ -2332,7 +2332,7 @@ UpdateThreadFunc(void *param)
|
||||
int NS_main(int argc, NS_tchar **argv)
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
if (getenv("LD_PRELOAD")) {
|
||||
if (EnvHasValue("LD_PRELOAD")) {
|
||||
// If the updater is launched with LD_PRELOAD set, then we wind up
|
||||
// preloading libmozglue.so. Under some circumstances, this can cause
|
||||
// the remount of /system to fail when going from rw to ro, so if we
|
||||
@ -2399,7 +2399,7 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
#ifdef XP_WIN
|
||||
bool useService = false;
|
||||
bool testOnlyFallbackKeyExists = false;
|
||||
bool noServiceFallback = getenv("MOZ_NO_SERVICE_FALLBACK") != nullptr;
|
||||
bool noServiceFallback = EnvHasValue("MOZ_NO_SERVICE_FALLBACK");
|
||||
putenv(const_cast<char*>("MOZ_NO_SERVICE_FALLBACK="));
|
||||
|
||||
// We never want the service to be used unless we build with
|
||||
@ -2465,7 +2465,7 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
*slash = NS_T('\0');
|
||||
}
|
||||
|
||||
if (getenv("MOZ_OS_UPDATE")) {
|
||||
if (EnvHasValue("MOZ_OS_UPDATE")) {
|
||||
sIsOSUpdate = true;
|
||||
putenv(const_cast<char*>("MOZ_OS_UPDATE="));
|
||||
}
|
||||
@ -2572,7 +2572,7 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
const int callbackIndex = 6;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
sUsingService = getenv("MOZ_USING_SERVICE") != nullptr;
|
||||
sUsingService = EnvHasValue("MOZ_USING_SERVICE");
|
||||
putenv(const_cast<char*>("MOZ_USING_SERVICE="));
|
||||
// lastFallbackError keeps track of the last error for the service not being
|
||||
// used, in case of an error when fallback is not enabled we write the
|
||||
@ -3217,13 +3217,10 @@ int NS_main(int argc, NS_tchar **argv)
|
||||
LaunchMacPostProcess(gInstallDirPath);
|
||||
}
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
if (getenv("MOZ_PROCESS_UPDATES") == nullptr) {
|
||||
LaunchCallbackApp(argv[5],
|
||||
argc - callbackIndex,
|
||||
argv + callbackIndex,
|
||||
sUsingService);
|
||||
}
|
||||
LaunchCallbackApp(argv[5],
|
||||
argc - callbackIndex,
|
||||
argv + callbackIndex,
|
||||
sUsingService);
|
||||
}
|
||||
|
||||
return gSucceeded ? 0 : 1;
|
||||
|
@ -3811,9 +3811,9 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
|
||||
if (NS_FAILED(rv))
|
||||
updRoot = mDirProvider.GetAppDir();
|
||||
|
||||
// If the MOZ_PROCESS_UPDATES environment variable already exists, then
|
||||
// If the MOZ_TEST_PROCESS_UPDATES environment variable already exists, then
|
||||
// we are being called from the callback application.
|
||||
if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
|
||||
if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
|
||||
// If the caller has asked us to log our arguments, do so. This is used
|
||||
// to make sure that the maintenance service successfully launches the
|
||||
// callback application.
|
||||
@ -3831,13 +3831,13 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
|
||||
// Support for processing an update and exiting. The MOZ_TEST_PROCESS_UPDATES
|
||||
// environment variable will be part of the updater's environment and the
|
||||
// application that is relaunched by the updater. When the application is
|
||||
// relaunched by the updater it will be removed below and the application
|
||||
// will exit.
|
||||
if (CheckArg("process-updates")) {
|
||||
SaveToEnv("MOZ_PROCESS_UPDATES=1");
|
||||
if (CheckArg("test-process-updates")) {
|
||||
SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
|
||||
}
|
||||
nsCOMPtr<nsIFile> exeFile, exeDir;
|
||||
rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
|
||||
@ -3851,8 +3851,8 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
|
||||
gRestartArgc,
|
||||
gRestartArgv,
|
||||
mAppData->version);
|
||||
if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
|
||||
SaveToEnv("MOZ_PROCESS_UPDATES=");
|
||||
if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
|
||||
SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
|
||||
*aExitFlag = true;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1012,7 +1012,7 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
|
||||
return rv;
|
||||
|
||||
ProcessType dummyPID; // this will only be used for MOZ_UPDATE_STAGING
|
||||
const char *processingUpdates = PR_GetEnv("MOZ_PROCESS_UPDATES");
|
||||
const char *processingUpdates = PR_GetEnv("MOZ_TEST_PROCESS_UPDATES");
|
||||
if (processingUpdates && *processingUpdates) {
|
||||
// Enable the tests to request an update to be staged.
|
||||
const char *stagingUpdate = PR_GetEnv("MOZ_UPDATE_STAGING");
|
||||
|
Loading…
Reference in New Issue
Block a user