Bug 1122050 - Adds addons data collection to TelemetryEnvironment. r=gfritzsche

This commit is contained in:
Alessio Placitelli 2015-02-25 23:54:32 +01:00
parent 8e60e95266
commit 485fac56a5
4 changed files with 215 additions and 8 deletions

View File

@ -10,6 +10,7 @@ this.EXPORTED_SYMBOLS = [
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Log.jsm");
@ -19,6 +20,10 @@ Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
"resource://gre/modules/ctypes.jsm");
#ifndef MOZ_WIDGET_GONK
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
#endif
XPCOMUtils.defineLazyModuleGetter(this, "ProfileTimesAccessor",
"resource://gre/modules/services/healthreport/profile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
@ -77,6 +82,17 @@ function getSystemLocale() {
}
}
/**
* Asynchronously get a list of addons of the specified type from the AddonManager.
* @param aTypes An array containing the types of addons to request.
* @return Promise<Array> resolved when AddonManager has finished, returning an
* array of addons.
*/
function promiseGetAddonsByTypes(aTypes) {
return new Promise((resolve) =>
AddonManager.getAddonsByTypes(aTypes, (addons) => resolve(addons)));
}
/**
* Safely get a sysinfo property and return its value. If the property is not
* available, return aDefault.
@ -629,6 +645,181 @@ this.TelemetryEnvironment = {
};
},
/**
* Get the addon data in object form.
* @return Object containing the addon data.
*/
_getActiveAddons: Task.async(function* () {
// Request addons, asynchronously.
let allAddons = yield promiseGetAddonsByTypes(["extension", "service"]);
let activeAddons = {};
for (let addon of allAddons) {
// Skip addons which are not active.
if (!addon.isActive) {
continue;
}
activeAddons[addon.id] = {
blocklisted: (addon.blocklistState !== Ci.nsIBlocklistService.STATE_NOT_BLOCKED),
description: addon.description,
name: addon.name,
userDisabled: addon.userDisabled,
appDisabled: addon.appDisabled,
version: addon.version,
scope: addon.scope,
type: addon.type,
foreignInstall: addon.foreignInstall,
hasBinaryComponents: addon.hasBinaryComponents,
installDay: truncateToDays(addon.installDate.getTime()),
updateDay: truncateToDays(addon.updateDate.getTime()),
};
}
return activeAddons;
}),
/**
* Get the currently active theme data in object form.
* @return Object containing the active theme data.
*/
_getActiveTheme: Task.async(function* () {
// Request themes, asynchronously.
let themes = yield promiseGetAddonsByTypes(["theme"]);
let activeTheme = {};
// We only store information about the active theme.
let theme = themes.find(theme => theme.isActive);
if (theme) {
activeTheme = {
id: theme.id,
blocklisted: (theme.blocklistState !== Ci.nsIBlocklistService.STATE_NOT_BLOCKED),
description: theme.description,
name: theme.name,
userDisabled: theme.userDisabled,
appDisabled: theme.appDisabled,
version: theme.version,
scope: theme.scope,
foreignInstall: theme.foreignInstall,
hasBinaryComponents: theme.hasBinaryComponents,
installDay: truncateToDays(theme.installDate.getTime()),
updateDay: truncateToDays(theme.updateDate.getTime()),
};
}
return activeTheme;
}),
/**
* Get the plugins data in object form.
* @return Object containing the plugins data.
*/
_getActivePlugins: function () {
let pluginTags =
Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost).getPluginTags({});
let activePlugins = [];
for (let tag of pluginTags) {
// Skip plugins which are not active.
if (tag.disabled) {
continue;
}
// Make sure to have a valid date.
let updateDate = new Date(Math.max(0, tag.lastModifiedTime));
activePlugins.push({
name: tag.name,
version: tag.version,
description: tag.description,
blocklisted: tag.blocklisted,
disabled: tag.disabled,
clicktoplay: tag.clicktoplay,
mimeTypes: tag.getMimeTypes({}),
updateDay: truncateToDays(updateDate.getTime()),
});
}
return activePlugins;
},
/**
* Get the GMPlugins data in object form.
* @return Object containing the GMPlugins data.
*/
_getActiveGMPlugins: Task.async(function* () {
// Request plugins, asynchronously.
let allPlugins = yield promiseGetAddonsByTypes(["plugin"]);
let activeGMPlugins = {};
for (let plugin of allPlugins) {
// Only get GM Plugin info.
if (!plugin.isGMPlugin) {
continue;
}
activeGMPlugins[plugin.id] = {
version: plugin.version,
userDisabled: plugin.userDisabled,
applyBackgroundUpdates: plugin.applyBackgroundUpdates,
};
}
return activeGMPlugins;
}),
/**
* Get the active experiment data in object form.
* @return Object containing the active experiment data.
*/
_getActiveExperiment: function () {
let experimentInfo = {};
try {
let scope = {};
Cu.import("resource:///modules/experiments/Experiments.jsm", scope);
let experiments = scope.Experiments.instance()
let activeExperiment = experiments.getActiveExperimentID();
if (activeExperiment) {
experimentInfo.id = activeExperiment;
experimentInfo.branch = experiments.getActiveExperimentBranch();
}
} catch(e) {
// If this is not Firefox, the import will fail.
return experimentInfo;
}
return experimentInfo;
},
/**
* Get the addon data in object form.
* @return Object containing the addon data.
*/
_getAddons: Task.async(function* () {
let activeAddons = yield this._getActiveAddons();
let activeTheme = yield this._getActiveTheme();
let activeGMPlugins = yield this._getActiveGMPlugins();
let personaId = null;
#ifndef MOZ_WIDGET_GONK
let theme = LightweightThemeManager.currentTheme;
if (theme) {
personaId = theme.id;
}
#endif
let addonData = {
activeAddons: activeAddons,
theme: activeTheme,
activePlugins: this._getActivePlugins(),
activeGMPlugins: activeGMPlugins,
activeExperiment: this._getActiveExperiment(),
persona: personaId,
};
return addonData;
}),
/**
* Get the environment data in object form.
* @return Promise<Object> Resolved with the data on success, otherwise rejected.
@ -660,6 +851,7 @@ this.TelemetryEnvironment = {
"profile": () => this._getProfile(),
"partner": () => this._getPartner(),
"system": () => this._getSystem(),
"addons": () => this._getAddons(),
};
let data = {};

View File

@ -123,7 +123,7 @@ Structure::
activeAddons: { // the currently enabled addons
<addon id>: {
blocklisted: <bool>,
description: <string>,
description: <string>, // null if not available
name: <string>,
userDisabled: <bool>,
appDisabled: <bool>,

View File

@ -4,14 +4,29 @@
Components.utils.import("resource://gre/modules/TelemetryPing.jsm", this);
Components.utils.import("resource://gre/modules/Services.jsm", this);
// copied from toolkit/mozapps/extensions/test/xpcshell/head_addons.js
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
let gAppInfo;
let gOldAppInfo = Components.classes[XULAPPINFO_CONTRACTID]
.getService(Components.interfaces.nsIXULRuntime);
let gOldAppInfo = null;
let gGlobalScope = this;
function loadAddonManager(id, name, version, platformVersion) {
let ns = {};
Cu.import("resource://gre/modules/Services.jsm", ns);
let head = "../../../../mozapps/extensions/test/xpcshell/head_addons.js";
let file = do_get_file(head);
let uri = ns.Services.io.newFileURI(file);
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
createAppInfo(id, name, version, platformVersion);
startupManager();
}
function createAppInfo(id, name, version, platformVersion) {
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
let gAppInfo;
if (!gOldAppInfo) {
gOldAppInfo = Components.classes[XULAPPINFO_CONTRACTID]
.getService(Components.interfaces.nsIXULRuntime);
}
gAppInfo = {
// nsIXULAppInfo
vendor: "Mozilla",

View File

@ -319,7 +319,7 @@ function run_test() {
do_test_pending();
spoofGfxAdapter();
do_get_profile();
createAppInfo(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
spoofPartnerInfo();
// Spoof the the hotfixVersion
Preferences.set("extensions.hotfix.lastVersion", APP_HOTFIX_VERSION);