зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1013433 - complete the packaged app update process; r=mfinkle,marco
This commit is contained in:
Родитель
aa5cdadcf0
Коммит
db078bd435
|
@ -1333,12 +1333,12 @@ this.DOMApplicationRegistry = {
|
|||
let app = this.webapps[id];
|
||||
if (!app) {
|
||||
debug("startDownload: No app found for " + aManifestURL);
|
||||
return;
|
||||
throw new Error("NO_SUCH_APP");
|
||||
}
|
||||
|
||||
if (app.downloading) {
|
||||
debug("app is already downloading. Ignoring.");
|
||||
return;
|
||||
throw new Error("APP_IS_DOWNLOADING");
|
||||
}
|
||||
|
||||
// If the caller is trying to start a download but we have nothing to
|
||||
|
@ -1352,7 +1352,7 @@ this.DOMApplicationRegistry = {
|
|||
eventType: "downloaderror",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
return;
|
||||
throw new Error("NO_DOWNLOAD_AVAILABLE");
|
||||
}
|
||||
|
||||
// First of all, we check if the download is supposed to update an
|
||||
|
@ -1409,7 +1409,7 @@ this.DOMApplicationRegistry = {
|
|||
if (!json) {
|
||||
debug("startDownload: No update manifest found at " + file.path + " " +
|
||||
aManifestURL);
|
||||
return;
|
||||
throw new Error("MISSING_UPDATE_MANIFEST");
|
||||
}
|
||||
|
||||
let manifest = new ManifestHelper(json, app.manifestURL);
|
||||
|
@ -1450,104 +1450,103 @@ this.DOMApplicationRegistry = {
|
|||
}
|
||||
}),
|
||||
|
||||
applyDownload: function applyDownload(aManifestURL) {
|
||||
applyDownload: Task.async(function*(aManifestURL) {
|
||||
debug("applyDownload for " + aManifestURL);
|
||||
let id = this._appIdForManifestURL(aManifestURL);
|
||||
let app = this.webapps[id];
|
||||
if (!app || (app && !app.readyToApplyDownload)) {
|
||||
return;
|
||||
if (!app) {
|
||||
throw new Error("NO_SUCH_APP");
|
||||
}
|
||||
if (!app.readyToApplyDownload) {
|
||||
throw new Error("NOT_READY_TO_APPLY_DOWNLOAD");
|
||||
}
|
||||
|
||||
// We need to get the old manifest to unregister web activities.
|
||||
this.getManifestFor(aManifestURL).then((aOldManifest) => {
|
||||
// Move the application.zip and manifest.webapp files out of TmpD
|
||||
let tmpDir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
|
||||
let manFile = tmpDir.clone();
|
||||
manFile.append("manifest.webapp");
|
||||
let appFile = tmpDir.clone();
|
||||
appFile.append("application.zip");
|
||||
let oldManifest = yield this.getManifestFor(aManifestURL);
|
||||
// Move the application.zip and manifest.webapp files out of TmpD
|
||||
let tmpDir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
|
||||
let manFile = tmpDir.clone();
|
||||
manFile.append("manifest.webapp");
|
||||
let appFile = tmpDir.clone();
|
||||
appFile.append("application.zip");
|
||||
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
appFile.moveTo(dir, "application.zip");
|
||||
manFile.moveTo(dir, "manifest.webapp");
|
||||
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
|
||||
appFile.moveTo(dir, "application.zip");
|
||||
manFile.moveTo(dir, "manifest.webapp");
|
||||
|
||||
// Move the staged update manifest to a non staged one.
|
||||
let staged = dir.clone();
|
||||
staged.append("staged-update.webapp");
|
||||
// Move the staged update manifest to a non staged one.
|
||||
let staged = dir.clone();
|
||||
staged.append("staged-update.webapp");
|
||||
|
||||
// If we are applying after a restarted download, we have no
|
||||
// staged update manifest.
|
||||
if (staged.exists()) {
|
||||
staged.moveTo(dir, "update.webapp");
|
||||
// If we are applying after a restarted download, we have no
|
||||
// staged update manifest.
|
||||
if (staged.exists()) {
|
||||
staged.moveTo(dir, "update.webapp");
|
||||
}
|
||||
|
||||
try {
|
||||
tmpDir.remove(true);
|
||||
} catch(e) { }
|
||||
|
||||
// Clean up the deprecated manifest cache if needed.
|
||||
if (id in this._manifestCache) {
|
||||
delete this._manifestCache[id];
|
||||
}
|
||||
|
||||
// Flush the zip reader cache to make sure we use the new application.zip
|
||||
// when re-launching the application.
|
||||
let zipFile = dir.clone();
|
||||
zipFile.append("application.zip");
|
||||
Services.obs.notifyObservers(zipFile, "flush-cache-entry", null);
|
||||
|
||||
// Get the manifest, and set properties.
|
||||
let newManifest = yield this.getManifestFor(aManifestURL);
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
app.downloadSize = 0;
|
||||
app.installState = "installed";
|
||||
app.readyToApplyDownload = false;
|
||||
|
||||
// Update the staged properties.
|
||||
if (app.staged) {
|
||||
for (let prop in app.staged) {
|
||||
app[prop] = app.staged[prop];
|
||||
}
|
||||
delete app.staged;
|
||||
}
|
||||
|
||||
try {
|
||||
tmpDir.remove(true);
|
||||
} catch(e) { }
|
||||
delete app.retryingDownload;
|
||||
|
||||
// Clean up the deprecated manifest cache if needed.
|
||||
if (id in this._manifestCache) {
|
||||
delete this._manifestCache[id];
|
||||
}
|
||||
// Update the asm.js scripts we need to compile.
|
||||
yield ScriptPreloader.preload(app, newManifest);
|
||||
yield this._saveApps();
|
||||
// Update the handlers and permissions for this app.
|
||||
this.updateAppHandlers(oldManifest, newManifest, app);
|
||||
|
||||
// Flush the zip reader cache to make sure we use the new application.zip
|
||||
// when re-launching the application.
|
||||
let zipFile = dir.clone();
|
||||
zipFile.append("application.zip");
|
||||
Services.obs.notifyObservers(zipFile, "flush-cache-entry", null);
|
||||
let updateManifest = yield AppsUtils.loadJSONAsync(staged.path);
|
||||
let appObject = AppsUtils.cloneAppObject(app);
|
||||
appObject.updateManifest = updateManifest;
|
||||
this.notifyUpdateHandlers(appObject, newManifest, appFile.path);
|
||||
|
||||
// Get the manifest, and set properties.
|
||||
this.getManifestFor(aManifestURL).then((aData) => {
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
app.downloadSize = 0;
|
||||
app.installState = "installed";
|
||||
app.readyToApplyDownload = false;
|
||||
|
||||
// Update the staged properties.
|
||||
if (app.staged) {
|
||||
for (let prop in app.staged) {
|
||||
app[prop] = app.staged[prop];
|
||||
}
|
||||
delete app.staged;
|
||||
}
|
||||
|
||||
delete app.retryingDownload;
|
||||
|
||||
// Update the asm.js scripts we need to compile.
|
||||
ScriptPreloader.preload(app, aData)
|
||||
.then(() => this._saveApps()).then(() => {
|
||||
// Update the handlers and permissions for this app.
|
||||
this.updateAppHandlers(aOldManifest, aData, app);
|
||||
|
||||
AppsUtils.loadJSONAsync(staged.path).then((aUpdateManifest) => {
|
||||
let appObject = AppsUtils.cloneAppObject(app);
|
||||
appObject.updateManifest = aUpdateManifest;
|
||||
this.notifyUpdateHandlers(appObject, aData, appFile.path);
|
||||
});
|
||||
|
||||
if (supportUseCurrentProfile()) {
|
||||
PermissionsInstaller.installPermissions(
|
||||
{ manifest: aData,
|
||||
origin: app.origin,
|
||||
manifestURL: app.manifestURL },
|
||||
true);
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, aData, app.appStatus);
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aData,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
});
|
||||
});
|
||||
if (supportUseCurrentProfile()) {
|
||||
PermissionsInstaller.installPermissions(
|
||||
{ manifest: newManifest,
|
||||
origin: app.origin,
|
||||
manifestURL: app.manifestURL },
|
||||
true);
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, newManifest, app.appStatus);
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: newManifest,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
},
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
}),
|
||||
|
||||
startOfflineCacheDownload: function(aManifest, aApp, aProfileDir, aIsUpdate) {
|
||||
if (!aManifest.appcache_path) {
|
||||
|
@ -2773,9 +2772,11 @@ this.DOMApplicationRegistry = {
|
|||
if (oldPackage) {
|
||||
debug("package's etag or hash unchanged; sending 'applied' event");
|
||||
// The package's Etag or hash has not changed.
|
||||
// We send a "applied" event right away.
|
||||
// We send an "applied" event right away so code awaiting that event
|
||||
// can proceed to access the app. We also throw an error to alert
|
||||
// the caller that the package wasn't downloaded.
|
||||
this._sendAppliedEvent(aNewApp, oldApp, id);
|
||||
return;
|
||||
throw new Error("PACKAGE_UNCHANGED");
|
||||
}
|
||||
|
||||
let newManifest = yield this._openAndReadPackage(zipFile, oldApp, aNewApp,
|
||||
|
@ -3488,6 +3489,8 @@ this.DOMApplicationRegistry = {
|
|||
});
|
||||
});
|
||||
AppDownloadManager.remove(aNewApp.manifestURL);
|
||||
|
||||
throw aError;
|
||||
},
|
||||
|
||||
doUninstall: function(aData, aMm) {
|
||||
|
|
|
@ -158,37 +158,46 @@ this.WebappManager = {
|
|||
return deferred.promise;
|
||||
},
|
||||
|
||||
askInstall: function(aData) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(aData.profilePath);
|
||||
|
||||
_deleteAppcachePath: function(aManifest) {
|
||||
// We don't yet support pre-installing an appcache because it isn't clear
|
||||
// how to do it without degrading the user experience (since users expect
|
||||
// apps to be available after the system tells them they've been installed,
|
||||
// which has already happened) and because nsCacheService shuts down
|
||||
// when we trigger the native install dialog and doesn't re-init itself
|
||||
// afterward (TODO: file bug about this behavior).
|
||||
if ("appcache_path" in aData.app.manifest) {
|
||||
debug("deleting appcache_path from manifest: " + aData.app.manifest.appcache_path);
|
||||
delete aData.app.manifest.appcache_path;
|
||||
if ("appcache_path" in aManifest) {
|
||||
debug("deleting appcache_path from manifest: " + aManifest.appcache_path);
|
||||
delete aManifest.appcache_path;
|
||||
}
|
||||
},
|
||||
|
||||
askInstall: function(aData) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(aData.profilePath);
|
||||
|
||||
this._deleteAppcachePath(aData.app.manifest);
|
||||
|
||||
DOMApplicationRegistry.registryReady.then(() => {
|
||||
DOMApplicationRegistry.confirmInstall(aData, file, (function(aManifest) {
|
||||
let localeManifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
|
||||
// aData.app.origin may now point to the app: url that hosts this app.
|
||||
sendMessageToJava({
|
||||
type: "Webapps:Postinstall",
|
||||
apkPackageName: aData.app.apkPackageName,
|
||||
origin: aData.app.origin,
|
||||
});
|
||||
|
||||
this.writeDefaultPrefs(file, localeManifest);
|
||||
this._postInstall(aData.profilePath, aManifest, aData.app.origin, aData.app.apkPackageName);
|
||||
}).bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
_postInstall: function(aProfilePath, aNewManifest, aOrigin, aApkPackageName) {
|
||||
// aOrigin may now point to the app: url that hosts this app.
|
||||
sendMessageToJava({
|
||||
type: "Webapps:Postinstall",
|
||||
apkPackageName: aApkPackageName,
|
||||
origin: aOrigin,
|
||||
});
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(aProfilePath);
|
||||
let localeManifest = new ManifestHelper(aNewManifest, aOrigin);
|
||||
this.writeDefaultPrefs(file, localeManifest);
|
||||
},
|
||||
|
||||
launch: function({ manifestURL, origin }) {
|
||||
debug("launchWebapp: " + manifestURL);
|
||||
|
||||
|
@ -211,11 +220,16 @@ this.WebappManager = {
|
|||
},
|
||||
|
||||
autoInstall: function(aData) {
|
||||
let oldApp = DOMApplicationRegistry.getAppByManifestURL(aData.manifestURL);
|
||||
if (oldApp) {
|
||||
// If the app is already installed, update the existing installation.
|
||||
this._autoUpdate(aData, oldApp);
|
||||
return;
|
||||
debug("autoInstall " + aData.manifestURL);
|
||||
|
||||
// If the app is already installed, update the existing installation.
|
||||
// We should be able to use DOMApplicationRegistry.getAppByManifestURL,
|
||||
// but it returns a mozIApplication, while _autoUpdate needs the original
|
||||
// object from DOMApplicationRegistry.webapps in order to modify it.
|
||||
for (let [ , app] in Iterator(DOMApplicationRegistry.webapps)) {
|
||||
if (app.manifestURL == aData.manifestURL) {
|
||||
return this._autoUpdate(aData, app);
|
||||
}
|
||||
}
|
||||
|
||||
let mm = {
|
||||
|
@ -276,13 +290,39 @@ this.WebappManager = {
|
|||
}
|
||||
|
||||
if (aData.type == "hosted") {
|
||||
this._deleteAppcachePath(aData.manifest);
|
||||
let oldManifest = yield DOMApplicationRegistry.getManifestFor(aData.manifestURL);
|
||||
DOMApplicationRegistry.updateHostedApp(aData, aOldApp.id, aOldApp, oldManifest, aData.manifest);
|
||||
yield DOMApplicationRegistry.updateHostedApp(aData, aOldApp.id, aOldApp, oldManifest, aData.manifest);
|
||||
} else {
|
||||
DOMApplicationRegistry.updatePackagedApp(aData, aOldApp.id, aOldApp, aData.manifest);
|
||||
yield this._autoUpdatePackagedApp(aData, aOldApp);
|
||||
}
|
||||
|
||||
this._postInstall(aData.profilePath, aData.manifest, aOldApp.origin, aOldApp.apkPackageName);
|
||||
}).bind(this)); },
|
||||
|
||||
_autoUpdatePackagedApp: Task.async(function*(aData, aOldApp) {
|
||||
debug("_autoUpdatePackagedApp: " + aData.manifestURL);
|
||||
|
||||
if (aData.updateManifest && aData.zipFilePath) {
|
||||
aData.updateManifest.package_path = aData.zipFilePath;
|
||||
}
|
||||
|
||||
// updatePackagedApp just prepares the update, after which we must
|
||||
// download the package via the misnamed startDownload and then apply it
|
||||
// via applyDownload.
|
||||
yield DOMApplicationRegistry.updatePackagedApp(aData, aOldApp.id, aOldApp, aData.updateManifest);
|
||||
|
||||
try {
|
||||
yield DOMApplicationRegistry.startDownload(aData.manifestURL);
|
||||
} catch (ex if ex.message == "PACKAGE_UNCHANGED") {
|
||||
debug("package unchanged");
|
||||
// If the package is unchanged, then there's nothing more to do.
|
||||
return;
|
||||
}
|
||||
|
||||
yield DOMApplicationRegistry.applyDownload(aData.manifestURL);
|
||||
}),
|
||||
|
||||
_checkingForUpdates: false,
|
||||
|
||||
checkForUpdates: function(userInitiated) { return Task.spawn((function*() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче