Bug 1356323 - Add telemetry for time spent injecting content scripts, r?kmag
MozReview-Commit-ID: Aa0gah03QnN
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -14,16 +14,18 @@ Cu.import("resource://gre/modules/Servic
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
"resource:///modules/translation/LanguageDetector.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
+ "resource://gre/modules/TelemetryStopwatch.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
// xpcshell doesn't handle idle callbacks well.
@@ -64,16 +66,17 @@ const {
} = ExtensionChild;
XPCOMUtils.defineLazyGetter(this, "console", ExtensionUtils.getConsole);
var DocumentManager;
const CATEGORY_EXTENSION_SCRIPTS_CONTENT = "webextension-scripts-content";
+const CONTENT_SCRIPT_INJECTION_HISTOGRAM = "WEBEXT_CONTENT_SCRIPT_INJECTION_MS";
var apiManager = new class extends SchemaAPIManager {
constructor() {
super("content");
this.initialized = false;
}
lazyInit() {
@@ -325,22 +328,27 @@ class Script {
if (this.runAt === "document_idle") {
await new Promise(resolve =>
context.contentWindow.requestIdleCallback(resolve,
{timeout: idleTimeout}));
}
// The evaluations below may throw, in which case the promise will be
// automatically rejected.
- for (let script of scripts) {
- result = script.executeInGlobal(context.cloneScope);
- }
+ TelemetryStopwatch.start(CONTENT_SCRIPT_INJECTION_HISTOGRAM, context);
+ try {
+ for (let script of scripts) {
+ result = script.executeInGlobal(context.cloneScope);
+ }
- if (this.matcher.jsCode) {
- result = Cu.evalInSandbox(this.matcher.jsCode, context.cloneScope, "latest");
+ if (this.matcher.jsCode) {
+ result = Cu.evalInSandbox(this.matcher.jsCode, context.cloneScope, "latest");
+ }
+ } finally {
+ TelemetryStopwatch.finish(CONTENT_SCRIPT_INJECTION_HISTOGRAM, context);
}
await cssPromise;
return result;
}
}
defineLazyGetter(Script.prototype, "cssURLs", function() {
--- a/toolkit/components/extensions/test/mochitest/chrome.ini
+++ b/toolkit/components/extensions/test/mochitest/chrome.ini
@@ -11,16 +11,17 @@ support-files =
webrequest_test.jsm
oauth.html
redirect_auto.sjs
tags = webextensions in-process-webextensions
[test_chrome_ext_background_page.html]
skip-if = (toolkit == 'android') # android doesn't have devtools
[test_chrome_ext_contentscript_data_uri.html]
+[test_chrome_ext_contentscript_telemetry.html]
[test_chrome_ext_contentscript_unrecognizedprop_warning.html]
[test_chrome_ext_downloads_open.html]
[test_chrome_ext_downloads_saveAs.html]
[test_chrome_ext_eventpage_warning.html]
[test_chrome_ext_hybrid_addons.html]
[test_chrome_ext_idle.html]
[test_chrome_ext_identity.html]
skip-if = os == 'android' # unsupported.
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_contentscript_telemetry.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test for telemetry for content script injection</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
+ <script src="head.js"></script>
+ <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script>
+"use strict";
+
+const HISTOGRAM = "WEBEXT_CONTENT_SCRIPT_INJECTION_MS";
+
+add_task(async function test_contentscript_telemetry() {
+ function background() {
+ browser.test.onMessage.addListener(() => {
+ browser.tabs.executeScript({code: 'browser.test.sendMessage("content-script-run");'});
+ });
+ }
+
+ let extensionData = {
+ manifest: {
+ permissions: ["<all_urls>"],
+ },
+ background,
+ };
+
+ let win = window.open("http://example.com/");
+
+ let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+ let histogram = SpecialPowers.Services.telemetry.getHistogramById(HISTOGRAM);
+ histogram.clear();
+ is(histogram.snapshot().sum, 0,
+ `No data recorded for histogram: ${HISTOGRAM}.`);
+
+ await extension.startup();
+ is(histogram.snapshot().sum, 0,
+ `No data recorded for histogram after startup: ${HISTOGRAM}.`);
+
+ extension.sendMessage();
+ await extension.awaitMessage("content-script-run");
+
+ let histogramSum = histogram.snapshot().sum;
+ ok(histogramSum > 0,
+ `Data recorded for first extension for histogram: ${HISTOGRAM}.`);
+
+ win.close();
+ await extension.unload();
+});
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_extension_content_telemetry.js
@@ -0,0 +1,73 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+const HISTOGRAM = "WEBEXT_CONTENT_SCRIPT_INJECTION_MS";
+
+const server = createHttpServer();
+server.registerDirectory("/data/", do_get_file("data"));
+
+const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
+
+add_task(async function test_telemetry() {
+ function contentScript() {
+ browser.test.sendMessage("content-script-run");
+ }
+
+ let extension1 = ExtensionTestUtils.loadExtension({
+ manifest: {
+ content_scripts: [{
+ "matches": ["http://*/*/file_sample.html"],
+ "js": ["content_script.js"],
+ "run_at": "document_end",
+ }],
+ },
+
+ files: {
+ "content_script.js": contentScript,
+ },
+ });
+ let extension2 = ExtensionTestUtils.loadExtension({
+ manifest: {
+ content_scripts: [{
+ "matches": ["http://*/*/file_sample.html"],
+ "js": ["content_script.js"],
+ "run_at": "document_end",
+ }],
+ },
+
+ files: {
+ "content_script.js": contentScript,
+ },
+ });
+
+ let histogram = Services.telemetry.getHistogramById(HISTOGRAM);
+ histogram.clear();
+ equal(histogram.snapshot().sum, 0,
+ `No data recorded for histogram: ${HISTOGRAM}.`);
+
+ await extension1.startup();
+ equal(histogram.snapshot().sum, 0,
+ `No data recorded for histogram after startup: ${HISTOGRAM}.`);
+
+ let contentPage = await ExtensionTestUtils.loadContentPage(`${BASE_URL}/file_sample.html`);
+ await extension1.awaitMessage("content-script-run");
+ let histogramSum = histogram.snapshot().sum;
+ ok(histogramSum > 0,
+ `Data recorded for first extension for histogram: ${HISTOGRAM}.`);
+
+ await contentPage.close();
+ await extension1.unload();
+
+ await extension2.startup();
+ equal(histogram.snapshot().sum, histogramSum,
+ `No data recorded for histogram after startup: ${HISTOGRAM}.`);
+
+ contentPage = await ExtensionTestUtils.loadContentPage(`${BASE_URL}/file_sample.html`);
+ await extension2.awaitMessage("content-script-run");
+ ok(histogram.snapshot().sum > histogramSum,
+ `Data recorded for second extension for histogram: ${HISTOGRAM}.`);
+
+ await contentPage.close();
+ await extension2.unload();
+});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -37,19 +37,20 @@ skip-if = os == "android" # Containers a
[test_ext_downloads_download.js]
skip-if = os == "android"
[test_ext_downloads_misc.js]
skip-if = os == "android" || (os=='linux' && bits==32) # linux32: bug 1324870
[test_ext_downloads_search.js]
skip-if = os == "android"
[test_ext_experiments.js]
[test_ext_extension.js]
+[test_ext_extension_content_telemetry.js]
+[test_ext_extension_startup_telemetry.js]
[test_ext_extensionPreferencesManager.js]
[test_ext_extensionSettingsStore.js]
-[test_ext_extension_startup_telemetry.js]
[test_ext_idle.js]
[test_ext_json_parser.js]
[test_ext_localStorage.js]
[test_ext_management.js]
[test_ext_management_uninstall_self.js]
[test_ext_manifest_content_security_policy.js]
[test_ext_manifest_incognito.js]
[test_ext_manifest_minimum_chrome_version.js]
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13419,16 +13419,27 @@
"alert_emails": ["addons-dev-internal@mozilla.com"],
"bug_numbers": [1297167],
"expires_in_version": "60",
"kind": "categorical",
"labels": ["popupShown", "clearAfterHover", "clearAfterMousedown"],
"releaseChannelCollection": "opt-out",
"description": "The number of times a browserAction popup is preloaded and results in one of the categories."
},
+ "WEBEXT_CONTENT_SCRIPT_INJECTION_MS": {
+ "record_in_processes": ["main", "content"],
+ "alert_emails": ["addons-dev-internal@mozilla.com"],
+ "bug_numbers": [1356323],
+ "expires_in_version": "60",
+ "kind": "exponential",
+ "releaseChannelCollection": "opt-out",
+ "high": 50000,
+ "n_buckets": 100,
+ "description": "The amount of time it takes for content scripts from a WebExtension to be injected into a window."
+ },
"WEBEXT_EXTENSION_STARTUP_MS": {
"record_in_processes": ["main"],
"alert_emails": ["addons-dev-internal@mozilla.com"],
"bug_numbers": [1353171],
"expires_in_version": "60",
"kind": "exponential",
"releaseChannelCollection": "opt-out",
"high": 50000,