~ubuntu-branches/ubuntu/vivid/ubufox/vivid-proposed

« back to all changes in this revision

Viewing changes to components/UpdateNotifier.js

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-08-16 22:01:18 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20120816220118-8tdzm0pcvhnj50kh
Tags: 2.4~r353-0ubuntu1
* New upstream snapshot
  - Make the plugin update restart notification work again, after a change
    in the plugin host broke it

Show diffs side-by-side

added added

removed removed

Lines of Context:
73
73
  var listeners = [];
74
74
  var watches = {};
75
75
  var timers = {};
76
 
  var dispatched = {};
 
76
  var dispatched = [];
77
77
  var plugins = {};
78
78
 
79
79
  /**
125
125
    listeners.splice(index, 1);
126
126
  };
127
127
 
128
 
  function dispatchNotification() {
129
 
    let event = arguments[0];
130
 
    let args = Array.prototype.slice.call(arguments, 1);
131
 
    dispatched[event] = args;
 
128
  function dispatchNotification(aEvent) {
 
129
    if (dispatched.indexOf(aEvent) != -1) {
 
130
      return;
 
131
    }
 
132
 
 
133
    dispatched.push(aEvent);
132
134
 
133
135
    listeners.forEach(function(listener) {
134
136
      try {
135
 
        if (event in listener) {
136
 
          listener[event].apply(listener, args);
 
137
        if (aEvent in listener) {
 
138
          listener[aEvent].apply(listener);
137
139
        }
138
140
      } catch(e) {
139
141
        Cu.reportError(e);
142
144
  }
143
145
 
144
146
  function handleAppUpdated() {
145
 
    if (!("onAppUpdated" in dispatched)) {
146
 
      dispatchNotification("onAppUpdated");
147
 
    }
 
147
    LOG("Application change detected");
 
148
    dispatchNotification("onAppUpdated");
148
149
  }
149
150
 
150
151
  function handlePluginsChanged() {
 
152
    LOG("Plugin change detected");
151
153
    let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
152
154
 
153
155
    try {
154
156
      ph.reloadPlugins(false);
155
 
    } catch(e) { return; }
156
 
 
157
 
    let oldPluginNamesByPath = {};
158
 
    for (let name in plugins) {
159
 
      oldPluginNamesByPath[plugins[name].path] = name;
 
157
    } catch(e) {
 
158
      LOG("nsIPluginHost.reloadPlugins failed. No changes?");
 
159
      return;
160
160
    }
161
161
 
162
162
    // Here's how this works:
163
 
    // - We iterate over the updated list of plugin tags
 
163
    // - We iterate over the updated list of plugin tags from the plugin host
164
164
    // - For each plugin tag, we check if we have old data for that plugin,
165
 
    //   first looking up by name and then by path (we use name in case
166
 
    //   the install location changed but fall back to path in case the new
167
 
    //   name is different. Obviously, we won't identify the old plugin data
168
 
    //   if the update has a new path and name - in this case, we will mistake
169
 
    //   it as a new install. Oh well...)
170
 
    // - We keep a count of how many plugin tags there are for each plugin.
 
165
    //   looking up by path
 
166
    // - We then pass over and new plugin data that hasn't been paired with
 
167
    //   old data, and see if it matches any old data by name. This is to handle
 
168
    //   plugin upgrades where the install path changes. We do this in
 
169
    //   a separate pass in case there is more than one plugin with the same
 
170
    //   name. In this case, we can still get a match if only one of those
 
171
    //   is updated.
 
172
    // - Obviously, if a plugin update changes its path and name, we detect
 
173
    //   that as a new install
171
174
    // - For each plugin, we compare the newest mtime with the recorded mtime
172
175
    //   from the old plugin data (if it exists). If the old data exists and the
173
176
    //   mtime is different, then the plugin was updated
174
 
    // - If there is more than one plugin tag for a plugin, this means that the
175
 
    //   old version of a plugin might still be in use. In this case, we
176
 
    //   require a restart. If there is only one plugin tag for an updated
177
 
    //   plugin, then the old version is definitely not in use and the next
178
 
    //   use of this plugin will pick up the new version without requiring
179
 
    //   a restart
180
 
    let seenPlugins = {};
181
 
    for each (let pluginTag in ph.getPluginTags()) {
182
 
      let oldPluginData;
183
 
      if (!(pluginTag.name in plugins)) {
184
 
        oldPluginData = plugins[oldPluginNamesByPath[pluginTag.fullpath]];
185
 
      } else {
186
 
        oldPluginData = plugins[pluginTag.name];
187
 
      }
188
 
 
189
 
      if (!(pluginTag.name in seenPlugins)) {
190
 
        seenPlugins[pluginTag.name] = {
 
177
    let newPlugins = {};
 
178
    ph.getPluginTags().forEach(function(pluginTag) {
 
179
      LOG("Processing plugin \"" + pluginTag.name + "\" at " +
 
180
          pluginTag.fullpath);
 
181
 
 
182
      if (pluginTag.fullpath in plugins) {
 
183
        var oldPluginData = plugins[pluginTag.fullpath];
 
184
        delete plugins[pluginTag.fullpath];
 
185
      }
 
186
 
 
187
      if (oldPluginData) {
 
188
        LOG("Found old data for plugin with the same path (\"" +
 
189
            oldPluginData.name + "\", lastModifiedTime " +
 
190
            oldPluginData.lastModifiedTime + ")");
 
191
      }
 
192
 
 
193
      if (!(pluginTag.fullpath in newPlugins)) {
 
194
        let plugin = {
191
195
          "pluginData": {
192
196
            "path": pluginTag.fullpath,
193
 
            "lastModifiedTime": (new FileUtils.File(pluginTag.fullpath))
194
 
                                              .lastModifiedTime
 
197
            "name": pluginTag.name
195
198
          },
196
 
          "count": 1,
197
199
          "oldPluginData": oldPluginData
198
 
        }
199
 
      } else {
200
 
        ++seenPlugins[pluginTag.name].count;
201
 
        if (pluginTag.fullpath !=
202
 
            seenPlugins[pluginTag.name].pluginData.path) {
203
 
          let mtime = (new FileUtils.File(pluginTag.fullpath))
204
 
                                    .lastModifiedTime;
205
 
          if (mtime > seenPlugins[pluginTag.name].pluginData
206
 
                                                 .lastModifiedTime) {
207
 
            seenPlugins[pluginTag.name].pluginData.path = pluginTag.fullpath;
208
 
            seenPlugins[pluginTag.name].pluginData.lastModifiedTime = mtime;
209
 
          }
210
 
        }
211
 
      }
212
 
    }
 
200
        };
 
201
 
 
202
        newPlugins[pluginTag.fullpath] = plugin;
 
203
 
 
204
        try {
 
205
          plugin.pluginData.lastModifiedTime = (new FileUtils.File(pluginTag.fullpath))
 
206
                                                             .lastModifiedTime;
 
207
          LOG("Updated lastModifiedTime: " + plugin.pluginData
 
208
                                                   .lastModifiedTime);
 
209
        } catch(e) {
 
210
          LOG("Plugin at path " + pluginTag.fullpath + " was not found");
 
211
          delete newPlugins[pluginTag.fullpath];
 
212
        }
 
213
      }
 
214
    });
 
215
 
 
216
    let pluginPathsByName = {};
 
217
    for (let path in plugins) {
 
218
      pluginPathsByName[plugins[path].name] = path;
 
219
    }
 
220
 
 
221
    // Try to match new data to old data by name, for plugins
 
222
    // where the install path changed
 
223
    for each (let plugin in newPlugins) {
 
224
      if (plugin.oldPluginData) {
 
225
        continue;
 
226
      }
 
227
 
 
228
      if (plugin.pluginData.name in pluginPathsByName) {
 
229
        let path = pluginPathsByName[plugin.pluginData.name];
 
230
        plugin.oldPluginData = plugins[path];
 
231
        delete plugins[path];
 
232
 
 
233
        LOG("Found old data for plugin \"" + plugin.pluginData.name +
 
234
            "\". Old path: " + path + ", old lastModifiedTime: " +
 
235
            plugin.oldPluginData.lastModifiedTime + ", new path: " +
 
236
            plugin.pluginData.path);
 
237
      }
 
238
    }
 
239
 
 
240
    Object.keys(plugins).forEach(function(path) {
 
241
      LOG("Plugin \"" + plugins[path].name + "\" at " +
 
242
          plugins[path].path + " was removed");
 
243
      delete plugins[path];
 
244
    });
213
245
 
214
246
    let foundUpdated = false;
215
 
    let requiresRestart = false;
216
 
    for (let name in seenPlugins) {
217
 
      if (!foundUpdated && seenPlugins[name].oldPluginData &&
218
 
          seenPlugins[name].oldPluginData.lastModifiedTime !=
219
 
          seenPlugins[name].pluginData.lastModifiedTime) {
220
 
        foundUpdated = true;
221
 
      }
222
 
 
223
 
      if (!requiresRestart && seenPlugins[name].count > 1) {
224
 
        requiresRestart = true;
225
 
      }
226
 
 
227
 
      plugins[name] = seenPlugins[name].pluginData;
 
247
    for each (let plugin in newPlugins) {
 
248
      if (plugin.oldPluginData &&
 
249
          plugin.oldPluginData.lastModifiedTime !=
 
250
          plugin.pluginData.lastModifiedTime) {
 
251
        LOG("Plugin \"" + plugin.pluginData.name + "\" at " +
 
252
            plugin.pluginData.path + " was updated");
 
253
        foundUpdated = true;     
 
254
      } else if (!plugin.oldPluginData) {
 
255
        LOG("Plugin \"" + plugin.pluginData.name + "\" at " +
 
256
            plugin.pluginData.path + " was newly installed");
 
257
      } else {
 
258
        LOG("Plugin \"" + plugin.pluginData.name + "\" at " +
 
259
            plugin.pluginData.path + " is unchanged");
 
260
      }
 
261
 
 
262
      plugins[plugin.pluginData.path] = plugin.pluginData;
228
263
    }
229
264
 
230
265
    if (foundUpdated) {
231
 
      if ("onPluginsUpdated" in dispatched && 
232
 
          dispatched["onPluginsUpdated"][0]) {
233
 
        return;
234
 
      }
235
 
      dispatchNotification("onPluginsUpdated", requiresRestart);
 
266
      dispatchNotification("onPluginsUpdated");
236
267
    }
237
268
  }
238
269
 
426
457
      // Would use the AddonManager here, but it doesn't expose full paths.
427
458
      // We use a delay here to avoid starting the plugin host at startup
428
459
      // if it isn't otherwise needed
 
460
      LOG("Initializing plugin data");
429
461
      Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost)
430
462
                                      .getPluginTags()
431
463
                                      .forEach(function(aPluginTag) {
432
 
        plugins[aPluginTag.name] = {
433
 
          "path": aPluginTag.fullpath,
434
 
          "lastModifiedTime": (new FileUtils.File(aPluginTag.fullpath))
435
 
                                            .lastModifiedTime
436
 
        };
 
464
        try {
 
465
          plugins[aPluginTag.fullpath] = {
 
466
            "path": aPluginTag.fullpath,
 
467
            "name": aPluginTag.name,
 
468
            "lastModifiedTime": (new FileUtils.File(aPluginTag.fullpath))
 
469
                                              .lastModifiedTime
 
470
          };
 
471
          LOG("Found plugin \"" + aPluginTag.name + "\" at " +
 
472
              aPluginTag.fullpath + ", lastModifiedTime: " +
 
473
              plugins[aPluginTag.fullpath].lastModifiedTime);
 
474
        } catch(e) {
 
475
          delete plugins[aPluginTag.fullpath];
 
476
          LOG("Plugin \"" + aPluginTag.name + "\" doesn't exist at " +
 
477
              aPluginTag.fullpath);
 
478
        }
437
479
      });
438
480
    }, 8000, Ci.nsITimer.TYPE_ONE_SHOT);
439
481