summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Xhokaxhiu2017-03-15 16:00:52 +0100
committerJulian Xhokaxhiu2017-03-15 16:00:52 +0100
commit1de72a763b71c3706a5bd7bcb90a2bad2da3fc1a (patch)
treea70691d8da8e7107fcdea056842d0c11b51f6b80
parente295302dbdb09a10efff7890088879d94e1c46e2 (diff)
downloadaur-1de72a763b71c3706a5bd7bcb90a2bad2da3fc1a.tar.gz
Reload a tab if it crashes
Thanks to https://chrome.google.com/webstore/detail/snapper-aw-snap-tab-reloa/jehgbfogcmbekbbcadldojojckehlkbi
-rw-r--r--PKGBUILD16
-rw-r--r--aw-snap-reloader-background.js189
-rw-r--r--aw-snap-reloader-manifest.json32
-rw-r--r--chromium-fullscreen.install1
-rw-r--r--chromium-fullscreen.xinitrc2
5 files changed, 234 insertions, 6 deletions
diff --git a/PKGBUILD b/PKGBUILD
index 828dc09d971c..27f753f2022f 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,7 +1,7 @@
# Author: Julian Xhokaxhiu <info@julianxhokaxhiu.com>
pkgname=chromium-fullscreen
-pkgver=1
-pkgrel=7
+pkgver=2
+pkgrel=1
pkgdesc="A script in order to run Chromium in fullscreen mode under the chromium user"
url=""
arch=('x86_64' 'i686' 'arm' 'armv6h' 'armv7h')
@@ -11,11 +11,15 @@ install='chromium-fullscreen.install'
source=('chromium-fullscreen.sysuser'
'chromium-fullscreen.xinitrc'
'disable-x-frame-option-background.js'
- 'disable-x-frame-option-manifest.json')
+ 'disable-x-frame-option-manifest.json'
+ 'aw-snap-reloader-background.js'
+ 'aw-snap-reloader-manifest.json')
md5sums=('9e979fbdd1e4a5a04fd0e91ce6a9a7be'
- 'b5fee3c827d9b9bd3a954dd1213c1525'
+ 'd95b5d1a926e4144984bb6761cae4217'
'c700c36f4ea3e353c6d49df823561fc4'
- 'f543ec018edbaf5533e6bddd5068ff54')
+ 'f543ec018edbaf5533e6bddd5068ff54'
+ 'a2e49410d550e79ac9c0037121522387'
+ 'e6bb49bafce141806d28fe03efc862b0')
package() {
# Copy autorun script
@@ -27,4 +31,6 @@ package() {
# Copy the extensions files
install -Dm644 ${srcdir}/disable-x-frame-option-background.js "$pkgdir/home/chromium/.extensions/disable-x-frame-option/background.js"
install -Dm644 ${srcdir}/disable-x-frame-option-manifest.json "$pkgdir/home/chromium/.extensions/disable-x-frame-option/manifest.json"
+ install -Dm644 ${srcdir}/aw-snap-reloader-background.js "$pkgdir/home/chromium/.extensions/aw-snap-reloader/background.js"
+ install -Dm644 ${srcdir}/aw-snap-reloader-manifest.json "$pkgdir/home/chromium/.extensions/aw-snap-reloader/manifest.json"
}
diff --git a/aw-snap-reloader-background.js b/aw-snap-reloader-background.js
new file mode 100644
index 000000000000..d7324e7c97bc
--- /dev/null
+++ b/aw-snap-reloader-background.js
@@ -0,0 +1,189 @@
+// Inspiration for this extension:
+// http://zerodeveloper.tumblr.com/post/67664299242/chrome-extension-reload-tab-after-crash
+// and
+// https://github.com/unclespode/ohnoyoudidnt
+
+// Different ways to test crashes and other problems in Chrome/Chromium:
+// In Chrome/Chromium see chrome://about under "For debug", currenlty
+// the following options are available:
+// chrome://badcastcrash/
+// chrome://crash/
+// chrome://crashdump/
+// chrome://kill/
+// chrome://hang/
+// chrome://shorthang
+// chrome://gpuclean/
+// chrome://gpucrash/
+// chrome://gpuhang/
+// chrome://memory-exhaust/
+// chrome://ppapiflashcrash/
+// chrome://ppapiflashhang/
+// chrome://quit/
+// chrome://restart/
+//
+// Another option is to open the developer tools on a tab that should be
+// crashed and in the JavaScript console type:
+//
+// var memoryHog = "more"; while(true) {memoryHog = memoryHog + "andMore";}
+//
+// This code will consume so much memory that the tab will crash
+
+// About reloading of tabs; see: https://developer.chrome.com/extensions/tabs
+// chrome.tabs.reload(integer tabId, object reloadProperties, function callback)
+// tabId (integer optional): The ID of the tab to reload;
+// defaults to the selected tab of the current window.
+// reloadProperties (object optional): bypassCache (boolean optional): Whether
+// using any local cache. Default is false.
+// callback (function optional): If you specify the callback parameter,
+// it should be a function that looks like this: function() {...};
+//
+// For the use case of reloading a kiosk app or tabs that the user is using
+// the default of calling chrome.tabs.reload() is best
+
+var tabSuccessCount = {}; // store of succesful probe calls
+var tabUnresponsiveCount = {}; // store of probe calls that got stuck in limbo
+// Interval between checks, do not make this too short (
+// less than 1 second seems unwise, better no less than
+// 2 seconds) since it is also used to determine if a
+// tab is unresponsive
+var checkInterval = 10000; // in milliseconds
+var tabsChecked = {}; // store for arrays of tab-ids that were checked
+var checkIndex = 0; // index of current array of checked tab-ids
+var nrTabs = 0; // current number of tabs
+
+function reloadTabIfNeeded(tab) {
+ return function(result) {
+ if (tabCrashed()) {
+ console.log("Crashed tab: title=" + (tab.title || "") + " id=" + tab.id +
+ " index=" + tab.index.toString() + " windowId=" + tab.windowId.toString() +
+ " sessionId=" + (tab.sessionId || "").toString() +
+ " highlighted=" + tab.highlighted.toString() + " active=" + tab.active.toString());
+ if (tabShouldBeReloaded(tab)) {
+ console.log("Reload tab:" + tab.id.toString());
+ chrome.tabs.reload(tab.id);
+ }
+ } else {
+ registerSuccessfulNoOp(tab);
+ }
+ tabsChecked[checkIndex].push(tab.id);
+ };
+}
+
+function tabShouldBeReloaded(tab) {
+ // Reload if at least one sucessful no-op has occurred.
+ // This might be too causious but ensures the tab was working
+ // before it crashed
+ // this also ensures that we do not reload a tab that takes a long
+ // time to load (being unresponsive whilst doing so)
+ return tabSuccessCount[tab.id] > 0;
+}
+
+function registerSuccessfulNoOp(tab) {
+ if ((tabSuccessCount[tab.id] || null) === null) {
+ tabSuccessCount[tab.id] = 0;
+ }
+ tabSuccessCount[tab.id] += 1;
+ tabUnresponsiveCount[tab.id] = 0;
+}
+
+function registerUnresponsive(tab) {
+ if ((tabUnresponsiveCount[tab.id] || null) === null) {
+ tabUnresponsiveCount[tab.id] = 0;
+ }
+ tabUnresponsiveCount[tab.id] += 1;
+}
+
+function tabCrashed() {
+ // The crux of finding a crashed tab:
+ // If an operation (even a no-op) is executed on a crashed tab an error
+ // is reported which is available as the chrome.runtime.lastError
+ // The error incorrectly reports the tab was closed instead of the fact that the
+ // tab does not respond.
+ return chrome.runtime.lastError && chrome.runtime.lastError.message === "The tab was closed.";
+}
+
+function checkTab(thisTab) {
+ if (relevantTab(thisTab)) {
+ // Perform a no-op as a probe to find if the tab reponds
+ chrome.tabs.executeScript(thisTab.id, {
+ // To find crashed tabs probing with a no-op is enough
+ // code: "null;"
+ // To find unresponsive tabs probing with some operation
+ // that takes CPU-cycles is needed
+ code: "1 + 1;"
+ }, reloadTabIfNeeded(thisTab));
+ }
+}
+
+function relevantTab(tab){
+ // Only check tabs that have finished loading
+ // and that use the http or https protocol.
+ // This ignores tabs like chrome://...
+ // return tab.url.substring(0, 4) == "http" && tab.status == "complete";
+ // This makes testing this extension more difficult, to test use
+ // the line below
+ return tab.status == "complete";
+}
+
+function reloadUnresposiveTabs(index, nrTabs, tabs) {
+ if (nrTabs === tabs.length && nrTabs > tabsChecked[index].length) {
+ var nrTabsToFind = nrTabs - tabsChecked[index].length;
+ console.log("Found " + nrTabsToFind.toString() + " unresponsive tabs");
+ for (var j = 0; j < nrTabs && nrTabsToFind > 0; j += 1) {
+ if (tabsChecked[index].indexOf(tabs[j].id) == -1) {
+ registerUnresponsive(tabs[j]);
+ if (tabShouldBeReloaded(tabs[j])) {
+ console.log("Reload unresponsive tab:" + tabs[j].id.toString());
+ // Reloading an unresponsive tab does not work
+ // chrome.tabs.reload(tabs[j].id);
+ // Therefore a new tab is created with the url of the old tab
+ // and the unresponsive tab is removed.
+ // Setting the new tab as active is mainly aimed at kiosk-like applications
+ chrome.tabs.create({url: tabs[j].url, active: true}, function(tab){
+ console.log("Created new tab: id=" + tab.id.toString() + " title=" + (tab.title || "") + " url=" + (tab.url || ""));
+ });
+ chrome.tabs.remove(tabs[j].id, function(){
+ console.log("Removed unresponsive tab:" + tabs[j].id.toString());
+ });
+ }
+ nrTabsToFind -= 1;
+ }
+ }
+ }
+}
+
+function checkTabs(tabs) {
+ // check for unresponsive tabs by checking the results of
+ // the previous round of checkTab calls
+ // NOTE: it is assumed all tabs have been checked (all callbacks
+ // initiated in the previous checkTabs call have ended (apart
+ // form the ones that were done on unresponsive tabs)). The
+ // checkInterval has to be long enough to make this a "certainty"
+ if (nrTabs > 0) {
+ reloadUnresposiveTabs(checkIndex, nrTabs, tabs);
+ }
+
+ // roll the checkIndex around after 10 iterations
+ checkIndex = checkIndex > 9 ? 0 : (checkIndex + 1);
+ nrTabs = tabs.length;
+ tabsChecked[checkIndex] = [];
+ for (var i = 0; i < tabs.length; i += 1) {
+ checkTab(tabs[i]);
+ }
+}
+
+// Reset the count for tabs that are closed or that change
+function tabChanged(tabId, changeInfo, tab) {
+ console.log("Resetting Stats for tab: id=" + tabId.toString() + " title=" +
+ (tab !== undefined ? tab.title : ""));
+ tabSuccessCount[tabId] = 0;
+ tabUnresponsiveCount[tabId] = 0;
+}
+
+setInterval(function() {
+ chrome.tabs.query({}, checkTabs);
+}, checkInterval);
+
+// If the tab reloads, reset stats
+chrome.tabs.onUpdated.addListener(tabChanged);
+chrome.tabs.onRemoved.addListener(tabChanged);
diff --git a/aw-snap-reloader-manifest.json b/aw-snap-reloader-manifest.json
new file mode 100644
index 000000000000..0d6aa4a6d8f9
--- /dev/null
+++ b/aw-snap-reloader-manifest.json
@@ -0,0 +1,32 @@
+{
+"update_url": "https://clients2.google.com/service/update2/crx",
+
+ "name": "Snapper - 'Aw snap' tab reloader",
+ "short_name": "Snapper",
+ "description": "Reload crashed or unresponsive Chrome tabs (Aw, snap). Specifically intended for digital signage content running in kiosk mode.",
+ "manifest_version": 2,
+ "version": "0.9.7.0",
+ "background": {
+ "scripts": ["javascript/background.js"],
+ "persistent": true
+ },
+ "permissions": [
+ "tabs"
+ ],
+ "browser_action": {
+ "default_icon": {
+ "16": "icons/icon-016.png",
+ "24": "icons/icon-024.png",
+ "32": "icons/icon-032.png"
+ },
+ "default_title": "Snapper"
+ },
+ "icons": {
+ "16": "icons/icon-016.png",
+ "19": "icons/icon-019.png",
+ "24": "icons/icon-024.png",
+ "32": "icons/icon-032.png",
+ "48": "icons/icon-048.png",
+ "128": "icons/icon-128.png"
+ }
+}
diff --git a/chromium-fullscreen.install b/chromium-fullscreen.install
index 711f747a1a49..150d01b72969 100644
--- a/chromium-fullscreen.install
+++ b/chromium-fullscreen.install
@@ -7,6 +7,7 @@ pre_install() {
# Create the extensions folders
mkdir -p /home/chromium/.extensions/disable-x-frame-option
+ mkdir -p /home/chromium/.extensions/aw-snap-reloader
}
post_install() {
diff --git a/chromium-fullscreen.xinitrc b/chromium-fullscreen.xinitrc
index 8a7994926d8d..c50beee37cdb 100644
--- a/chromium-fullscreen.xinitrc
+++ b/chromium-fullscreen.xinitrc
@@ -30,7 +30,7 @@ exec /usr/bin/chromium --disable \
--disable-suggestions-service \
--disable-save-password-bubble \
--disable-session-crashed-bubble \
- --load-extension=.extensions/disable-x-frame-option \
+ --load-extension=.extensions/disable-x-frame-option,.extensions/aw-snap-reloader \
--window-position="0,0" \
--window-size="1920,1080" \
--kiosk "$URL"