Bug 1164159 - Send information about the default search engines through Telemetry, r=markh,gfritzsche.

This commit is contained in:
Florian Quèze 2015-06-10 11:17:31 +02:00
Родитель 1341bf71a3
Коммит a9ec9ab1eb
4 изменённых файлов: 183 добавлений и 0 удалений

Просмотреть файл

@ -2818,6 +2818,75 @@ Engine.prototype = {
return this.__id = this._file.path;
},
// This indicates where we found the .xml file to load the engine,
// and attempts to hide user-identifiable data (such as username).
get _anonymizedLoadPath() {
/* Examples of expected output:
* jar:[app]/omni.ja!browser/engine.xml
* 'browser' here is the name of the chrome package, not a folder.
* [profile]/searchplugins/engine.xml
* [distribution]/searchplugins/common/engine.xml
* [other]/engine.xml
*/
let leafName = this._getLeafName();
if (!leafName)
return "null";
let prefix = "", suffix = "";
let file = this._file;
if (!file) {
let uri = this._uri;
if (uri.schemeIs("chrome")) {
let packageName = uri.hostPort;
uri = gChromeReg.convertChromeURL(uri);
if (uri instanceof Ci.nsINestedURI) {
prefix = "jar:";
suffix = "!" + packageName + "/" + leafName;
uri = uri.innermostURI;
}
uri.QueryInterface(Ci.nsIFileURL)
file = uri.file;
} else {
return "[" + uri.scheme + "]/" + leafName;
}
}
let id;
let enginePath = file.path;
const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
const XRE_APP_DISTRIBUTION_DIR = "XREAppDist";
const knownDirs = {
app: NS_XPCOM_CURRENT_PROCESS_DIR,
profile: NS_APP_USER_PROFILE_50_DIR,
distribution: XRE_APP_DISTRIBUTION_DIR
};
for (let key in knownDirs) {
let path;
try {
path = getDir(knownDirs[key]).path;
} catch(e) {
// Getting XRE_APP_DISTRIBUTION_DIR throws during unit tests.
continue;
}
if (enginePath.startsWith(path)) {
id = "[" + key + "]" + enginePath.slice(path.length).replace(/\\/g, "/");
break;
}
}
// If the folder doesn't have a known ancestor, don't record its path to
// avoid leaking user identifiable data.
if (!id)
id = "[other]/" + file.leafName;
return prefix + id + suffix;
},
get _installLocation() {
if (this.__installLocation === null) {
if (!this._file) {
@ -3200,6 +3269,10 @@ function SearchService() {
SearchService.prototype = {
classID: Components.ID("{7319788a-fe93-4db3-9f39-818cf08f4256}"),
get wrappedJSObject() {
return this;
},
// The current status of initialization. Note that it does not determine if
// initialization is complete, only if an error has been encountered so far.
_initRV: Cr.NS_OK,
@ -4597,6 +4670,71 @@ SearchService.prototype = {
notifyAction(this._currentEngine, SEARCH_ENGINE_CURRENT);
},
getDefaultEngineInfo() {
let result = {};
let engine;
try {
engine = this.defaultEngine;
} catch(e) {
// The defaultEngine getter will throw if there's no engine at all,
// which shouldn't happen unless an add-on or a test deleted all of them.
// Our preferences UI doesn't let users do that.
Cu.reportError("getDefaultEngineInfo: No default engine");
}
if (!engine) {
result.name = "NONE";
} else {
if (engine.name)
result.name = engine.name;
result.loadPath = engine._anonymizedLoadPath;
// For privacy, we only collect the submission URL for engines
// from the application or distribution folder...
let sendSubmissionURL =
/^(?:jar:|\[app\]|\[distribution\])/.test(result.loadPath);
// ... or engines sorted by default near the top of the list.
if (!sendSubmissionURL) {
let extras =
Services.prefs.getChildList(BROWSER_SEARCH_PREF + "order.extra.");
for (let prefName of extras) {
try {
if (result.name == Services.prefs.getCharPref(prefName)) {
sendSubmissionURL = true;
break;
}
} catch(e) {}
}
let prefNameBase = getGeoSpecificPrefName(BROWSER_SEARCH_PREF + "order");
let i = 0;
while (!sendSubmissionURL) {
let prefName = prefNameBase + "." + (++i);
let engineName = getLocalizedPref(prefName);
if (!engineName)
break;
if (result.name == engineName) {
sendSubmissionURL = true;
break;
}
}
}
if (sendSubmissionURL) {
let uri = engine._getURLOfType("text/html")
.getSubmission("", engine, "searchbar").uri;
uri.userPass = ""; // Avoid reporting a username or password.
result.submissionURL = uri.spec;
}
}
return result;
},
/**
* This map is built lazily after the available search engines change. It
* allows quick parsing of an URL representing a search submission into the

Просмотреть файл

@ -880,6 +880,8 @@ EnvironmentCache.prototype = {
this._currentEnvironment.settings = this._currentEnvironment.settings || {};
// Update the search engine entry in the current environment.
this._currentEnvironment.settings.defaultSearchEngine = this._getDefaultSearchEngine();
this._currentEnvironment.settings.defaultSearchEngineData =
Services.search.wrappedJSObject.getDefaultEngineInfo();
},
/**

Просмотреть файл

@ -35,6 +35,11 @@ Structure::
blocklistEnabled: <bool>, // true on failure
isDefaultBrowser: <bool>, // null on failure, not available on Android
defaultSearchEngine: <string>, // e.g. "yahoo"
defaultSearchEngineData: {, // data about the current default engine
name: <string>, // engine name, e.g. "Yahoo"; or "NONE" if no default
loadPath: <string>, // where the engine line is located; missing if no default
submissionURL: <string> // missing if no default or for user-installed engines
},
e10sEnabled: <bool>, // false on failure
telemetryEnabled: <bool>, // false on failure
locale: <string>, // e.g. "it", null on failure
@ -197,6 +202,8 @@ Settings
defaultSearchEngine
~~~~~~~~~~~~~~~~~~~
Note: Deprecated, use defaultSearchEngineData instead.
Contains the string identifier or name of the default search engine provider. This will not be present in environment data collected before the Search Service initialization.
The special value ``NONE`` could occur if there is no default search engine.
@ -204,3 +211,24 @@ The special value ``NONE`` could occur if there is no default search engine.
The special value ``UNDEFINED`` could occur if a default search engine exists but its identifier could not be determined.
This field's contents are ``Services.search.defaultEngine.identifier`` (if defined) or ``"other-"`` + ``Services.search.defaultEngine.name`` if not. In other words, search engines without an ``.identifier`` are prefixed with ``other-``.
defaultSearchEngineData
~~~~~~~~~~~~~~~~~~~~~~~
Contains data identifying the engine currently set as the default.
The object contains:
- a ``name`` property with the name of the engine, or ``NONE`` if no
engine is currently set as the default.
- a ``loadPath`` property: an anonymized path of the engine xml file, e.g.
jar:[app]/omni.ja!browser/engine.xml
(where 'browser' is the name of the chrome package, not a folder)
[profile]/searchplugins/engine.xml
[distribution]/searchplugins/common/engine.xml
[other]/engine.xml
- a ``submissionURL`` property with the HTTP url we would use to search.
For privacy, we don't record this for user-installed engines.
``loadPath`` and ``submissionURL`` are not present if ``name`` is ``NONE``.

Просмотреть файл

@ -284,6 +284,7 @@ function checkSettingsSection(data) {
// Check "defaultSearchEngine" separately, as it can either be undefined or string.
if ("defaultSearchEngine" in data.settings) {
checkString(data.settings.defaultSearchEngine);
Assert.equal(typeof data.settings.defaultSearchEngineData, "object");
}
}
@ -994,6 +995,7 @@ add_task(function* test_defaultSearchEngine() {
let data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data);
Assert.ok(!("defaultSearchEngine" in data.settings));
Assert.ok(!("defaultSearchEngineData" in data.settings));
// Load the engines definitions from a custom JAR file: that's needed so that
// the search provider reports an engine identifier.
@ -1011,6 +1013,12 @@ add_task(function* test_defaultSearchEngine() {
data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data);
Assert.equal(data.settings.defaultSearchEngine, "telemetrySearchIdentifier");
let expectedSearchEngineData = {
name: "telemetrySearchIdentifier",
loadPath: "jar:[other]/searchTest.jar!testsearchplugin/telemetrySearchIdentifier.xml",
submissionURL: "http://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB?search=&sourceid=Mozilla-search"
};
Assert.deepEqual(data.settings.defaultSearchEngineData, expectedSearchEngineData);
// Remove all the search engines.
for (let engine of Services.search.getEngines()) {
@ -1025,6 +1033,7 @@ add_task(function* test_defaultSearchEngine() {
data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data);
Assert.equal(data.settings.defaultSearchEngine, "NONE");
Assert.deepEqual(data.settings.defaultSearchEngineData, {name:"NONE"});
// Add a new search engine (this will have no engine identifier).
const SEARCH_ENGINE_ID = "telemetry_default";
@ -1044,6 +1053,12 @@ add_task(function* test_defaultSearchEngine() {
const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID;
Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
const EXPECTED_SEARCH_ENGINE_DATA = {
name: "telemetry_default",
loadPath: "[profile]/searchplugins/telemetrydefault.xml"
};
Assert.deepEqual(data.settings.defaultSearchEngineData, EXPECTED_SEARCH_ENGINE_DATA);
TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
// Define and reset the test preference.