/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; this.EXPORTED_SYMBOLS = ["Bootstraper"]; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const CC = Components.Constructor; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); function debug(aMsg) { //dump("-*- Bootstraper: " + aMsg + "\n"); } /** * This module loads the manifest for app from the --start-url enpoint and * ensures that it's installed as the system app. */ this.Bootstraper = { _manifestURL: null, _startupURL: null, bailout: function(aMsg) { dump("************************************************************\n"); dump("* /!\\ " + aMsg + "\n"); dump("************************************************************\n"); let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] .getService(Ci.nsIAppStartup); appStartup.quit(appStartup.eForceQuit); }, installSystemApp: function(aManifest) { // Get the appropriate startup url from the manifest launch_path. let base = Services.io.newURI(this._manifestURL, null, null); let origin = base.prePath; let helper = new ManifestHelper(aManifest, origin, this._manifestURL); this._startupURL = helper.fullLaunchPath(); return new Promise((aResolve, aReject) => { debug("Origin is " + origin); let appData = { app: { installOrigin: origin, origin: origin, manifest: aManifest, manifestURL: this._manifestURL, manifestHash: AppsUtils.computeHash(JSON.stringify(aManifest)), appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED }, appId: 1, isBrowser: false, isPackage: false }; //DOMApplicationRegistry.confirmInstall(appData, null, aResolve); }); }, /** * Resolves to a json manifest. */ loadManifest: function() { return new Promise((aResolve, aReject) => { debug("Loading manifest " + this._manifestURL); let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] .createInstance(Ci.nsIXMLHttpRequest); xhr.mozBackgroundRequest = true; xhr.open("GET", this._manifestURL); xhr.responseType = "json"; xhr.addEventListener("load", () => { if (xhr.status >= 200 && xhr.status < 400) { debug("Success loading " + this._manifestURL); aResolve(xhr.response); } else { aReject("Error loading " + this._manifestURL); } }); xhr.addEventListener("error", () => { aReject("Error loading " + this._manifestURL); }); xhr.send(null); }); }, configure: function() { debug("Setting startup prefs... " + this._startupURL); Services.prefs.setCharPref("b2g.system_manifest_url", this._manifestURL); Services.prefs.setCharPref("b2g.system_startup_url", this._startupURL); return Promise.resolve(); }, /** * If a system app is already installed, uninstall it so that we can * cleanly replace it by the current one. */ uninstallPreviousSystemApp: function() { // TODO: FIXME return Promise.resolve(); let oldManifestURL; try{ oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); } catch(e) { // No preference set, so nothing to uninstall. return Promise.resolve(); } let id = DOMApplicationRegistry.getAppLocalIdByManifestURL(oldManifestURL); if (id == Ci.nsIScriptSecurityManager.NO_APP_ID) { return Promise.resolve(); } debug("Uninstalling " + oldManifestURL); return DOMApplicationRegistry.uninstall(oldManifestURL); }, /** * Check if we are already configured to run from this manifest url. */ isInstallRequired: function(aManifestURL) { try { if (Services.prefs.getCharPref("b2g.system_manifest_url") == aManifestURL) { return false; } } catch(e) { } return true; }, /** * Resolves once we have installed the app. */ ensureSystemAppInstall: function(aManifestURL) { this._manifestURL = aManifestURL; debug("Installing app from " + this._manifestURL); if (!this.isInstallRequired(this._manifestURL)) { debug("Already configured for " + this._manifestURL); return Promise.resolve(); } return new Promise((aResolve, aReject) => { this.uninstallPreviousSystemApp.bind(this) .then(this.loadManifest.bind(this)) .then(this.installSystemApp.bind(this)) .then(this.configure.bind(this)) .then(aResolve) .catch(aReject); }); } };