Chromium process monitoring methods? Restart if crashes - linux

I have a single page app written in pure HTML with no external plugings and using a full screen chromium for the client. (kiosk mode)
Though Chromium itself is very stable with very minor crashes, But I would like to have it restarted to the page, if it really crashes.
My thought this should be done with an external process like a watchdog, But how does the external monitor chrome? since there are several individual processes in the process table. Sometimes even it crashes, the process still alive out there.
Any suggestion or mature soutuion?

I just solved this myself. At first I tried using the processes API, but that isn't in the version of chrome I'm using on the kiosk. I've configured my kiosk with an extension that I wrote to handle other stuff (TUIO touch input, etc.), so I already had a place to add it.
My kiosk is running a little web server locally, because I found getting chromium to show file:// urls was just too much of a pain in the neck. If you are using file URLs, then your manifest will need to match those, instead of http URLs.
Here's the critical stuff from manifest.json:
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["kiosk.js"]
}
],
"background": {
"scripts": [
"background.js"
]
},
"permissions": [
"webNavigation",
"tabs",
"runtime",
"<all_urls>"
],
This goes into kiosk.js:
chrome.runtime.onMessage.addListener(
function(message, sender, response) {
response(message);
}
);
Basically, it's a ping responder. If you send it a message, it sends it right back.
Here is background.js in its entirety:
var tab_id = -1;
var send_count = 0;
var recv_count = 0;
chrome.webNavigation.onBeforeNavigate.addListener(function (details) {
tab_id = details.tabId;
});
setInterval(function() {
if (tab_id == -1) return;
if (send_count > recv_count+2) {
chrome.tabs.reload(tab_id);
send_count = recv_count = 0;
}
++send_count;
chrome.tabs.sendMessage(tab_id, "heartbeat", function(resp) {
if (resp) {
recv_count = send_count;
}
});
}, 1000);
It listens for my page showing up, and grabs the tab ID. It pings the responder. The documentation says that if an error happens, sendMessage will get called with no response, but that's not true. It actually doesn't get called at all. I coded it to handle either case.
Note that I originally said ++recv_count in the handler, but if you think about it, the above will be a little more robust to slowness on the receiving page.
Assuming your kiosk is linux (that is, you aren't insane), then you can test this easily enough by ssh'ing into your kiosk, and doing a ps axfww |grep render and then kill the first process listed. You'll see the sick computer screen for a sec, and then it will reload.

Related

Chrome extension content scripts not running on certain sites

I've been attempting to write a very simple Chrome extension (manifest v3) to automatically close those annoying tabs zoom leaves open after you join a meeting.
So far I have been able to get most pages to automatically close with my extension but it simply refuses to run on certain domains, including the one I actually need it to run on: https://company-name-here.zoom.us/. I ultimately would like to set the content script matchers to just zoom but for now I have expanded it to all sites in an effort to reduce sources of error.
It is not working no matter how I attempt to load the page, be it by clicking the redirect url on a google calendar event, reloading the page manually after it has already been opened, and even manually typing out the url and hitting enter. The zoom home page suffers from the same problem but other sites such as stack overflow show the "Content script loaded" console log and close in 5 seconds as I would expect.
Please find the entire source for the extension below:
manifest.json
{
"manifest_version": 3,
"name": "Zoom Auto Closer",
"version": "1.0",
"background": {
"service_worker": "src/background.js"
},
"content_scripts": [{
"run_at": "document_start",
"matches": ["<all_urls>"],
"js": ["src/content.js"]
}]
}
src/content.js
const closeDelay = 5_000;
const closeCurrentTab = () => chrome.runtime.sendMessage('close-tab');
const main = () => {
console.log('Content script loaded');
setTimeout(closeCurrentTab, closeDelay);
};
main();
src/background.js
const closeTab = tabId => chrome.tabs.remove(tabId);
const onMessage = (message, sender) => {
console.log('Received a message:', message);
switch (message) {
case 'close-tab': return closeTab(sender.tab.id);
}
}
const main = () => {
console.log('Service worker registered');
chrome.runtime.onMessage.addListener(onMessage);
}
main();
The issue might be with the usage of <all_urls>.
Google says on the matching patterns docs:
The special pattern <all_urls> matches any URL that starts with a
permitted scheme.
And the permitted schemes are http:, https:, and file:.
I am not too familiar with Zoom, but this article suggests that zoom uses the protocol zoommtg: to launch the the desktop program, so this falls outside of what <all_urls> covers.
Edit:
Now I see that you stated that the urls start with https:// so that might invalidate what I suggested. Still might be worth trying "*://*.zoom.us/*" instead of <all_urls>.
You could try using "*://*.zoom.us/*" instead. If that doesn't work you could try ditching the content script and handling everything in the background service worker.
In the background service worker, you could add a listener for chrome.tabs.onUpdated and check the url value to see if it matches the url for a Zoom tab and close it from there. You would also need to use the Alarms API for the delay.
This method wouldn't be as efficient because it is called on every tab update (not really worth worrying about), but it is a possible workaround if you can't get the content script method to work.

HtmlResponse is not supported on this device

I have developed interactive canvas application and it was working fine with devices having display.
Suddenly when I checked it today it says "Application is not responding, try again later.". When I checked in test simulator and gone through debug I have received following error printed in debug.
"sharedDebugInfoList": [
{
"name": "ResponseValidation",
"debugInfo": "",
"subDebugEntryList": [
{
"name": "MalformedResponse",
"debugInfo": "expected_inputs[0].input_prompt.rich_initial_prompt.items[1].html_response: HtmlResponse is not supported on this device..",
"subDebugEntryList": []
}
]
}
],
It was working and users were using it in their mobile device, but this sudden error made me blind to understand it. I have not made even 1 line of change in my code. I have even checked cloud logs and there is nothing. Here is what I am doing when user enters in my action.
app.intent('welcome', (conv) => {
console.log('capabilities = ',conv.surface.capabilities)
if (!conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT')) {
conv.close('Sorry, this device does not support Interactive Canvas!');
return;
}
conv.ask(`Welcome! Let's start the game`);
conv.ask(new HtmlResponse({
url: '<url of my website having interactive canvas support>',
}));
});
Here is the action that I am facing error.
The action seems to be working ok for me.
The most common reason I've seen for it not working is that the category wasn't set to "Games & Fun" (or was cleared for some reason) or the Interactive Canvas checkbox wasn't set.
To make sure you are still in the "Games & Fun" category, go to the Actions Console, the "Deploy" tab, and the "Directory" information.
Then, towards the bottom of that same page, make sure you have the Interactive Canvas checkbox set.

Why reloading google chrome tab via extension switches accounts?

I have a following illustrative extension that will terminate tab process and reload page if user visits "www.ru":
manifest.json
{
"manifest_version" : 2,
"name" : "test extension",
"version" : "1.0.0",
"permissions" : [ "tabs", "experimental" ],
"background" : { "scripts" : [ "extension.js" ], "persistent" : true }
}
extension.js
function reload() {
chrome.tabs.query( {}, function( tabs ) {
for( var i = 0; i < tabs.length; i ++ ) {
if( tabs[ i ].url.match( /www\.ru/ ) ) {
window.setTimeout( function() {
chrome.experimental.processes.getProcessIdForTab( tabs[ i ].id, function( id ) {
chrome.experimental.processes.terminate( id );
})
}, 5000);
window.setTimeout( function() {
chrome.tabs.reload( tabs[ i ].id );
}, 10000);
return;
}
}
window.setTimeout( reload, 1000 );
});
}
window.setTimeout( reload, 1000 );
I start latest google chrome (26.0.1410.64 m 32-bit for windows downloaded from chrome.google.com minutes ago), create second chrome user, switch to that user, install extension, open 'www.ru', switch to first user - and after 10 seconds chrome forcibly switches me back to second user in order to demonstrate tab reload!
Only process kill + tab reload produces this weird behavior (they pause in between can be any length). If terminate or reload parts are commented out, corresponding action is carried but user account is newer switched.
Is it some chrome bug i'm facing or this is documented behavior? Is it possible to prevent forcible account switch? It's very unpleasant for me to be interrupted in the middle of something just to display that some web crawler extension on web crawler account found tab that is not responding and reloaded it :(.
Eye of Hell, this answer is an educated guess. It's possible that Chrome uses a heuristic to determine whether a tab should become the active tab during a load or reload. The heuristic might be that the first load/reload for the tab process should make it the active tab, unless the tab was explicitly created with createProperties active: false. This would make sense if you think of a new tab's default for the active state, and understand that at process creation time (including the process creation after a terminate/reload), the tab is likely set to that default.
If this is true, then instead of reloading the tab after killing its process, perhaps you could do this instead:
Remember the about-to-be-killed tab's URL.
Kill the process and close the tab OR just close the tab.
chrome.tabs.create({url: savedUrl, active: false}).
It's possible that this has some other undesirable side effects, such as losing session cookies. But without knowing more about your use case, this seems like an equivalent approach to what you're trying to do.
By the way, your recovery process could be faster. Rather than setting the 5-second and 10-second timeouts to serialize the kill/reload operations, you can chain the reload (or create) operation in the terminate function's callback. Then it's guaranteed to be called after the terminate is complete, and it won't waste wall-clock time waiting for the extra five seconds.

chrome.experimental.processes.onExited.addListener not working

I am trying to write a Chrome extension which detects process crashes.
First i went to about:flags page of Chrome and enabled "Experimental Extension APIs".
This is the extension I wrote:
manifest.json:
{
"manifest_version": 2,
"name": "CrashDetect",
"description": "Detects crashes in processes.",
"version": "1.0",
"permissions": [
"experimental","tabs"
],
"background": {
"scripts": ["background.js"]
}
}
backround.js:
chrome.experimental.processes.onExited.addListener(function(integer processId, integer exitType, integerexitCode) {
chrome.tabs.getCurrent(function(Tab tab) {
chrome.tabs.update(tab.id, {url:"http:\\127.0.0.1\""});
};)
});
Then I visited about://crash page of Chrome. But onExited listener does not execute.
Have I done anything wrong in manifest.json or background.js?
There a couple errors in your code. First you have the types of the parameters in the function declaration, change it to:
function(processId, exitType, integerexitCode){
Second, you put };) instead of });. Try inspecting the background page to see syntax errors.
Alright, after playing around with it some as I was unfamiliar with this particular API, I found that none of the events fired if I didn't include a handler for onUpdated. I really doubt that this is the intended behavior and I will check to see if there is a bug report on it. For now just do something like this to get it working:
chrome.experimental.processes.onUpdated.addListener(function(process){});
chrome.experimental.processes.onExited.addListener(function(processId, exitType, integerexitCode){
chrome.tabs.query({active:true, currentWindow:true},function(tabs){
chrome.tabs.update(tabs[0].id, {url:"http:\\127.0.0.1"});
});
});
Notice that I did swap out your getCurrent for a chrome.tabs.query as the former would have given you an error. This does lead to the behavior of if you close a tab, the next tab will be redirected. Perhaps you could try to filter by exitType and not include normal exits.

