前面分析了这么多,还没有真正的走到download流程。这篇就去了解真正的downloader。
1. UpdateService.downloadUpdate
看来这正的worker就是最后new出来的Downloader。
downloadUpdate: function AUS_downloadUpdate(update, background) { if (!update) throw Cr.NS_ERROR_NULL_POINTER; // Don‘t download the update if the update‘s version is less than the // current application‘s version or the update‘s version is the same as the // application‘s version and the build ID is the same as the application‘s // build ID. if (update.appVersion && (Services.vc.compare(update.appVersion, Services.appinfo.version) < 0 || update.buildID && update.buildID == Services.appinfo.appBuildID && update.appVersion == Services.appinfo.version)) { LOG("UpdateService:downloadUpdate - canceling download of update since " + "it is for an earlier or same application version and build ID.\n" + "current application version: " + Services.appinfo.version + "\n" + "update application version : " + update.appVersion + "\n" + "current build ID: " + Services.appinfo.appBuildID + "\n" + "update build ID : " + update.buildID); cleanupActiveUpdate(); return STATE_NONE; } // If a download request is in progress vs. a download ready to resume if (this.isDownloading) { if (update.isCompleteUpdate == this._downloader.isCompleteUpdate && background == this._downloader.background) { LOG("UpdateService:downloadUpdate - no support for downloading more " + "than one update at a time"); return readStatusFile(getUpdatesDir()); } this._downloader.cancel(); } if (AppConstants.platform == "gonk") { let um = Cc["@mozilla.org/updates/update-manager;1"]. getService(Ci.nsIUpdateManager); let activeUpdate = um.activeUpdate; if (activeUpdate && (activeUpdate.appVersion != update.appVersion || activeUpdate.buildID != update.buildID)) { // We have an activeUpdate (which presumably was interrupted), and are // about start downloading a new one. Make sure we remove all traces // of the active one (otherwise we‘ll start appending the new update.mar // the the one that‘s been partially downloaded). LOG("UpdateService:downloadUpdate - removing stale active update."); cleanupActiveUpdate(); } } // Set the previous application version prior to downloading the update. update.previousAppVersion = Services.appinfo.version; this._downloader = new Downloader(background, this); return this._downloader.downloadUpdate(update); },
2. Downloader.downloadUpdate
由于downloadUpdate函数比较长,这里只贴出部分代码
/** * Download and stage the given update. * @param update * A nsIUpdate object to download a patch for. Cannot be null. */ downloadUpdate: function Downloader_downloadUpdate(update) { ... // 获取update保存位置 var updateDir = getUpdatesDir(); ... //根据预设的policy,返回Update中的一个UpdatePatch以下载 this._patch = this._selectPatch(update, updateDir); ...
// Only used by gonk
let status = STATE_NONE;
if (AppConstants.platform == "gonk") {
...
// 检测之前是否有interrupted update
} ... // 获取patch的URL var uri = Services.io.newURI(this._patch.URL, null, null); // 创建一个nsIIncrementalDownload组件去下载 this._request = Cc["@mozilla.org/network/incremental-download;1"].createInstance(Ci.nsIIncrementalDownload);
LOG("Downloader:downloadUpdate - downloading from " + uri.spec + " to " + patchFile.path);
var interval = this.background ? getPref("getIntPref",
PREF_APP_UPDATE_BACKGROUND_INTERVAL, DOWNLOAD_BACKGROUND_INTERVAL) : DOWNLOAD_FOREGROUND_INTERVAL;
this._request.init(uri, patchFile, DOWNLOAD_CHUNK_SIZE, interval);
//传递了this,因为Downloader实现了nsIRequest和nsIProcessEventSink接口,实现下载完成、下载进度等的回调
this._request.start(this, null);
writeStatusFile(updateDir, STATE_DOWNLOADING);
this._patch.QueryInterface(Ci.nsIWritablePropertyBag);
this._patch.state = STATE_DOWNLOADING;
// 通过UpdateManager保存当前的下载update
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager);
um.saveUpdates();
return STATE_DOWNLOADING;
}
3. Downloader.onStopRequest 下载完成
代码很长,贴关键部分
/** * When data transfer ceases * @param request * The nsIRequest object for the transfer * @param context * Additional data * @param status * Status code containing the reason for the cessation. */ onStopRequest: function Downloader_onStopRequest(request, context, status) { // 判断是否下载成功 if (Components.isSuccessCode(status)) { // 验证update package if (this._verifyDownload()) { ... } } else { ... } ... this._patch.state = state; // UpdateManager保存状态 var um = Cc["@mozilla.org/updates/update-manager;1"]. getService(Ci.nsIUpdateManager); if (deleteActiveUpdate) { this._update.installDate = (new Date()).getTime(); um.activeUpdate = null; } else { if (um.activeUpdate) { um.activeUpdate.state = state; } } um.saveUpdates(); ... if (shouldShowPrompt) { // Notify the user that an update has been downloaded and is ready for // installation (i.e. that they should restart the application). We do // not notify on failed update attempts. let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. createInstance(Ci.nsIUpdatePrompt); // 通知UpdatePrompt,update下载完成 prompter.showUpdateDownloaded(this._update, true); } }