Bug 1124895 2/2- Add password manager usage data to FHR.r=dolske,r=gfritzsche

This commit is contained in:
Allison Naaktgeboren 2015-03-27 12:32:42 -07:00
parent 82359f9bb9
commit c8dc36afbe
4 changed files with 133 additions and 11 deletions

View File

@ -1959,3 +1959,30 @@ Example
"numSavedPasswords": 5, "numSavedPasswords": 5,
"enabled": 0, "enabled": 0,
} }
Version 2
^^^^^^^^^
More detailed measurements of login forms & their behavior
numNewSavedPasswordsInSession
Number of passwords saved to the password manager this session.
numSuccessfulFills
Number of times the password manager filled in password fields for user this session.
numTotalLoginsEncountered
Number of times a login form was encountered by the user in the session.
Example
^^^^^^^
::
"org.mozilla.passwordmgr.passwordmgr": {
"_v": 2,
"numSavedPasswords": 32,
"enabled": 1,
"numNewSavedPasswords": 5,
"numSuccessfulFills": 11,
"numTotalLoginsEncountered": 23,
}

View File

@ -261,11 +261,16 @@ var LoginManagerContent = {
onFormPassword: function (event) { onFormPassword: function (event) {
if (!event.isTrusted) if (!event.isTrusted)
return; return;
let form = event.target;
let doc = form.ownerDocument;
let win = doc.defaultView;
let messageManager = messageManagerFromWindow(win);
messageManager.sendAsyncMessage("LoginStats:LoginEncountered");
if (!gEnabled) if (!gEnabled)
return; return;
let form = event.target;
log("onFormPassword for", form.ownerDocument.documentURI); log("onFormPassword for", form.ownerDocument.documentURI);
this._getLoginDataFromParent(form, { showMasterPassword: true }) this._getLoginDataFromParent(form, { showMasterPassword: true })
.then(this.loginsFound.bind(this)) .then(this.loginsFound.bind(this))
@ -806,6 +811,10 @@ var LoginManagerContent = {
} }
recordAutofillResult(AUTOFILL_RESULT.FILLED); recordAutofillResult(AUTOFILL_RESULT.FILLED);
let doc = form.ownerDocument;
let win = doc.defaultView;
let messageManager = messageManagerFromWindow(win);
messageManager.sendAsyncMessage("LoginStats:LoginFillSuccessful");
} finally { } finally {
Services.obs.notifyObservers(form, "passwordmgr-processed-form", null); Services.obs.notifyObservers(form, "passwordmgr-processed-form", null);
} }

View File

