Skip to content

Commit c8e8ca2

Browse files
committed
Bug 1784258 - Add new telemetry probe for the DoH disablement reason r=necko-reviewers,kershaw
This patch adds the following scalars: `networking.doh_heuristics_attempts` - contains the number of heuristic attempts we performed during a subsession. `networking.doh_heuristics_pass_count` - contains the number of times we passed heuristic during a subsession. `networking.doh_heuristics_result` - the result of the last heuristic run. `networking.doh_heuristic_ever_tripped` - a keyed scalar containing true if a heuristic was ever tripped during a subsession and false otherwise. Differential Revision: https://phabricator.services.mozilla.com/D187983
1 parent 97fa8be commit c8e8ca2

File tree

8 files changed

+392
-3
lines changed

8 files changed

+392
-3
lines changed

browser/components/doh/DoHController.sys.mjs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ export const DoHController = {
161161
lazy.Preferences.observe(NATIVE_FALLBACK_WARNING_HEURISTIC_LIST_PREF, this);
162162

163163
if (lazy.DoHConfigController.currentConfig.enabled) {
164+
// At init time set these heuristics to false if we may run heuristics
165+
for (let key of lazy.Heuristics.Telemetry.heuristicNames()) {
166+
Services.telemetry.keyedScalarSet(
167+
"networking.doh_heuristic_ever_tripped",
168+
key,
169+
false
170+
);
171+
}
172+
164173
await this.maybeEnableHeuristics();
165174
} else if (lazy.Preferences.get(FIRST_RUN_PREF, false)) {
166175
await this.rollback();
@@ -216,8 +225,32 @@ export const DoHController = {
216225

217226
let policyResult = await lazy.Heuristics.checkEnterprisePolicy();
218227

219-
if (["policy_without_doh", "disable_doh"].includes(policyResult)) {
220-
await this.setState("policyDisabled");
228+
if (policyResult != "no_policy_set") {
229+
switch (policyResult) {
230+
case "policy_without_doh":
231+
Services.telemetry.scalarSet(
232+
"networking.doh_heuristics_result",
233+
lazy.Heuristics.Telemetry.enterprisePresent
234+
);
235+
await this.setState("policyDisabled");
236+
break;
237+
case "disable_doh":
238+
Services.telemetry.scalarSet(
239+
"networking.doh_heuristics_result",
240+
lazy.Heuristics.Telemetry.enterpriseDisabled
241+
);
242+
await this.setState("policyDisabled");
243+
break;
244+
case "enable_doh":
245+
// The TRR mode has already been set, so theoretically we should not get here.
246+
// XXX: should we skip heuristics or continue?
247+
// TODO: Make sure we use the correct URL if the policy defines one.
248+
Services.telemetry.scalarSet(
249+
"networking.doh_heuristics_result",
250+
lazy.Heuristics.Telemetry.enterpriseEnabled
251+
);
252+
break;
253+
}
221254
lazy.Preferences.set(SKIP_HEURISTICS_PREF, true);
222255
return;
223256
}
@@ -326,6 +359,11 @@ export const DoHController = {
326359
async runHeuristics(evaluateReason) {
327360
let start = Date.now();
328361

362+
Services.telemetry.scalarAdd("networking.doh_heuristics_attempts", 1);
363+
Services.telemetry.scalarSet(
364+
"networking.doh_heuristics_result",
365+
lazy.Heuristics.Telemetry.incomplete
366+
);
329367
let results = await lazy.Heuristics.run();
330368

331369
if (
@@ -339,6 +377,10 @@ export const DoHController = {
339377
// during this heuristics run. We simply discard the results in this case.
340378
// Same thing if there was another heuristics run triggered or if we have
341379
// detected a locked captive portal while this one was ongoing.
380+
Services.telemetry.scalarSet(
381+
"networking.doh_heuristics_result",
382+
lazy.Heuristics.Telemetry.ignored
383+
);
342384
return;
343385
}
344386

@@ -382,6 +424,11 @@ export const DoHController = {
382424

383425
this.setHeuristicResult(Ci.nsITRRSkipReason.TRR_UNSET);
384426
if (decision === lazy.Heuristics.DISABLE_DOH) {
427+
Services.telemetry.scalarSet(
428+
"networking.doh_heuristics_result",
429+
lazy.Heuristics.Telemetry.fromResults(results)
430+
);
431+
385432
let fallbackHeuristicTripped = undefined;
386433
if (lazy.Preferences.get(NATIVE_FALLBACK_WARNING_PREF, false)) {
387434
let heuristics = lazy.Preferences.get(
@@ -411,6 +458,11 @@ export const DoHController = {
411458

412459
await this.setState("disabled");
413460
} else {
461+
Services.telemetry.scalarSet(
462+
"networking.doh_heuristics_result",
463+
lazy.Heuristics.Telemetry.pass
464+
);
465+
Services.telemetry.scalarAdd("networking.doh_heuristics_pass_count", 1);
414466
await this.setState("enabled");
415467
}
416468

@@ -440,6 +492,14 @@ export const DoHController = {
440492
} else if (["vpn", "proxy", "nrpt"].includes(heuristicName)) {
441493
platform.push(heuristicName);
442494
}
495+
496+
if (lazy.Heuristics.Telemetry.heuristicNames().includes(heuristicName)) {
497+
Services.telemetry.keyedScalarSet(
498+
"networking.doh_heuristic_ever_tripped",
499+
heuristicName,
500+
true
501+
);
502+
}
443503
}
444504

445505
resultsForTelemetry.canaries = canaries.join(",");
@@ -488,6 +548,32 @@ export const DoHController = {
488548
state,
489549
"null"
490550
);
551+
552+
let modePref = lazy.Preferences.get(NETWORK_TRR_MODE_PREF);
553+
if (state == "manuallyDisabled") {
554+
if (
555+
modePref == Ci.nsIDNSService.MODE_TRRFIRST ||
556+
modePref == Ci.nsIDNSService.MODE_TRRONLY
557+
) {
558+
Services.telemetry.scalarSet(
559+
"networking.doh_heuristics_result",
560+
lazy.Heuristics.Telemetry.manuallyEnabled
561+
);
562+
} else if (
563+
lazy.Preferences.get("doh-rollout.doorhanger-decision", "") ==
564+
"UIDisabled"
565+
) {
566+
Services.telemetry.scalarSet(
567+
"networking.doh_heuristics_result",
568+
lazy.Heuristics.Telemetry.optOut
569+
);
570+
} else {
571+
Services.telemetry.scalarSet(
572+
"networking.doh_heuristics_result",
573+
lazy.Heuristics.Telemetry.manuallyDisabled
574+
);
575+
}
576+
}
491577
},
492578

493579
async disableHeuristics(state) {

browser/components/doh/DoHHeuristics.sys.mjs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,55 @@ export const Heuristics = {
105105
}
106106
return Ci.nsITRRSkipReason.TRR_FAILED;
107107
},
108+
109+
// Keep this in sync with the description of networking.doh_heuristics_result
110+
// defined in Scalars.yaml
111+
Telemetry: {
112+
incomplete: 0,
113+
pass: 1,
114+
optOut: 2,
115+
manuallyDisabled: 3,
116+
manuallyEnabled: 4,
117+
enterpriseDisabled: 5,
118+
enterprisePresent: 6,
119+
enterpriseEnabled: 7,
120+
vpn: 8,
121+
proxy: 9,
122+
nrpt: 10,
123+
browserParent: 11,
124+
modifiedRoots: 12,
125+
thirdPartyRoots: 13,
126+
google: 14,
127+
youtube: 15,
128+
zscalerCanary: 16,
129+
canary: 17,
130+
ignored: 18,
131+
132+
heuristicNames() {
133+
return [
134+
"google",
135+
"youtube",
136+
"zscalerCanary",
137+
"canary",
138+
"modifiedRoots",
139+
"browserParent",
140+
"thirdPartyRoots",
141+
"policy",
142+
"vpn",
143+
"proxy",
144+
"nrpt",
145+
];
146+
},
147+
148+
fromResults(results) {
149+
for (let label of Heuristics.Telemetry.heuristicNames()) {
150+
if (results[label] == Heuristics.DISABLE_DOH) {
151+
return Heuristics.Telemetry[label];
152+
}
153+
}
154+
return Heuristics.Telemetry.pass;
155+
},
156+
},
108157
};
109158

110159
async function dnsLookup(hostname, resolveCanonicalName = false) {

browser/components/doh/test/browser/browser_doorhangerUserReject.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ add_task(async function testDoorhangerUserReject() {
2828
await ensureTRRMode(2);
2929
await checkHeuristicsTelemetry("enable_doh", "startup");
3030

31+
checkScalars([
32+
["networking.doh_heuristics_attempts", { value: 1 }],
33+
["networking.doh_heuristics_pass_count", { value: 1 }],
34+
["networking.doh_heuristics_result", { value: Heuristics.Telemetry.pass }],
35+
// All of the heuristics must be false.
36+
falseExpectations([]),
37+
]);
38+
3139
prefPromise = TestUtils.waitForPrefChange(
3240
prefs.DOORHANGER_USER_DECISION_PREF
3341
);
@@ -52,6 +60,17 @@ add_task(async function testDoorhangerUserReject() {
5260
ensureNoHeuristicsTelemetry();
5361
is(Preferences.get(prefs.BREADCRUMB_PREF), undefined, "Breadcrumb cleared.");
5462

63+
checkScalars([
64+
["networking.doh_heuristics_attempts", { value: 1 }],
65+
["networking.doh_heuristics_pass_count", { value: 1 }],
66+
[
67+
"networking.doh_heuristics_result",
68+
{ value: Heuristics.Telemetry.optOut },
69+
],
70+
// All of the heuristics must be false.
71+
falseExpectations([]),
72+
]);
73+
5574
// Simulate a network change.
5675
simulateNetworkChange();
5776
await ensureNoTRRModeChange(undefined);

browser/components/doh/test/browser/browser_platformDetection.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ add_task(setup);
1212

1313
add_task(async function testPlatformIndications() {
1414
// Check if the platform heuristics actually cause a "disable_doh" event
15-
1615
let { MockRegistrar } = ChromeUtils.importESModule(
1716
"resource://testing-common/MockRegistrar.sys.mjs"
1817
);
@@ -45,29 +44,83 @@ add_task(async function testPlatformIndications() {
4544
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
4645
await checkHeuristicsTelemetry("enable_doh", "startup");
4746

47+
checkScalars([
48+
["networking.doh_heuristics_attempts", { value: 1 }],
49+
["networking.doh_heuristics_pass_count", { value: 1 }],
50+
["networking.doh_heuristics_result", { value: Heuristics.Telemetry.pass }],
51+
// All of the heuristics must be false.
52+
falseExpectations([]),
53+
]);
54+
4855
await ensureTRRMode(2);
4956

5057
mockedLinkService.platformDNSIndications =
5158
Ci.nsINetworkLinkService.VPN_DETECTED;
5259
simulateNetworkChange();
5360
await ensureTRRMode(0);
5461
await checkHeuristicsTelemetry("disable_doh", "netchange");
62+
checkScalars(
63+
[
64+
["networking.doh_heuristics_attempts", { value: 2 }],
65+
["networking.doh_heuristics_pass_count", { value: 1 }],
66+
["networking.doh_heuristics_result", { value: Heuristics.Telemetry.vpn }],
67+
["networking.doh_heuristic_ever_tripped", { value: true, key: "vpn" }],
68+
].concat(falseExpectations(["vpn"]))
69+
);
5570

5671
mockedLinkService.platformDNSIndications =
5772
Ci.nsINetworkLinkService.PROXY_DETECTED;
5873
simulateNetworkChange();
5974
await ensureNoTRRModeChange(0);
6075
await checkHeuristicsTelemetry("disable_doh", "netchange");
76+
checkScalars(
77+
[
78+
["networking.doh_heuristics_attempts", { value: 3 }],
79+
["networking.doh_heuristics_pass_count", { value: 1 }],
80+
[
81+
"networking.doh_heuristics_result",
82+
{ value: Heuristics.Telemetry.proxy },
83+
],
84+
["networking.doh_heuristic_ever_tripped", { value: true, key: "vpn" }], // Was tripped earlier this session
85+
["networking.doh_heuristic_ever_tripped", { value: true, key: "proxy" }],
86+
].concat(falseExpectations(["vpn", "proxy"]))
87+
);
6188

6289
mockedLinkService.platformDNSIndications =
6390
Ci.nsINetworkLinkService.NRPT_DETECTED;
6491
simulateNetworkChange();
6592
await ensureNoTRRModeChange(0);
6693
await checkHeuristicsTelemetry("disable_doh", "netchange");
94+
checkScalars(
95+
[
96+
["networking.doh_heuristics_attempts", { value: 4 }],
97+
["networking.doh_heuristics_pass_count", { value: 1 }],
98+
[
99+
"networking.doh_heuristics_result",
100+
{ value: Heuristics.Telemetry.nrpt },
101+
],
102+
["networking.doh_heuristic_ever_tripped", { value: true, key: "vpn" }], // Was tripped earlier this session
103+
["networking.doh_heuristic_ever_tripped", { value: true, key: "proxy" }], // Was tripped earlier this session
104+
["networking.doh_heuristic_ever_tripped", { value: true, key: "nrpt" }],
105+
].concat(falseExpectations(["vpn", "proxy", "nrpt"]))
106+
);
67107

68108
mockedLinkService.platformDNSIndications =
69109
Ci.nsINetworkLinkService.NONE_DETECTED;
70110
simulateNetworkChange();
71111
await ensureTRRMode(2);
72112
await checkHeuristicsTelemetry("enable_doh", "netchange");
113+
checkScalars(
114+
[
115+
["networking.doh_heuristics_attempts", { value: 5 }],
116+
["networking.doh_heuristics_pass_count", { value: 2 }],
117+
[
118+
"networking.doh_heuristics_result",
119+
{ value: Heuristics.Telemetry.pass },
120+
],
121+
["networking.doh_heuristic_ever_tripped", { value: true, key: "vpn" }], // Was tripped earlier this session
122+
["networking.doh_heuristic_ever_tripped", { value: true, key: "proxy" }], // Was tripped earlier this session
123+
["networking.doh_heuristic_ever_tripped", { value: true, key: "nrpt" }], // Was tripped earlier this session
124+
].concat(falseExpectations(["vpn", "proxy", "nrpt"]))
125+
);
73126
});

browser/components/doh/test/browser/browser_policyOverride.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ add_task(async function testPolicyOverride() {
4747
await ensureNoTRRModeChange(undefined);
4848
ensureNoHeuristicsTelemetry();
4949

50+
checkScalars(
51+
[
52+
[
53+
"networking.doh_heuristics_result",
54+
{ value: Heuristics.Telemetry.enterprisePresent },
55+
],
56+
// All of the heuristics must be false.
57+
].concat(falseExpectations([]))
58+
);
59+
5060
// Simulate a network change.
5161
simulateNetworkChange();
5262
await ensureNoTRRModeChange(undefined);

0 commit comments

Comments
 (0)