gecko-dev/toolkit/components/telemetry/geckoview/GeckoViewTelemetryController.jsm
2020-03-08 21:45:16 +00:00

147 lines
4.4 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";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { GeckoViewUtils } = 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",
});
const { debug, warn } = GeckoViewUtils.initLogging(
"GeckoView.TelemetryController"
); // eslint-disable-line no-unused-vars
var EXPORTED_SYMBOLS = ["GeckoViewTelemetryController"];
// 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`;
const histograms = Services.telemetry.getSnapshotForHistograms(
"main",
/* clear */ false
);
const keyedHistograms = Services.telemetry.getSnapshotForKeyedHistograms(
"main",
/* clear */ false
);
const scalars = Services.telemetry.getSnapshotForScalars(
"main",
/* clear */ false
);
const keyedScalars = Services.telemetry.getSnapshotForKeyedScalars(
"main",
/* clear */ false
);
const snapshots = {
histograms,
keyedHistograms,
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);
},
};