您的位置:首页 > 大数据 > 人工智能

(FFOS Gecko & Gaia) OTA - Do real check

2015-08-05 10:45 344 查看
  虽然代码分析了很多,但是还没有真正做check的工作,下面就来找到真正的checker。

  代码位置:gecko/toolkit/mozapps/update/nsUpdateService.js。参考之前的(FFOS Gecko & Gaia) OTA - 代码模块总览,nsUpdateService.js中的Checker对象,实现了nsIUpdateChecker这个interface。下面就来分析Checker对象的实现。

1. checkForUpdates函数:

  实现略长,在代码中添加注释分析。

checkForUpdates: function UC_checkForUpdates(listener, force) {
LOG("Checker: checkForUpdates, force: " + force);
if (!listener)
throw Cr.NS_ERROR_NULL_POINTER;

  // 通知'update-check-start'事件,监听者是谁呢?还记得上一篇分析的UpdatePrompt实现了nsIObserver吗?
Services.obs.notifyObservers(null, "update-check-start", null);

 // 这个函数很重要,它通过获取很多settings和preferences,还会通过libutils库,来获取很多系统参数,拼接成一个url,
// 这个url就是OTA server URL
var url = this.getUpdateURL(force);
if (!url || (!this.enabled && !force))
return;

// 通过XHR发送GET请求,获取update信息
this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsISupports);
// This is here to let unit test code override XHR
if (this._request.wrappedJSObject) {
this._request = this._request.wrappedJSObject;
}
this._request.open("GET", url, true);
var allowNonBuiltIn = !getPref("getBoolPref",
PREF_APP_UPDATE_CERT_REQUIREBUILTIN, true);
this._request.channel.notificationCallbacks = new gCertUtils.BadCertHandler(allowNonBuiltIn);
// Prevent the request from reading from the cache.
this._request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
// Prevent the request from writing to the cache.
this._request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;

this._request.overrideMimeType("text/xml");
// The Cache-Control header is only interpreted by proxies and the
// final destination. It does not help if a resource is already
// cached locally.
this._request.setRequestHeader("Cache-Control", "no-cache");
// HTTP/1.0 servers might not implement Cache-Control and
// might only implement Pragma: no-cache
this._request.setRequestHeader("Pragma", "no-cache");

var self = this;
// 设置XHR event listener
this._request.addEventListener("error", function(event) { self.onError(event); } ,false);
this._request.addEventListener("load", function(event) { self.onLoad(event); }, false);

LOG("Checker:checkForUpdates - sending request to: " + url);
this._request.send(null);
// 将传进来的listener保存下来,在XHR的event handler中回调
this._callback = listener;
},


2. onLoad函数

  当request请求返回时,会回调onLoad函数

onLoad: function UC_onLoad(event) {
LOG("Checker:onLoad - request completed downloading document");

var prefs = Services.prefs;
var certs = null;
if (!getPref("getCharPref", PREF_APP_UPDATE_URL_OVERRIDE, null) &&
getPref("getBoolPref", PREF_APP_UPDATE_CERT_CHECKATTRS, true)) {
certs = gCertUtils.readCertPrefs(PREF_APP_UPDATE_CERTS_BRANCH);
}

try {
// Analyze the resulting DOM and determine the set of updates.
  // 之前没有找到对于request response解析的部分,其实秘密就在于这里,Checker中并没有显示的定义_updates属性,而是定义了一个get _updates()函数。
   // 这是js的特性,如果定义了get/set property()函数,就表示可以get/set这个以property命名的属性。

var updates = this._updates;
LOG("Checker:onLoad - number of updates available: " + updates.length);
var allowNonBuiltIn = !getPref("getBoolPref",
PREF_APP_UPDATE_CERT_REQUIREBUILTIN, true);
gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs);

if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS))
Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_ERRORS);

if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS))
Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS);

// Tell the callback about the updates

this._callback.onCheckComplete(event.target, updates, updates.length);
}
catch (e) {
LOG("Checker:onLoad - there was a problem checking for updates. " +
"Exception: " + e);
var request = event.target;
var status = this._getChannelStatus(request);
LOG("Checker:onLoad - request.status: " + status);
var update = new Update(null);
update.errorCode = status;
update.statusText = getStatusTextFromCode(status, 404);

if (this._isHttpStatusCode(status)) {
update.errorCode = HTTP_ERROR_OFFSET + status;
}
if (e.result && e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
update.errorCode = updates[0] ? CERT_ATTR_CHECK_FAILED_HAS_UPDATE
: CERT_ATTR_CHECK_FAILED_NO_UPDATE;
}

this._callback.onError(request, update);
}

this._callback = null;
this._request = null;
},


3. get _updates()函数

  解析request response,根据mozilla的文档,这个response是一个update.xml文件,具体的格式请参考https://wiki.mozilla.org/Software_Update:updates.xml_Format

  通过解析update.xml文件,返回一个nsIUpdate数组,也就是Update对象的数组。Update的构造函数又会解析update.xml中的所有patch标签,每个patch标签会对应的生成一个nsIUpdatePatch,也就是UpdatePatch,也就是说Update对象里会包含1-多个UpdatePatch对象,并且Update对象里会保存一些其他的信息,比如是否为OS Update等,具体的解析过程请参考代码。


/**
  * Returns an array of nsIUpdate objects discovered by the update check.
  * @throws if the XML document element node name is not updates.
  */

get _updates() {
var updatesElement = this._request.responseXML.documentElement;
if (!updatesElement) {
LOG("Checker:_updates get - empty updates document?!");
return [];
}

if (updatesElement.nodeName != "updates") {
LOG("Checker:_updates get - unexpected node name!");
throw new Error("Unexpected node name, expected: updates, got: " +
updatesElement.nodeName);
}

const ELEMENT_NODE = Ci.nsIDOMNode.ELEMENT_NODE;
var updates = [];
for (var i = 0; i < updatesElement.childNodes.length; ++i) {
var updateElement = updatesElement.childNodes.item(i);
if (updateElement.nodeType != ELEMENT_NODE ||
updateElement.localName != "update")
continue;

updateElement.QueryInterface(Ci.nsIDOMElement);
let update;
try {
update = new Update(updateElement);
} catch (e) {
LOG("Checker:_updates get - invalid <update/>, ignoring...");
continue;
}
update.serviceURL = this.getUpdateURL(this._forced);
update.channel = UpdateChannel.get();
updates.push(update);
}
return updates;
},
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: