diff --git a/browser/components/migration/MigrationUtils.jsm b/browser/components/migration/MigrationUtils.jsm index 7e1173f2e99c..0b559f9b1c32 100644 --- a/browser/components/migration/MigrationUtils.jsm +++ b/browser/components/migration/MigrationUtils.jsm @@ -13,6 +13,7 @@ const TOPIC_DID_IMPORT_BOOKMARKS = "initial-migration-did-import-default-bookmar Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); @@ -545,12 +546,21 @@ this.MigrationUtils = Object.freeze({ * Show the migration wizard. On mac, this may just focus the wizard if it's * already running, in which case aOpener and aParams are ignored. * - * @param [optional] aOpener - * the window that asks to open the wizard. - * @param [optioanl] aParams - * arguments for the migration wizard, in the form of an nsIArray. + * @param {Window} [aOpener] + * optional; the window that asks to open the wizard. + * @param {Array} [aParams] + * optional arguments for the migration wizard, in the form of an array * This is passed as-is for the params argument of - * nsIWindowWatcher.openWindow. + * nsIWindowWatcher.openWindow. The array elements we expect are, in + * order: + * - {Number} migration entry point constant (see below) + * - {String} source browser identifier + * - {nsIBrowserProfileMigrator} actual migrator object + * - {Boolean} whether this is a startup migration + * - {Boolean} whether to skip the 'source' page + * NB: If you add new consumers, please add a migration entry point + * constant below, and specify at least the first element of the array + * (the migration entry point for purposes of telemetry). */ showMigrationWizard: function MU_showMigrationWizard(aOpener, aParams) { @@ -636,18 +646,18 @@ this.MigrationUtils = Object.freeze({ } } - let params = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - let keyCSTR = Cc["@mozilla.org/supports-cstring;1"]. - createInstance(Ci.nsISupportsCString); - keyCSTR.data = migratorKey; - let skipImportSourcePageBool = Cc["@mozilla.org/supports-PRBool;1"]. - createInstance(Ci.nsISupportsPRBool); - skipImportSourcePageBool.data = skipSourcePage; - params.appendElement(keyCSTR, false); - params.appendElement(migrator, false); - params.appendElement(aProfileStartup, false); - params.appendElement(skipImportSourcePageBool, false); + let migrationEntryPoint = this.MIGRATION_ENTRYPOINT_FIRSTRUN; + if (migrator && skipSourcePage && migratorKey == AppConstants.MOZ_APP_NAME) { + migrationEntryPoint = this.MIGRATION_ENTRYPOINT_FXREFRESH; + } + let params = [ + migrationEntryPoint, + migratorKey, + migrator, + aProfileStartup, + skipSourcePage + ]; this.showMigrationWizard(null, params); }, @@ -658,5 +668,26 @@ this.MigrationUtils = Object.freeze({ gMigrators = null; gProfileStartup = null; gMigrationBundle = null; - } + }, + + MIGRATION_ENTRYPOINT_UNKNOWN: 0, + MIGRATION_ENTRYPOINT_FIRSTRUN: 1, + MIGRATION_ENTRYPOINT_FXREFRESH: 2, + MIGRATION_ENTRYPOINT_PLACES: 3, + MIGRATION_ENTRYPOINT_PASSWORDS: 4, + + _sourceNameToIdMapping: { + "nothing": 1, + "firefox": 2, + "edge": 3, + "ie": 4, + "chrome": 5, + "chromium": 6, + "canary": 7, + "safari": 8, + "360se": 9, + }, + getSourceIdForTelemetry(sourceName) { + return this._sourceNameToIdMapping[sourceName] || 0; + }, }); diff --git a/browser/components/migration/content/migration.js b/browser/components/migration/content/migration.js index 44dbdfeb8097..6fc87bf05738 100644 --- a/browser/components/migration/content/migration.js +++ b/browser/components/migration/content/migration.js @@ -9,6 +9,7 @@ var Cu = Components.utils; const kIMig = Ci.nsIBrowserProfileMigrator; const kIPStartup = Ci.nsIProfileStartup; +Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/MigrationUtils.jsm"); var MigrationWizard = { @@ -21,8 +22,7 @@ var MigrationWizard = { init: function () { - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); + let os = Services.obs; os.addObserver(this, "Migration:Started", false); os.addObserver(this, "Migration:ItemBeforeMigrate", false); os.addObserver(this, "Migration:ItemAfterMigrate", false); @@ -31,18 +31,20 @@ var MigrationWizard = { this._wiz = document.documentElement; - if ("arguments" in window && window.arguments.length > 1) { - this._source = window.arguments[0]; - this._migrator = window.arguments[1] instanceof kIMig ? - window.arguments[1] : null; - this._autoMigrate = window.arguments[2].QueryInterface(kIPStartup); - this._skipImportSourcePage = window.arguments[3]; + let args = (window.arguments && window.arguments[0]) || []; + let entryPointId = args[0] || MigrationUtils.MIGRATION_ENTRYPOINT_UNKNOWN; + Services.telemetry.getHistogramById("FX_MIGRATION_ENTRY_POINT").add(entryPointId); + + if (args.length > 1) { + this._source = args[1]; + this._migrator = args[2] instanceof kIMig ? args[2] : null; + this._autoMigrate = args[3].QueryInterface(kIPStartup); + this._skipImportSourcePage = args[4]; if (this._autoMigrate) { // Show the "nothing" option in the automigrate case to provide an // easily identifiable way to avoid migration and create a new profile. - var nothing = document.getElementById("nothing"); - nothing.hidden = false; + document.getElementById("nothing").hidden = false; } } @@ -122,6 +124,11 @@ var MigrationWizard = { var newSource = document.getElementById("importSourceGroup").selectedItem.id; if (newSource == "nothing") { + // Need to do telemetry here because we're closing the dialog before we get to + // do actual migration. For actual migration, this doesn't happen until after + // migration takes place. + Services.telemetry.getHistogramById("FX_MIGRATION_SOURCE_BROWSER") + .add(MigrationUtils.getSourceIdForTelemetry("nothing")); document.documentElement.cancel(); return false; } @@ -357,12 +364,27 @@ var MigrationWizard = { this._itemsFlags = this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate); this._listItems("migratingItems"); - setTimeout(this.onMigratingMigrate, 0, this); + setTimeout(() => this.onMigratingMigrate(), 0); }, - onMigratingMigrate: function (aOuter) + onMigratingMigrate: function () { - aOuter._migrator.migrate(aOuter._itemsFlags, aOuter._autoMigrate, aOuter._selectedProfile); + this._migrator.migrate(this._itemsFlags, this._autoMigrate, this._selectedProfile); + + Services.telemetry.getHistogramById("FX_MIGRATION_SOURCE_BROWSER") + .add(MigrationUtils.getSourceIdForTelemetry(this._source)); + if (!this._autoMigrate) { + let hist = Services.telemetry.getKeyedHistogramById("FX_MIGRATION_USAGE"); + let exp = 0; + let items = this._itemsFlags; + while (items) { + if (items & 1) { + hist.add(this._source, exp); + } + items = items >> 1; + exp++ + } + } }, _listItems: function (aID) @@ -409,6 +431,8 @@ var MigrationWizard = { break; case "Migration:Ended": if (this._autoMigrate) { + Services.telemetry.getKeyedHistogramById("FX_MIGRATION_HOMEPAGE_IMPORTED") + .add(this._source, !!this._newHomePage); if (this._newHomePage) { try { // set homepage properly @@ -451,8 +475,9 @@ var MigrationWizard = { } break; case "Migration:ItemError": - var type = "undefined"; - switch (parseInt(aData)) { + let type = "undefined"; + let numericType = parseInt(aData); + switch (numericType) { case Ci.nsIBrowserProfileMigrator.SETTINGS: type = "settings"; break; @@ -478,6 +503,8 @@ var MigrationWizard = { Cc["@mozilla.org/consoleservice;1"] .getService(Ci.nsIConsoleService) .logStringMessage("some " + type + " did not successfully migrate."); + Services.telemetry.getKeyedHistogramById("FX_MIGRATION_ERRORS") + .add(this._source, Math.log2(numericType)); break; } }, diff --git a/browser/components/migration/content/migration.xul b/browser/components/migration/content/migration.xul index 679082390e8e..a11a4bb7f9ff 100644 --- a/browser/components/migration/content/migration.xul +++ b/browser/components/migration/content/migration.xul @@ -32,6 +32,7 @@ +# NB: if you add items to this list, please also assign them a unique migrator ID in MigrationUtils.jsm #ifdef XP_WIN diff --git a/browser/components/places/content/places.js b/browser/components/places/content/places.js index 81895105cc69..9a1b669fec87 100644 --- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -362,7 +362,8 @@ var PlacesOrganizer = { * cookies, history, preferences, and bookmarks. */ importFromBrowser: function PO_importFromBrowser() { - MigrationUtils.showMigrationWizard(window); + // We pass in the type of source we're using for use in telemetry: + MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PLACES]); }, /** diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js index 5fc9e915292a..5ed30f892893 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.js +++ b/toolkit/components/passwordmgr/content/passwordManager.js @@ -452,5 +452,6 @@ function escapeKeyHandler() { function OpenMigrator() { const { MigrationUtils } = Cu.import("resource:///modules/MigrationUtils.jsm", {}); - MigrationUtils.showMigrationWizard(window); + // We pass in the type of source we're using for use in telemetry: + MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS]); } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index f6fb7453ceec..6879fde5c9fd 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -4177,6 +4177,43 @@ "kind": "boolean", "description": "THUMBNAILS: Thumbnail found" }, + "FX_MIGRATION_ENTRY_POINT": { + "expires_in_version": "49", + "kind": "enumerated", + "n_values": 10, + "releaseChannelCollection": "opt-out", + "description": "Where the migration wizard was entered from. 0=Other/catch-all, 1=first-run, 2=refresh-firefox, 3=Places window, 4=Password manager" + }, + "FX_MIGRATION_SOURCE_BROWSER": { + "expires_in_version": "49", + "kind": "enumerated", + "n_values": 15, + "releaseChannelCollection": "opt-out", + "description": "The browser that data is pulled from. The values correspond to the internal browser ID (see MigrationUtils.jsm)" + }, + "FX_MIGRATION_ERRORS": { + "expires_in_version": "49", + "kind": "enumerated", + "keyed": "true", + "n_values": 12, + "releaseChannelCollection": "opt-out", + "description": "Errors encountered during migration in buckets defined by the datatype, keyed by the string description of the browser." + }, + "FX_MIGRATION_USAGE": { + "expires_in_version": "49", + "kind": "enumerated", + "keyed": "true", + "n_values": 12, + "releaseChannelCollection": "opt-out", + "description": "Usage of migration for each datatype when migration is run through the post-firstrun flow which allows individual datatypes, keyed by the string description of the browser." + }, + "FX_MIGRATION_HOMEPAGE_IMPORTED": { + "expires_in_version": "49", + "kind": "boolean", + "keyed": "true", + "releaseChannelCollection": "opt-out", + "description": "Whether the homepage was imported during browser migration. Only available on release builds during firstrun." + }, "EVENTLOOP_UI_LAG_EXP_MS": { "alert_emails": ["perf-telemetry-alerts@mozilla.com"], "expires_in_version": "never",