Search code examples
javascriptfirefox-addonuninstallationfirefox-addon-restartless

In uninstall function of bootstrap, re-import?


In the uninstall part of my bootstrapped addons I do some important stuff. I delete any files it created and all preferences. However this uses some services.

This is an example of one of my uninstall procedures:

function uninstall(aData, aReason) {
    if (aReason == ADDON_UNINSTALL) { //have to put this here because uninstall fires on upgrade/downgrade too
        //this is real uninstall
        Cu.import('resource://gre/modules/Services.jsm');
        Cu.import('resource://gre/modules/devtools/Console.jsm');
        Cu.import('resource://gre/modules/osfile.jsm');
        //if custom images were used lets delete them now
        var customImgPrefs = ['customImgIdle', 'customImgLoading'];
        [].forEach.call(customImgPrefs, function(n) {
            //cant check the pref i guess because its probably unintialized or deleted before i used have a `if(prefs[n].value != '') {`
            //var normalized = OS.Path.normalize(prefs[n].value);
            //var profRootDirLoc = OS.Path.join(OS.Constants.Path.profileDir, OS.Path.basename(normalized));
            var profRootDirLoc = OS.Path.join(OS.Constants.Path.profileDir, 'throbber-restored-' + n);
            var promiseDelete = OS.File.remove(profRootDirLoc);
            console.log('profRootDirLoc', profRootDirLoc)
            promiseDelete.then(
                function() {
                    Services.prompt.alert(null, 'deleted', 'success on ' + n);
                },
                function(aRejReas) {
                    console.warn('Failed to delete copy of custom throbber ' + n + ' image for reason: ', aRejReas);
                    Services.prompt.alert(null, 'deleted', 'FAILED on ' + n);
                }
            );
        });

        Services.prefs.deleteBranch(prefPrefix);
    }

The reason I post rather than test is because I tested and it worked but is there any special cases? Like what if addon was disabled, browser restarted, and then user opened addon manager then uninstalled. Special cases like these and any others? Do they require me to import all my stuff again?


Solution

  • uninstall wlll be called regardless of whether the add-on was previously enabled or not, and regardless of whether the add-on was compatible or not, as long at the add-on is still present. It won't be called, of course, if the user manually deleted the add-on XPI (or unpacked directory) from their profile while the browser wasn't running, because then on the next start there is nothing left to call.

    This also means that uninstall might be the first (and only) add-on function called. If the add-on was always disabled right from the browser start and it is then disabled, then there won't be any other calls. This is important to be aware of. Consider the following contrived example.

    var myId;
    
    Cu.reportError("global exec"); // Thiw will be always run, as well.
    
    function startup(data) {
      myId = data.id,
    }
    function uninstall() {
      Cu.reportError(myId); // might be undefined if startup never ran.
    }
    

    So, there are three and a half special "things" to consider:

    1. uninstall does not run when the XPI is manually removed while the browser is not running. 2. When uinstalled properly, then uninstall will always be run.
    2. .. even if no other add-on functions were called prior to that.
    3. This also means that any global code in your bootstrap.js will also run on uninstall, as a consequent of loading bootstrap.js.

    Upon cursory inspection, your code does not seem to rely on anything initialized elsewhere, so it should be fine.

    I'd like to point out however, that it is generally considered a bad idea to remove user configuration upon uninstall if not specifically instructed by the user to do so. Same goes for configuration files and user data files. If you do so, you should ask before. Users will regularly uninstall and then reinstall stuff, only to find their carefully crafted preferences, etc. are gone otherwise.