WebExtension: Zombie Processes after Disable/Uninstall

I have recently started to try out developing with the new WebExtension. I always use the release version of Firefox (FF 45.0.2 in this case) since it is my policy to only develop on the version that is used by the users (and not the beta/dev versions).

As I was testing new codes and APIs, I repeatedly enable/disable/uninstall/install the addon without restarting and that is where errors started to appear.

For example:
Array [ "h....../7bvK..", "h....../7uCn..", "h....../7CPv.." ] content.js:76:3 1 called content.js:25:7 2 called content.js:30:7 Array [ "h....../7bvK..", "h....../7uCn..", "h....../7CPv.." ] content.js:76:3 1 called content.js:25:7 2 called content.js:30:7 Permission denied to access property "getSelection" content.js:45:0

The last error appeared on different functions such as:
Permission denied to access property "console" content.js

Besides the error, it was also strange that the same data were being logged to the console twice (or more) while there was nothing in the code to cause that.

That is when I realised the presence of Zombies processes.

As an addon reviewer, I always advise developers to consider leftover running processes.

Add-on must unregister/disconnect observers, remove listeners, clearInterval (for setInterval), revert all built-in preferences which add-on changes, and remove its own imported modules (not imported Firefox modules), unregisterSheet; on ‘disable’ or ‘uninstall’.

Sadly, it seems that at the moment, there is no API to listen to Disable/Uninstall in WebExtensions.[1]

The WebExtension I was working on had a single chrome.runtime.onMessage.addListener() in its content script. Initially, I was injecting the script using the content_scripts key in manifest.json.
Later I change to chrome.tabs.executeScript(), however the problem remained.

N.B. A continuously running process (such as Listener, observer, setInterval etc) will remain until it is cleared by the programmer OR garbage collected once the tab is closed or reloaded.

In this case, once the addon was installed, enabled; and/or activated, it injected the listener into the tab/s. However, after disable or uninstall, the listeners remained on the relevant tabs. as zombie processes.

Once the addon was re-installed, re-enabled; and re-activated, a new listeners was injected into the same tab/page. There were now 2 listeners listening on the tab/page for the same call to do the same process.

Calling the listener (e.g. from background script) resulted in both listens being activated and both running the same process.

The result was that the debugging console.log logged the same thing twice. I suspect the subsequent permission errors are also the result of the same processes accessing the the API simultaneously.

In conclusion, the following are the possible options:

  • Developers using a different API and not rely on continuously running processes (e.g. listeners) wherever possible (e.g. APIs with function(result))
    The callback function of tabs.executeScript is a good option but it Requires Gecko 47.
  • Developers removing such processes once they are called (and possibly re-injecting them again once needed)
  • Mozilla Developers implementing a new API to listen to unload (similar to SDK API)

Update:
I decided to use tabs.executeScript to inject the content script. For FF45-46 (which doesn’t support callback function of tabs.executeScript), instead of setting up listeners in the content script, I opted for runtime.sendMessage in the content script to send the message back to the background script and set the listener up in the background script. Furthermore, since the action was initiated by the context-menu, I removed the listener (i.e. runtime.onMessage.removeListener) as soon as it was called. This way, the listener is not inserted in the content and therefore would not cause a zombie process on disable/uninstall.

If I can think of anything else, I will add it later.
:slightly_smiling:

[1] Reference for reviewers: https://addons.mozilla.org/en-US/editors/review/reviewboard-collapser

This is not a good strategy for WebExtensions. Support on 45 is in a pre-release state. It’s meant as a preview, not as a development target.

Can you reproduce this in Firefox 48?

I am not using FF48. Can someone test it out?