Bug 778079 - Support loading app packages from multiple locations [r=vingtetun]

This commit is contained in:
Fabrice Desré 2012-08-29 14:20:03 -07:00
Родитель 009e165d07
Коммит 6c2d0b1566
6 изменённых файлов: 95 добавлений и 54 удалений

Просмотреть файл

@ -23,14 +23,19 @@ DirectoryProvider.prototype = {
getFile: function dp_getFile(prop, persistent) {
#ifdef MOZ_WIDGET_GONK
let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir",
"permissionDBPDir", "UpdRootD"];
"permissionDBPDir", "UpdRootD"];
if (localProps.indexOf(prop) != -1) {
prop.persistent = true;
let file = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile)
file.initWithPath(LOCAL_DIR);
persistent.value = true;
return file;
}
} else if (prop == "coreAppsDir") {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
file.initWithPath("/system/b2g");
persistent.value = true;
return file;
}
#endif
return null;

Просмотреть файл

@ -30,6 +30,7 @@ let AppsUtils = {
installTime: aApp.installTime,
manifestURL: aApp.manifestURL,
appStatus: aApp.appStatus,
removable: aApp.removable,
localId: aApp.localId,
progress: aApp.progress || 0.0,
status: aApp.status || "installed"

Просмотреть файл

@ -20,8 +20,7 @@ function convertAppsArray(aApps, aWindow) {
let apps = Cu.createArrayIn(aWindow);
for (let i = 0; i < aApps.length; i++) {
let app = aApps[i];
apps.push(createApplicationObject(aWindow, app.origin, app.manifest, app.manifestURL,
app.receipts, app.installOrigin, app.installTime));
apps.push(createApplicationObject(aWindow, app));
}
return apps;
@ -73,8 +72,7 @@ WebappsRegistry.prototype = {
let app = msg.app;
switch (aMessage.name) {
case "Webapps:Install:Return:OK":
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
break;
case "Webapps:Install:Return:KO":
Services.DOMRequest.fireError(req, msg.error || "DENIED");
@ -82,8 +80,7 @@ WebappsRegistry.prototype = {
case "Webapps:GetSelf:Return:OK":
if (msg.apps.length) {
app = msg.apps[0];
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime));
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
} else {
Services.DOMRequest.fireSuccess(req, null);
}
@ -223,9 +220,9 @@ WebappsRegistry.prototype = {
* mozIDOMApplication object
*/
function createApplicationObject(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
function createApplicationObject(aWindow, aApp) {
let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
app.wrappedJSObject.init(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime);
app.wrappedJSObject.init(aWindow, aApp);
return app;
}
@ -246,20 +243,24 @@ WebappsApplication.prototype = {
onprogress: 'rw',
launch: 'r',
receipts: 'r',
removable: 'r',
uninstall: 'r'
},
init: function(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
this.origin = aOrigin;
this.manifest = ObjectWrapper.wrap(aManifest, aWindow);
this.manifestURL = aManifestURL;
this.receipts = aReceipts;
this.installOrigin = aInstallOrigin;
this.installTime = aInstallTime;
init: function(aWindow, aApp) {
this.origin = aApp.origin;
this.manifest = ObjectWrapper.wrap(aApp.manifest, aWindow);
this.manifestURL = aApp.manifestURL;
this.receipts = aApp.receipts;
this.installOrigin = aApp.installOrigin;
this.installTime = aApp.installTime;
this.status = "installed";
this.removable = aApp.removable;
this.progress = NaN;
this._onprogress = null;
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", "Webapps:OfflineCache"]);
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Return:KO",
"Webapps:OfflineCache"]);
},
set onprogress(aCallback) {
@ -422,15 +423,14 @@ WebappsApplicationMgmt.prototype = {
if (this._oninstall) {
let app = msg.app;
let event = new this._window.MozApplicationEvent("applicationinstall",
{ application : createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
app.installOrigin, app.installTime) });
{ application : createApplicationObject(this._window, app) });
this._oninstall.handleEvent(event);
}
break;
case "Webapps:Uninstall:Return:OK":
if (this._onuninstall) {
let event = new this._window.MozApplicationEvent("applicationuninstall",
{ application : createApplicationObject(this._window, msg.origin, null, null, null, null, 0) });
{ application : createApplicationObject(this._window, { origin: msg.origin }) });
this._onuninstall.handleEvent(event);
}
break;

Просмотреть файл

@ -71,24 +71,41 @@ let DOMApplicationRegistry = {
this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
["webapps", "webapps.json"], true);
if (this.appsFile.exists()) {
this._loadJSONAsync(this.appsFile, (function(aData) {
this.webapps = aData;
for (let id in this.webapps) {
#ifdef MOZ_SYS_MSG
this._processManifestForId(id);
#endif
if (!this.webapps[id].localId) {
this.webapps[id].localId = this._nextLocalId();
}
let dirList = [DIRECTORY_NAME];
// Default to a non privileged status.
if (this.webapps[id].appStatus === undefined) {
this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
#ifdef MOZ_WIDGET_GONK
dirList.push("coreAppsDir");
#endif
let currentId = 1;
dirList.forEach((function(dir) {
let curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], true);
if (curFile.exists()) {
let appDir = FileUtils.getDir(dir, ["webapps"]);
this._loadJSONAsync(curFile, (function(aData) {
if (!aData) {
return;
}
};
}).bind(this));
}
// 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
this._processManifestForId(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++;
}
};
}).bind(this));
}
}).bind(this));
try {
let hosts = Services.prefs.getCharPref("dom.mozApps.whitelist");
@ -254,7 +271,7 @@ let DOMApplicationRegistry = {
this.installPackage(msg);
break;
case "Webapps:GetBasePath":
return FileUtils.getFile(DIRECTORY_NAME, ["webapps"], true).path;
return this.webapps[msg.id].basePath;
break;
case "Webapps:GetList":
this.children.push(aMessage.target);
@ -262,6 +279,11 @@ let DOMApplicationRegistry = {
}
},
_getAppDir: function(aId) {
FileUtils.getDir(this.webapps[aId].removable ? DIRECTORY_NAME : "coreAppsDir",
["webapps", aId], true, true);
},
_writeFile: function ss_writeFile(aFile, aData, aCallbak) {
// Initialize the file output stream.
let ostream = FileUtils.openSafeFileOutputStream(aFile);
@ -294,12 +316,13 @@ let DOMApplicationRegistry = {
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
let app = aData.app;
app.removable = true;
let id = app.syncId || this._appId(app.origin);
let localId = this.getAppLocalIdByManifestURL(app.manifestURL);
// Installing an application again is considered as an update.
if (id) {
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
let dir = this._getAppDir(id);
try {
dir.remove(true);
} catch(e) {
@ -375,7 +398,8 @@ let DOMApplicationRegistry = {
},
_nextLocalId: function() {
let maxLocalId = Ci.nsIScriptSecurityManager.NO_APP_ID;
// All installed apps have a localId > 1000.
let maxLocalId = 1000;
for (let id in this.webapps) {
if (this.webapps[id].localId > maxLocalId) {
@ -419,9 +443,10 @@ let DOMApplicationRegistry = {
let id = aData[index].id;
// the manifest file used to be named manifest.json, so fallback on this.
let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.webapp"], true);
let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir");
let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true);
if (!file.exists()) {
file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.json"], true);
file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.json"], true);
}
this._loadJSONAsync(file, (function(aJSON) {
@ -598,6 +623,9 @@ let DOMApplicationRegistry = {
continue;
}
if (!this.webapps[id].removable)
return;
found = true;
let appNote = JSON.stringify(AppsUtils.cloneAppObject(app));
appNote.id = id;
@ -608,7 +636,7 @@ let DOMApplicationRegistry = {
#endif
}).bind(this));
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
let dir = this._getAppDir(id);
try {
dir.remove(true);
} catch (e) {}
@ -761,11 +789,11 @@ let DOMApplicationRegistry = {
for (let i = 0; i < aRecords.length; i++) {
let record = aRecords[i];
if (record.hidden) {
if (!this.webapps[record.id])
if (!this.webapps[record.id] || !this.webapps[record.id].removable)
continue;
let origin = this.webapps[record.id].origin;
delete this.webapps[record.id];
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", record.id], true, true);
let dir = this._getAppDir(record.id);
try {
dir.remove(true);
} catch (e) {
@ -798,8 +826,12 @@ let DOMApplicationRegistry = {
wipe: function(aCallback) {
let ids = this.getAllIDs();
for (let id in ids) {
if (!this.webapps[id].removable) {
continue;
}
delete this.webapps[id];
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
let dir = this._getAppDir(id);
try {
dir.remove(true);
} catch (e) {

Просмотреть файл

@ -8,7 +8,7 @@
interface nsIDOMDOMRequest;
interface nsIArray;
[scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)]
[scriptable, uuid(e3649c1d-c950-495e-b0ed-6ce40be9743b)]
interface mozIDOMApplication : nsISupports
{
readonly attribute jsval manifest;
@ -17,6 +17,7 @@ interface mozIDOMApplication : nsISupports
readonly attribute DOMString origin;
readonly attribute DOMString installOrigin;
readonly attribute unsigned long long installTime;
readonly attribute boolean removable;
/*
* The current progress when downloading an offline cache.

Просмотреть файл

@ -16,7 +16,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"nsISyncMessageSender");
function AppProtocolHandler() {
this._basePath = null;
this._basePath = [];
}
AppProtocolHandler.prototype = {
@ -30,12 +30,14 @@ AppProtocolHandler.prototype = {
Ci.nsIProtocolHandler.URI_NOAUTH |
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
get basePath() {
if (!this._basePath) {
this._basePath = cpmm.sendSyncMessage("Webapps:GetBasePath", { })[0] + "/";
getBasePath: function app_phGetBasePath(aId) {
if (!this._basePath[aId]) {
this._basePath[aId] = cpmm.sendSyncMessage("Webapps:GetBasePath",
{ id: aId })[0] + "/";
}
return this._basePath;
return this._basePath[aId];
},
newURI: function app_phNewURI(aSpec, aOriginCharset, aBaseURI) {
@ -60,7 +62,7 @@ AppProtocolHandler.prototype = {
}
// Build a jar channel and masquerade as an app:// URI.
let uri = "jar:file://" + this.basePath + appId + "/application.zip!" + fileSpec;
let uri = "jar:file://" + this.getBasePath(appId) + appId + "/application.zip!" + fileSpec;
let channel = Services.io.newChannel(uri, null, null);
channel.QueryInterface(Ci.nsIJARChannel).setAppURI(aURI);
channel.QueryInterface(Ci.nsIChannel).originalURI = aURI;