144
146
function handleAppUpdated() {
145
if (!("onAppUpdated" in dispatched)) {
146
dispatchNotification("onAppUpdated");
147
LOG("Application change detected");
148
dispatchNotification("onAppUpdated");
150
151
function handlePluginsChanged() {
152
LOG("Plugin change detected");
151
153
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
154
156
ph.reloadPlugins(false);
155
} catch(e) { return; }
157
let oldPluginNamesByPath = {};
158
for (let name in plugins) {
159
oldPluginNamesByPath[plugins[name].path] = name;
158
LOG("nsIPluginHost.reloadPlugins failed. No changes?");
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
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
180
let seenPlugins = {};
181
for each (let pluginTag in ph.getPluginTags()) {
183
if (!(pluginTag.name in plugins)) {
184
oldPluginData = plugins[oldPluginNamesByPath[pluginTag.fullpath]];
186
oldPluginData = plugins[pluginTag.name];
189
if (!(pluginTag.name in seenPlugins)) {
190
seenPlugins[pluginTag.name] = {
178
ph.getPluginTags().forEach(function(pluginTag) {
179
LOG("Processing plugin \"" + pluginTag.name + "\" at " +
182
if (pluginTag.fullpath in plugins) {
183
var oldPluginData = plugins[pluginTag.fullpath];
184
delete plugins[pluginTag.fullpath];
188
LOG("Found old data for plugin with the same path (\"" +
189
oldPluginData.name + "\", lastModifiedTime " +
190
oldPluginData.lastModifiedTime + ")");
193
if (!(pluginTag.fullpath in newPlugins)) {
192
196
"path": pluginTag.fullpath,
193
"lastModifiedTime": (new FileUtils.File(pluginTag.fullpath))
197
"name": pluginTag.name
197
199
"oldPluginData": oldPluginData
200
++seenPlugins[pluginTag.name].count;
201
if (pluginTag.fullpath !=
202
seenPlugins[pluginTag.name].pluginData.path) {
203
let mtime = (new FileUtils.File(pluginTag.fullpath))
205
if (mtime > seenPlugins[pluginTag.name].pluginData
207
seenPlugins[pluginTag.name].pluginData.path = pluginTag.fullpath;
208
seenPlugins[pluginTag.name].pluginData.lastModifiedTime = mtime;
202
newPlugins[pluginTag.fullpath] = plugin;
205
plugin.pluginData.lastModifiedTime = (new FileUtils.File(pluginTag.fullpath))
207
LOG("Updated lastModifiedTime: " + plugin.pluginData
210
LOG("Plugin at path " + pluginTag.fullpath + " was not found");
211
delete newPlugins[pluginTag.fullpath];
216
let pluginPathsByName = {};
217
for (let path in plugins) {
218
pluginPathsByName[plugins[path].name] = path;
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) {
228
if (plugin.pluginData.name in pluginPathsByName) {
229
let path = pluginPathsByName[plugin.pluginData.name];
230
plugin.oldPluginData = plugins[path];
231
delete plugins[path];
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);
240
Object.keys(plugins).forEach(function(path) {
241
LOG("Plugin \"" + plugins[path].name + "\" at " +
242
plugins[path].path + " was removed");
243
delete plugins[path];
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) {
223
if (!requiresRestart && seenPlugins[name].count > 1) {
224
requiresRestart = true;
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");
254
} else if (!plugin.oldPluginData) {
255
LOG("Plugin \"" + plugin.pluginData.name + "\" at " +
256
plugin.pluginData.path + " was newly installed");
258
LOG("Plugin \"" + plugin.pluginData.name + "\" at " +
259
plugin.pluginData.path + " is unchanged");
262
plugins[plugin.pluginData.path] = plugin.pluginData;
230
265
if (foundUpdated) {
231
if ("onPluginsUpdated" in dispatched &&
232
dispatched["onPluginsUpdated"][0]) {
235
dispatchNotification("onPluginsUpdated", requiresRestart);
266
dispatchNotification("onPluginsUpdated");
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)
431
463
.forEach(function(aPluginTag) {
432
plugins[aPluginTag.name] = {
433
"path": aPluginTag.fullpath,
434
"lastModifiedTime": (new FileUtils.File(aPluginTag.fullpath))
465
plugins[aPluginTag.fullpath] = {
466
"path": aPluginTag.fullpath,
467
"name": aPluginTag.name,
468
"lastModifiedTime": (new FileUtils.File(aPluginTag.fullpath))
471
LOG("Found plugin \"" + aPluginTag.name + "\" at " +
472
aPluginTag.fullpath + ", lastModifiedTime: " +
473
plugins[aPluginTag.fullpath].lastModifiedTime);
475
delete plugins[aPluginTag.fullpath];
476
LOG("Plugin \"" + aPluginTag.name + "\" doesn't exist at " +
477
aPluginTag.fullpath);
438
480
}, 8000, Ci.nsITimer.TYPE_ONE_SHOT);