forked from mirrors/gecko-dev
Backed out changeset 2d6a773b1cfe (bug 1894958) Backed out changeset 64fa5abd15b1 (bug 1894958) Backed out changeset 73017dc41a54 (bug 1894958) Backed out changeset 99498fc1e89c (bug 1894958) Backed out changeset 4ef86875b1c2 (bug 1894958) Backed out changeset 31e1c5284927 (bug 1894958) Backed out changeset 29545556fe0b (bug 1894958)
236 lines
6.1 KiB
JavaScript
236 lines
6.1 KiB
JavaScript
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
HiddenFrame: "resource://gre/modules/HiddenFrame.sys.mjs",
|
|
});
|
|
|
|
ChromeUtils.defineLazyGetter(lazy, "console", () => {
|
|
return console.createInstance({
|
|
prefix: "UserCharacteristicsPage",
|
|
maxLogLevelPref: "toolkit.telemetry.user_characteristics_ping.logLevel",
|
|
});
|
|
});
|
|
|
|
ChromeUtils.defineLazyGetter(lazy, "contentPrefs", () => {
|
|
return Cc["@mozilla.org/content-pref/service;1"].getService(
|
|
Ci.nsIContentPrefService2
|
|
);
|
|
});
|
|
|
|
const BACKGROUND_WIDTH = 1024;
|
|
const BACKGROUND_HEIGHT = 768;
|
|
|
|
/**
|
|
* A manager for hidden browsers. Responsible for creating and destroying a
|
|
* hidden frame to hold them.
|
|
* All of this is copied from PageDataService.sys.mjs
|
|
*/
|
|
class HiddenBrowserManager {
|
|
/**
|
|
* The hidden frame if one has been created.
|
|
*
|
|
* @type {HiddenFrame | null}
|
|
*/
|
|
#frame = null;
|
|
/**
|
|
* The number of hidden browser elements currently in use.
|
|
*
|
|
* @type {number}
|
|
*/
|
|
#browsers = 0;
|
|
|
|
/**
|
|
* Creates and returns a new hidden browser.
|
|
*
|
|
* @returns {Browser}
|
|
*/
|
|
async #acquireBrowser() {
|
|
this.#browsers++;
|
|
if (!this.#frame) {
|
|
this.#frame = new lazy.HiddenFrame();
|
|
}
|
|
|
|
let frame = await this.#frame.get();
|
|
let doc = frame.document;
|
|
let browser = doc.createXULElement("browser");
|
|
browser.setAttribute("remote", "true");
|
|
browser.setAttribute("type", "content");
|
|
browser.setAttribute(
|
|
"style",
|
|
`
|
|
width: ${BACKGROUND_WIDTH}px;
|
|
min-width: ${BACKGROUND_WIDTH}px;
|
|
height: ${BACKGROUND_HEIGHT}px;
|
|
min-height: ${BACKGROUND_HEIGHT}px;
|
|
`
|
|
);
|
|
browser.setAttribute("maychangeremoteness", "true");
|
|
doc.documentElement.appendChild(browser);
|
|
|
|
return browser;
|
|
}
|
|
|
|
/**
|
|
* Releases the given hidden browser.
|
|
*
|
|
* @param {Browser} browser
|
|
* The hidden browser element.
|
|
*/
|
|
#releaseBrowser(browser) {
|
|
browser.remove();
|
|
|
|
this.#browsers--;
|
|
if (this.#browsers == 0) {
|
|
this.#frame.destroy();
|
|
this.#frame = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calls a callback function with a new hidden browser.
|
|
* This function will return whatever the callback function returns.
|
|
*
|
|
* @param {Callback} callback
|
|
* The callback function will be called with the browser element and may
|
|
* be asynchronous.
|
|
* @returns {T}
|
|
*/
|
|
async withHiddenBrowser(callback) {
|
|
let browser = await this.#acquireBrowser();
|
|
try {
|
|
return await callback(browser);
|
|
} finally {
|
|
this.#releaseBrowser(browser);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class UserCharacteristicsPageService {
|
|
classId = Components.ID("{ce3e9659-e311-49fb-b18b-7f27c6659b23}");
|
|
QueryInterface = ChromeUtils.generateQI([
|
|
"nsIUserCharacteristicsPageService",
|
|
]);
|
|
|
|
_initialized = false;
|
|
_isParentProcess = false;
|
|
|
|
/**
|
|
* A manager for hidden browsers.
|
|
*
|
|
* @type {HiddenBrowserManager}
|
|
*/
|
|
_browserManager = new HiddenBrowserManager();
|
|
|
|
/**
|
|
* A map of hidden browsers to a resolve function that should be passed the
|
|
* actor that was created for the browser.
|
|
*
|
|
* @type {WeakMap<Browser, function(PageDataParent): void>}
|
|
*/
|
|
_backgroundBrowsers = new WeakMap();
|
|
|
|
constructor() {
|
|
lazy.console.debug("Init");
|
|
|
|
if (
|
|
Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT
|
|
) {
|
|
throw new Error(
|
|
"Shouldn't init UserCharacteristicsPage in content processes."
|
|
);
|
|
}
|
|
|
|
// Return if we have initiated.
|
|
if (this._initialized) {
|
|
lazy.console.warn("preventing re-initilization...");
|
|
return;
|
|
}
|
|
this._initialized = true;
|
|
}
|
|
|
|
shutdown() {}
|
|
|
|
createContentPage() {
|
|
lazy.console.debug("called createContentPage");
|
|
return this._browserManager.withHiddenBrowser(async browser => {
|
|
lazy.console.debug(`In withHiddenBrowser`);
|
|
try {
|
|
let { promise, resolve } = Promise.withResolvers();
|
|
this._backgroundBrowsers.set(browser, resolve);
|
|
|
|
let principal = Services.scriptSecurityManager.getSystemPrincipal();
|
|
let loadURIOptions = {
|
|
triggeringPrincipal: principal,
|
|
};
|
|
|
|
let userCharacteristicsPageURI = Services.io.newURI(
|
|
"about:fingerprinting"
|
|
);
|
|
|
|
browser.loadURI(userCharacteristicsPageURI, loadURIOptions);
|
|
|
|
let data = await promise;
|
|
if (data.debug) {
|
|
lazy.console.debug(`Debugging Output:`);
|
|
for (let line of data.debug) {
|
|
lazy.console.debug(line);
|
|
}
|
|
lazy.console.debug(`(debugging output done)`);
|
|
}
|
|
lazy.console.debug(`Data:`, data.output);
|
|
|
|
lazy.console.debug("Populating Glean metrics...");
|
|
Glean.characteristics.timezone.set(data.output.foo);
|
|
|
|
for (let gamepad of data.output.gamepads) {
|
|
Glean.characteristics.gamepads.add(gamepad);
|
|
}
|
|
Glean.characteristics.zoomCount.set(await this.populateZoomPrefs());
|
|
|
|
lazy.console.debug("Unregistering actor");
|
|
Services.obs.notifyObservers(
|
|
null,
|
|
"user-characteristics-populating-data-done"
|
|
);
|
|
} finally {
|
|
this._backgroundBrowsers.delete(browser);
|
|
}
|
|
});
|
|
}
|
|
|
|
async populateZoomPrefs() {
|
|
const zoomPrefsCount = await new Promise(resolve => {
|
|
lazy.contentPrefs.getByName("browser.content.full-zoom", null, {
|
|
_result: 0,
|
|
handleResult(_) {
|
|
this._result++;
|
|
},
|
|
handleCompletion() {
|
|
resolve(this._result);
|
|
},
|
|
});
|
|
});
|
|
|
|
return zoomPrefsCount;
|
|
}
|
|
|
|
async pageLoaded(browsingContext, data) {
|
|
lazy.console.debug(
|
|
`pageLoaded browsingContext=${browsingContext} data=${data}`
|
|
);
|
|
|
|
let browser = browsingContext.embedderElement;
|
|
|
|
let backgroundResolve = this._backgroundBrowsers.get(browser);
|
|
if (backgroundResolve) {
|
|
backgroundResolve(data);
|
|
return;
|
|
}
|
|
throw new Error(`No backround resolve for ${browser} found`);
|
|
}
|
|
}
|