gecko-dev/toolkit/components/telemetry/geckoview/GeckoViewTelemetryControlle...

135 строки
4.8 KiB
JavaScript

/* 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 http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
EventDispatcher: "resource://gre/modules/Messaging.jsm",
Services: "resource://gre/modules/Services.jsm",
TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm",
});
GeckoViewUtils.initLogging("GeckoView.TelemetryController", this);
var EXPORTED_SYMBOLS = ["GeckoViewTelemetryController"];
/* global debug warn */
// Persistent data loading topic - see TelemetryGeckoViewPersistence.cpp.
const LOAD_COMPLETE_TOPIC = "internal-telemetry-geckoview-load-complete";
const GeckoViewTelemetryController = {
/**
* Setup the Telemetry recording flags. This must be called
* in all the processes that need to collect Telemetry.
*/
setup() {
TelemetryUtils.setTelemetryRecordingFlags();
debug `setup -
canRecordPrereleaseData ${Services.telemetry.canRecordPrereleaseData},
canRecordReleaseData ${Services.telemetry.canRecordReleaseData}`;
if (GeckoViewUtils.IS_PARENT_PROCESS) {
// Prevent dispatching snapshots before persistent data has been loaded.
this._loadComplete = new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
if (aTopic !== LOAD_COMPLETE_TOPIC) {
warn `Received unexpected topic ${aTopic}`;
return;
}
debug `observed ${aTopic} - ready to handle telemetry requests`;
// Loading data has completed, discard this observer.
Services.obs.removeObserver(observer, LOAD_COMPLETE_TOPIC);
resolve();
}, LOAD_COMPLETE_TOPIC);
});
try {
EventDispatcher.instance.registerListener(this, [
"GeckoView:TelemetrySnapshots",
]);
} catch (e) {
warn `Failed registering GeckoView:TelemetrySnapshots listener: ${e}`;
}
}
},
/**
* Handle GeckoView:TelemetrySnapshots requests.
* Match with RuntimeTelemetry.getSnapshots.
*
* @param aEvent Name of the event to dispatch.
* @param aData Optional object containing data for the event.
* @param aCallback Optional callback implementing nsIAndroidEventCallback.
*/
onEvent(aEvent, aData, aCallback) {
debug `onEvent: aEvent=${aEvent}, aData=${aData}`;
if (aEvent !== "GeckoView:TelemetrySnapshots") {
warn `Received unexpected event ${aEvent}`;
return;
}
// Handle this request when loading has completed.
this._loadComplete.then(() => this.retrieveSnapshots(aData.clear, aCallback));
},
/**
* Retrieve snapshots and forward them to the callback.
*
* @param aClear True if snapshot data should be cleared after retrieving.
* @param aCallback Callback implementing nsIAndroidEventCallback.
*/
retrieveSnapshots(aClear, aCallback) {
debug `retrieveSnapshots`;
// Selecting the opt-in dataset will ensure that we retrieve opt-in probes
// (iff canRecordPreRelease == true) and opt-out probes
// (iff canRecordRelease == true) if they are being recorded.
const dataset = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
const rawHistograms = Services.telemetry.snapshotHistograms(dataset,
/* subsession */ false,
/* clear */ false);
const rawKeyedHistograms =
Services.telemetry.snapshotKeyedHistograms(dataset, /* subsession */ false,
/* clear */ false);
const scalars = Services.telemetry.snapshotScalars(dataset, /* clear */ false);
const keyedScalars = Services.telemetry.snapshotKeyedScalars(dataset, /* clear */ false);
const snapshots = {
histograms: TelemetryUtils.packHistograms(rawHistograms),
keyedHistograms: TelemetryUtils.packKeyedHistograms(rawKeyedHistograms),
scalars,
keyedScalars,
};
if (!snapshots.histograms || !snapshots.keyedHistograms ||
!snapshots.scalars || !snapshots.keyedScalars) {
aCallback.onError(`Failed retrieving snapshots!`);
return;
}
let processSnapshots = {};
for (let [name, snapshot] of Object.entries(snapshots)) {
for (let [processName, processSnapshot] of Object.entries(snapshot)) {
if (!(processName in processSnapshots)) {
processSnapshots[processName] = {};
}
processSnapshots[processName][name] = processSnapshot;
}
}
if (aClear) {
Services.telemetry.clearProbes();
}
aCallback.onSuccess(processSnapshots);
},
};