• (FFOS Gecko & Gaia) OTA


      虽然代码分析了很多,但是还没有真正做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;
    },
  • 相关阅读:
    经典哦,男女3.8,8.3
    在web窗体设计器中未能加载该文件
    使用客户端脚本
    C#的数据类型
    实验下cookie
    C#中Split分隔字符串的应用
    未将对象引用设置到对象的实例
    System.StackOverflowException 的异常;jit调试失败
    DataGrid中添加删除确认对话框 多种实现
    常用正则表达式
  • 原文地址:https://www.cnblogs.com/code-4-fun/p/4704077.html
Copyright © 2020-2023  润新知