Chrome extension that focuses items in elements panel

I am trying to develop a chrome extension that among other things, will be able to focus an element in the elements panel of the chrome devtools.
I have been pulling my hair out trying to get this to work today but have had no luck so far.
I think part of the key to cracking what I need is here
Here are the main differences between the eval() and
chrome.tabs.executeScript() methods:
The eval() method does not use an isolated world for the code being evaluated, so the JavaScript state of the inspected window is
accessible to the code. Use this method when access to the JavaScript
state of the inspected page is required.
The execution context of the code being evaluated includes the Developer Tools console API. For example, the code can use inspect()
and $0.
The evaluated code may return a value that is passed to the extension callback. The returned value has to be a valid JSON object
(it may contain only primitive JavaScript types and acyclic references
to other JSON objects). Please observe extra care while processing the
data received from the inspected page — the execution context is
essentially controlled by the inspected page; a malicious page may
affect the data being returned to the extension.
But I cannot find the correct place to send the message to or execute the command in order for this to work I am just repeatedly told the following:
Error in event handler for 'undefined': $ is not defined
ReferenceError: $ is not defined
at Object.ftDev.processMsg (chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:39:31)
at chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:16:7
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at miscellaneous_bindings:166:35
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at Object.chromeHidden.Port.dispatchOnMessage (miscellaneous_bindings:254:22) event_bindings:377
chrome.Event.dispatch_
Ideally I would like to use the inspect() method of the chrome console not the $() method.
manifest.json
{
"name": "XXXXX Ad and Spotlight Debugger",
"version": "0.1",
"manifest_version": 2,
"description": "A tool to help you identify and debug XXXXXX ads and spotlights in Chrome",
"devtools_page": "ftDev.html",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "XXXXXX Debug Tool"
},
"background": {
"persistent": false,
"page": "background.html",
"js": ["background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["getFTContent.js"],
"all_frames": true
}],
"permissions": ["tabs","cookies","<all_urls>","devtools"]
}
Then there is similar code in the popup.js, background.js and devtools.js file that essentially boils down to this:
processMsg: function(request, sender, sendResponse) {
switch(request.type) {
case "inspect":
$(request.msg);
sendResponse(request.msg + "successfully inspected");
break;
default:
break;
}
} /*other cases removed for sake of brevity*/
Which when executed results in the error above. I am sure that I am trying to execute the command in the wrong context but I can't figure out how to apply it. In the popup.js file I have also tried executing the $ method as below
chrome.tabs.executeScript(tabId, {code: 'function(){$("#htmlID");}'}, function(){});
Any ideas help would be amazing I can supply more of my code if you think it's necessary but I think this pretty much sums up the problem.
Ok - so I had a look around at the font changer thing and it still wasn't quite what I was looking for in the end but then I had a Eureka moment when I was looking over this page for about the 15th time and realised that I had somehow missed the most important part on the page (at least in order to do what I wanted) which was this method
chrome.devtools.inspectedWindow.eval("string to evaluate", callBack)
It is noted that isn't necessarily a good idea for security reasons as it it doesn't run the code in the isolated world.
Anyway - if I run this code from my devtools' page js-code with the following
chrome.devtools.inspectedWindow.eval("inspect(*id_of_the_div_i_want_inspect*)")
Then it will select this item in the elements page of the devtools... it also made me extremely happy!
:D
I don't know if anyone else will ever need/want this but it too me a long(ish) time to figure it out so I hope it helps other people in future.
You can easily highlight DOM elements in any tab, where your content script is injected. As an example, look at Font Selector extension.
As the source code is available (and thoroughly explained) I'll not post it here. The effect you'll see is that after clicking the browser action button every DOM element under mouse cursor becomes highlighed with red border.
If you want to send some info about selected/highlighted element from the tab into your background page, you can do it via messaging (you have already used it, as I see).

Resources