@ -21,6 +21,30 @@ this.EXPORTED_SYMBOLS = [ "LoginManagerParent", "PasswordsMetricsProvider" ];
var gDebug; var gDebug;
#ifndef ANDROID
#ifdef MOZ_SERVICES_HEALTHREPORT
XPCOMUtils.defineLazyModuleGetter(this, "Metrics",
"resource://gre/modules/Metrics.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
function recordFHRDailyCounter(aField) {
let reporter = Cc["@mozilla.org/datareporting/service;1"]
.getService()
.wrappedJSObject
.healthReporter;
// This can happen if the FHR component of the data reporting service is
// disabled. This is controlled by a pref that most will never use.
if (!reporter) {
return;
}
reporter.onInit().then(() => reporter.getProvider("org.mozilla.passwordmgr")
.recordDailyCounter(aField));
}
#endif
#endif
function log(...pieces) { function log(...pieces) {
function generateLogMessage(args) { function generateLogMessage(args) {
let strings = ['Login Manager (parent):']; let strings = ['Login Manager (parent):'];
@ -53,10 +77,6 @@ function log(...pieces) {
#ifndef ANDROID #ifndef ANDROID
#ifdef MOZ_SERVICES_HEALTHREPORT #ifdef MOZ_SERVICES_HEALTHREPORT
XPCOMUtils.defineLazyModuleGetter(this, "Metrics",
"resource://gre/modules/Metrics.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
this.PasswordsMetricsProvider = function() { this.PasswordsMetricsProvider = function() {
Metrics.Provider.call(this); Metrics.Provider.call(this);
@ -69,17 +89,16 @@ PasswordsMetricsProvider.prototype = Object.freeze({
measurementTypes: [ measurementTypes: [
PasswordsMeasurement1, PasswordsMeasurement1,
PasswordsMeasurement2,
], ],
pullOnly: true, collectDailyData: function () {
collectDailyData: function* () {
return this.storage.enqueueTransaction(this._recordDailyPasswordData.bind(this)); return this.storage.enqueueTransaction(this._recordDailyPasswordData.bind(this));
}, },
_recordDailyPasswordData: function() { _recordDailyPasswordData: function *() {
let m = this.getMeasurement(PasswordsMeasurement1.prototype.name, let m = this.getMeasurement(PasswordsMeasurement2.prototype.name,
PasswordsMeasurement1.prototype.version); PasswordsMeasurement2.prototype.version);
let enabled = Services.prefs.getBoolPref("signon.rememberSignons"); let enabled = Services.prefs.getBoolPref("signon.rememberSignons");
yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0); yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0);
@ -87,6 +106,20 @@ PasswordsMetricsProvider.prototype = Object.freeze({
yield m.setDailyLastNumeric("numSavedPasswords", loginsCount); yield m.setDailyLastNumeric("numSavedPasswords", loginsCount);
}, },
recordDailyCounter: function(aField) {
let m = this.getMeasurement(PasswordsMeasurement2.prototype.name,
PasswordsMeasurement2.prototype.version);
if (this.storage.hasFieldFromMeasurement(m.id, aField,
Metrics.Storage.FIELD_DAILY_COUNTER)) {
let fieldID = this.storage.fieldIDFromMeasurement(m.id, aField, Metrics.Storage.FIELD_DAILY_COUNTER);
return this.enqueueStorageOperation(() => m.incrementDailyCounter(aField));
}
// Otherwise, we first need to create the field.
return this.enqueueStorageOperation (() => this.storage.registerField(m.id, aField,
Metrics.Storage.FIELD_DAILY_COUNTER).then(() => m.incrementDailyCounter(aField)));
},
}); });
function PasswordsMeasurement1() { function PasswordsMeasurement1() {
@ -103,6 +136,22 @@ PasswordsMeasurement1.prototype = Object.freeze({
}, },
}); });
function PasswordsMeasurement2() {
Metrics.Measurement.call(this);
}
PasswordsMeasurement2.prototype = Object.freeze({
__proto__: Metrics.Measurement.prototype,
name: "passwordmgr",
version: 2,
fields: {
enabled: {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC},
numSavedPasswords: {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC},
numSuccessfulFills: {type: Metrics.Storage.FIELD_DAILY_COUNTER},
numNewSavedPasswordsInSession: {type: Metrics.Storage.FIELD_DAILY_COUNTER},
numTotalLoginsEncountered: {type: Metrics.Storage.FIELD_DAILY_COUNTER},
},
});
#endif #endif
#endif #endif
@ -120,12 +169,27 @@ var LoginManagerParent = {
mm.addMessageListener("RemoteLogins:findLogins", this); mm.addMessageListener("RemoteLogins:findLogins", this);
mm.addMessageListener("RemoteLogins:onFormSubmit", this); mm.addMessageListener("RemoteLogins:onFormSubmit", this);
mm.addMessageListener("RemoteLogins:autoCompleteLogins", this); mm.addMessageListener("RemoteLogins:autoCompleteLogins", this);
mm.addMessageListener("LoginStats:LoginEncountered", this);
mm.addMessageListener("LoginStats:LoginFillSuccessful", this);
Services.obs.addObserver(this, "LoginStats:NewSavedPassword", false);
XPCOMUtils.defineLazyGetter(this, "recipeParentPromise", () => { XPCOMUtils.defineLazyGetter(this, "recipeParentPromise", () => {
const { LoginRecipesParent } = Cu.import("resource://gre/modules/LoginRecipes.jsm", {}); const { LoginRecipesParent } = Cu.import("resource://gre/modules/LoginRecipes.jsm", {});
let parent = new LoginRecipesParent(); let parent = new LoginRecipesParent();
return parent.initializationPromise; return parent.initializationPromise;
}); });
},
observe: function (aSubject, aTopic, aData) {
#ifndef ANDROID
#ifdef MOZ_SERVICES_HEALTHREPORT
if (aTopic == "LoginStats:NewSavedPassword") {
recordFHRDailyCounter("numNewSavedPasswordsInSession");
}
#endif
#endif
}, },
receiveMessage: function (msg) { receiveMessage: function (msg) {
@ -157,6 +221,24 @@ var LoginManagerParent = {
this.doAutocompleteSearch(data, msg.target); this.doAutocompleteSearch(data, msg.target);
break; break;
} }
case "LoginStats:LoginFillSuccessful": {
#ifndef ANDROID
#ifdef MOZ_SERVICES_HEALTHREPORT
recordFHRDailyCounter("numSuccessfulFills");
#endif
#endif
break;
}
case "LoginStats:LoginEncountered": {
#ifndef ANDROID
#ifdef MOZ_SERVICES_HEALTHREPORT
recordFHRDailyCounter("numTotalLoginsEncountered");
#endif
#endif
break;
}
} }
}, },

View File

@ -896,6 +896,10 @@ LoginManagerPrompter.prototype = {
accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey), accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey),
callback: () => { callback: () => {
histogram.add(PROMPT_ADD_OR_UPDATE); histogram.add(PROMPT_ADD_OR_UPDATE);
if(histogramName == "PWMGR_PROMPT_REMEMBER_ACTION")
{
Services.obs.notifyObservers(null, 'LoginStats:NewSavedPassword', null);
}
readDataFromUI(); readDataFromUI();
persistData(); persistData();
browser.focus(); browser.focus();