From 158cd8dd65e642c8bf3570030dd214b65625c07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabrice=20Desr=C3=A9?= Date: Wed, 19 Sep 2012 09:28:55 -0700 Subject: [PATCH] Bug 787439 - Ensure applications permissions are updated when doing a system update [r=vingtetun] --- b2g/chrome/content/shell.js | 5 +- dom/apps/src/Webapps.jsm | 177 +++++++++++++++++++++++--------- modules/libpref/src/init/all.js | 8 +- 3 files changed, 138 insertions(+), 52 deletions(-) diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index a30a64ed16d..f38ead80e3b 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -13,7 +13,6 @@ Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/ContactService.jsm'); Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm'); -Cu.import('resource://gre/modules/Webapps.jsm'); Cu.import('resource://gre/modules/AlarmService.jsm'); Cu.import('resource://gre/modules/ActivitiesService.jsm'); Cu.import('resource://gre/modules/PermissionPromptHelper.jsm'); @@ -297,6 +296,9 @@ var shell = { let chromeWindow = window.QueryInterface(Ci.nsIDOMChromeWindow); chromeWindow.browserDOMWindow = new nsBrowserAccess(); + Cu.import('resource://gre/modules/Webapps.jsm'); + DOMApplicationRegistry.allAppsLaunchable = true; + this.sendEvent(window, 'ContentStart'); break; case 'MozApplicationManifest': @@ -568,7 +570,6 @@ var WebappsHelper = { init: function webapps_init() { Services.obs.addObserver(this, "webapps-launch", false); Services.obs.addObserver(this, "webapps-ask-install", false); - DOMApplicationRegistry.allAppsLaunchable = true; }, registerInstaller: function webapps_registerInstaller(data) { diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index dcbc2d0bdf1..a5c363cd64a 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -67,52 +67,38 @@ let DOMApplicationRegistry = { ppmm.addMessageListener(msgName, this); }).bind(this)); + cpmm.addMessageListener("Activities:Register:OK", this); + Services.obs.addObserver(this, "xpcom-shutdown", false); this.appsFile = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], true); - let dirList = [DIRECTORY_NAME]; + this.loadAndUpdateApps(); + }, -#ifdef MOZ_WIDGET_GONK - dirList.push("coreAppsDir"); -#endif - let currentId = 1; - this.dirsToLoad = dirList.length; - this.dirsLoaded = 0; - dirList.forEach((function(dir) { - let curFile; - try { - // getFile calls getDir with |shouldCreate = true|, so we have - // to wrap in a try..catch in case the file does not exist on a - // read-only partition. - curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], false); - } catch(e) { } - if (curFile && curFile.exists()) { - let appDir = FileUtils.getDir(dir, ["webapps"], false); - this._loadJSONAsync(curFile, (function(aData) { - if (!aData) { - return; - } -#ifdef MOZ_SYS_MSG - let ids = []; -#endif - // Add new apps to the merged list. - for (let id in aData) { - this.webapps[id] = aData[id]; - this.webapps[id].basePath = appDir.path; - this.webapps[id].removable = (dir == DIRECTORY_NAME); -#ifdef MOZ_SYS_MSG - ids.push({ id: id }); -#endif - // local ids must be stable between restarts. - // We partition the ids in two buckets: - // - 1 to 1000 for the core apps. - // - 1001 to Inf for installed apps. - // This way, a gecko update with new core apps will not lead to - // changes for installed apps ids. - if (!this.webapps[id].removable) { - this.webapps[id].localId = currentId++; + // loads the current registry, that could be empty on first run. + // aNext() is called after we load the current webapps list. + loadCurrentRegistry: function loadCurrentRegistry(aNext) { + let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], false); + if (file && file.exists) { + this._loadJSONAsync(file, (function loadRegistry(aData) { + if (aData) { + this.webapps = aData; + let appDir = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false); + for (let id in this.webapps) { + // Make sure we have a localId + if (this.webapps[id].localId === undefined) { + this.webapps[id].localId = this._nextLocalId(); + } + + if (this.webapps[id].basePath === undefined) { + this.webapps[id].basePath = appDir.path; + } + + // Default to removable apps. + if (this.webapps[id].removable === undefined) { + this.webapps[id].removable = true; } // Default to a non privileged status. @@ -120,14 +106,101 @@ let DOMApplicationRegistry = { this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED; } }; + } + aNext(); + }).bind(this)); + } else { + aNext(); + } + }, + + // We are done with loading and initializing. Notify and + // save a copy of the registry. + onInitDone: function onInitDone() { + Services.obs.notifyObservers(this, "webapps-registry-ready", null); + this._saveApps(); + }, + + // registers all the activities and system messages + registerAppsHandlers: function registerAppsHandlers() { #ifdef MOZ_SYS_MSG - this._processManifestForIds(ids); + let ids = []; + for (let id in this.webapps) { + ids.push({ id: id }); + } + this._processManifestForIds(ids); +#else + // Nothing else to do but notifying we're ready. + this.onInitDone(); #endif + }, + + // Implements the core of bug 787439 + // 1. load the apps from the current registry. + // 2. if at first run, go through these steps: + // a. load the core apps registry. + // b. uninstall any core app from the current registry but not in the + // new core apps registry. + // c. for all apps in the new core registry, install them if they are not + // yet in the current registry, and run installPermissions() + loadAndUpdateApps: function loadAndUpdateApps() { + let runUpdate = Services.prefs.getBoolPref("dom.mozApps.runUpdate"); + Services.prefs.setBoolPref("dom.mozApps.runUpdate", false); + + // 1. + this.loadCurrentRegistry((function() { +#ifdef MOZ_WIDGET_GONK + // if first run, merge the system apps. + if (runUpdate) { + let file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false); + if (file && file.exists) { + // 2.a + this._loadJSONAsync(file, (function loadCoreRegistry(aData) { + if (!aData) { + this.registerAppsHandlers(); + return; + } + + // 2.b : core apps are not removable. + for (let id in this.webapps) { + if (id in aData || this.webapps[id].removable) + continue; + let localId = this.webapps[id].localId; + delete this.webapps[id]; + // XXXX once bug 758269 is ready, revoke perms for this app + // removePermissions(localId); + } + + let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false); + // 2.c + for (let id in aData) { + // Core apps have ids matching their domain name (eg: dialer.gaiamobile.org) + // Use that property to check if they are new or not. + if (!(id in this.webapps)) { + this.webapps[id] = aData[id]; + this.webapps[id].basePath = appDir.path; + + // Create a new localId. + this.webapps[id].localId = this._nextLocalId(); + + // Core apps are not removable. + if (this.webapps[id].removable === undefined) { + this.webapps[id].removable = false; + } + } + // XXXX once bug 758269 is ready, revoke perms for this app + // let localId = this.webapps[id].localId; + // installPermissions(localId); + } + this.registerAppsHandlers(); }).bind(this)); - } else { - // The directory we're trying to load from doesn't exist. - this.dirsToLoad--; } + } else { + this.registerAppsHandlers(); + } +#else + this.registerAppsHandlers(); +#endif }).bind(this)); }, @@ -200,6 +273,7 @@ let DOMApplicationRegistry = { "icon": manifest.iconURLForSize(128), "description": description } + this.activitiesToRegister++; cpmm.sendAsyncMessage("Activities:Register", json); let launchPath = @@ -254,6 +328,9 @@ let DOMApplicationRegistry = { }, _processManifestForIds: function(aIds) { + this.activitiesToRegister = 0; + this.activitiesRegistered = 0; + this.allActivitiesSent = false; this._readManifests(aIds, (function registerManifests(aResults) { aResults.forEach(function registerManifest(aResult) { let app = this.webapps[aResult.id]; @@ -262,10 +339,7 @@ let DOMApplicationRegistry = { this._registerSystemMessages(manifest, app); this._registerActivities(manifest, app); }, this); - this.dirsLoaded++; - if (this.dirsLoaded == this.dirsToLoad) { - Services.obs.notifyObservers(this, "webapps-registry-ready", null); - } + this.allActivitiesSent = true; }).bind(this)); }, #endif @@ -393,6 +467,13 @@ let DOMApplicationRegistry = { case "Webapps:GetList": this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], mm); return this.webapps; + case "Activities:Register:OK": + this.activitiesRegistered++; + if (this.allActivitiesSent && + this.activitiesRegistered === this.activitiesToRegister) { + this.onInitDone(); + } + break; } }, diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 60e837b1041..efb043ae4a0 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3725,5 +3725,9 @@ pref("toolkit.identity.debug", false); // for them in their manifest. pref("dom.mozApps.dev_mode", false); -// Lowest localId for installed apps. -pref("dom.mozApps.maxLocalId", 10000); +// Lowest localId for apps. +pref("dom.mozApps.maxLocalId", 0); + +// Let us know wether we should run the permissions update algorithm. +// See Bug 787439 +pref("dom.mozApps.runUpdate", true);