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

View File

@ -21,6 +21,30 @@ this.EXPORTED_SYMBOLS = [ "LoginManagerParent", "PasswordsMetricsProvider" ];
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 generateLogMessage(args) {
let strings = ['Login Manager (parent):'];
@ -53,10 +77,6 @@ function log(...pieces) {
#ifndef ANDROID
#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() {
Metrics.Provider.call(this);
@ -69,17 +89,16 @@ PasswordsMetricsProvider.prototype = Object.freeze({
measurementTypes: [
PasswordsMeasurement1,
PasswordsMeasurement2,
],
pullOnly: true,
collectDailyData: function* () {
collectDailyData: function () {
return this.storage.enqueueTransaction(this._recordDailyPasswordData.bind(this));
},
_recordDailyPasswordData: function() {
let m = this.getMeasurement(PasswordsMeasurement1.prototype.name,
PasswordsMeasurement1.prototype.version);
_recordDailyPasswordData: function *() {
let m = this.getMeasurement(PasswordsMeasurement2.prototype.name,
PasswordsMeasurement2.prototype.version);
let enabled = Services.prefs.getBoolPref("signon.rememberSignons");
yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0);
@ -87,6 +106,20 @@ PasswordsMetricsProvider.prototype = Object.freeze({
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() {
@ -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
@ -120,12 +169,27 @@ var LoginManagerParent = {
mm.addMessageListener("RemoteLogins:findLogins", this);
mm.addMessageListener("RemoteLogins:onFormSubmit", 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", () => {
const { LoginRecipesParent } = Cu.import("resource://gre/modules/LoginRecipes.jsm", {});
let parent = new LoginRecipesParent();
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) {
@ -157,6 +221,24 @@ var LoginManagerParent = {
this.doAutocompleteSearch(data, msg.target);
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),
callback: () => {
histogram.add(PROMPT_ADD_OR_UPDATE);
if(histogramName == "PWMGR_PROMPT_REMEMBER_ACTION")
{
Services.obs.notifyObservers(null, 'LoginStats:NewSavedPassword', null);
}
readDataFromUI();
persistData();
browser.focus();