Commit 1b4eae88 authored by Alex Cooper's avatar Alex Cooper Committed by Commit Bot

Update xr feature policy name and behavior to match spec

As a result of TPAC there were some spec changes to the xr feature
policy (FP). These were made in:
https://github.com/immersive-web/webxr/pull/842
The following changes were needed to become spec compliant:

* rename FP from "xr" to "xr-spatial-tracking"
* supportsSession always resolves for "inline"
* supportsSession rejects for immersive-vr with a SecurityError if FP
  not set
* default features per mode are now required features for that mode
* requestSession does not unconditionally reject if FP is not set,
  instead resolving specific features now depends on FP status.
* While resolving features, if any required features depend on a missing
  FP, the requestSession call will fail with a "NotSupportedError"
* While resolving features, if any optional features depend on a missing
  FP, those features will be silently ignored.
* devicechange events will not fire for documents that do not have
  FP set.

Bug: 1003842
Change-Id: Ie9ae16b5c1d863b730e556b511c024bae8a4503c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1808800
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Reviewed-by: default avatarIan Clelland <iclelland@chromium.org>
Reviewed-by: default avatarJacob DeWitt <jacde@chromium.org>
Auto-Submit: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701740}
parent 02badc14
......@@ -305,7 +305,7 @@
},
{
name: "WebXr",
feature_policy_name: "xr",
feature_policy_name: "xr-spatial-tracking",
depends_on: ["WebXR"],
},
// TODO(crbug.com/960132): WebVR added manually in feature_policy_helper.cc.
......
This diff is collapsed.
......@@ -232,16 +232,20 @@ class XR final : public EventTargetWithInlineData,
const char* CheckInlineSessionRequestAllowed(
LocalFrame* frame,
Document* doc,
const PendingRequestSessionQuery& query);
RequestedXRSessionFeatureSet ParseRequestedFeatures(
Document* doc,
const HeapVector<ScriptValue>& features,
const XRSession::SessionMode& session_mode,
mojom::ConsoleMessageLevel error_level);
void RequestImmersiveSession(LocalFrame* frame,
Document* doc,
PendingRequestSessionQuery* query,
ExceptionState* exception_state);
void RequestInlineSession(LocalFrame* frame,
Document* doc,
PendingRequestSessionQuery* query,
ExceptionState* exception_state);
......
......@@ -10,7 +10,7 @@ const check_report_format = ([reports, observer]) => {
const report = reports[0];
assert_equals(report.type, "feature-policy-violation");
assert_equals(report.url, document.location.href);
assert_equals(report.body.featureId, "xr");
assert_equals(report.body.featureId, "xr-spatial-tracking");
assert_equals(report.body.sourceFile, document.location.href);
assert_equals(typeof report.body.lineNumber, "number");
assert_equals(typeof report.body.columnNumber, "number");
......@@ -23,11 +23,12 @@ promise_test(async t => {
{types: ['feature-policy-violation']}).observe();
});
try {
await navigator.xr.supportsSession('inline');
let supported = await navigator.xr.isSessionSupported('immersive-vr');
} catch (err) {
// If no XR devices are available, supportsSession() will reject with a
// NotSupportedError, but the report should be generated anyway.
assert_equals(err.name, 'NotSupportedError');
// IsSessionSupported should only throw with a feature policy violation;
// however, inline does not trigger the feature policy,
// so immersive-vr must be used.
assert_unreached("isSessionSupported should not throw in ReportOnly mode");
}
check_report_format(await report);
}, "XR report only mode");
......
Feature-Policy-Report-Only: xr 'none'
Feature-Policy-Report-Only: xr-spatial-tracking 'none'
......@@ -10,7 +10,7 @@ var check_report_format = (reports, observer) => {
let report = reports[0];
assert_equals(report.type, "feature-policy-violation");
assert_equals(report.url, document.location.href);
assert_equals(report.body.featureId, "xr");
assert_equals(report.body.featureId, "xr-spatial-tracking");
assert_equals(report.body.sourceFile, document.location.href);
assert_equals(typeof report.body.lineNumber, "number");
assert_equals(typeof report.body.columnNumber, "number");
......@@ -22,8 +22,9 @@ promise_test(async (t) => {
new ReportingObserver((reports, observer) => resolve([reports, observer]),
{types: ['feature-policy-violation']}).observe();
});
await promise_rejects(t, 'SecurityError', navigator.xr.supportsSession('inline'),
"XR device access should not be allowed in this document.");
await promise_rejects(t, 'SecurityError',
navigator.xr.isSessionSupported('immersive-vr'),
"XR spatial tracking should not be allowed in this document.");
const [reports, observer] = await report;
check_report_format(reports, observer);
}, "XR Report Format");
......
......@@ -16,6 +16,15 @@ function xr_promise_test(name, func, properties) {
await loadChromiumResources;
}
// Ensure that any devices are disconnected when done. If this were done in
// a .then() for the success case, a test that expected failure would
// already be marked done at the time that runs and the shutdown would
// interfere with the next test.
t.add_cleanup(async () => {
// Ensure system state is cleaned up.
await navigator.xr.test.disconnectAllDevices();
});
return func(t);
}, name, properties);
}
......@@ -44,19 +53,16 @@ function xr_session_promise_test(
xr_promise_test(
name,
(t) => {
// Ensure that any pending sessions are ended and devices are
// disconnected when done. This needs to use a cleanup function to
// ensure proper sequencing. If this were done in a .then() for the
// success case, a test that expected failure would already be marked
// done at the time that runs, and the shutdown would interfere with
// the next test which may have started already.
// Ensure that any pending sessions are ended when done. This needs to
// use a cleanup function to ensure proper sequencing. If this were
// done in a .then() for the success case, a test that expected
// failure would already be marked done at the time that runs, and the
// shutdown would interfere with the next test which may have started.
t.add_cleanup(async () => {
// If a session was created, end it.
if (testSession) {
await testSession.end().catch(() => {});
}
// Cleanup system state.
await navigator.xr.test.disconnectAllDevices();
// If a session was created, end it.
if (testSession) {
await testSession.end().catch(() => {});
}
});
return navigator.xr.test.simulateDeviceConnection(fakeDeviceInit)
......
......@@ -5,6 +5,6 @@
<script src="/resources/testharnessreport.js"></script>
<script>
test(() => {
assert_in_array('xr', document.featurePolicy.features());
}, 'document.featurePolicy.features should advertise xr.');
assert_in_array('xr-spatial-tracking', document.featurePolicy.features());
}, 'document.featurePolicy.features should advertise xr-spatial-tracking.');
</script>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webxr_util.js"></script>
<script src="resources/webxr_test_constants.js"></script>
<canvas />
<script>
xr_promise_test(
"Validate isSessionSupported behavior without xr-spatial-tracking policy",
(t) => {
// Inline should never reject.
return navigator.xr.isSessionSupported("inline").then((supported) => {
t.step(() => {
assert_true(supported,
"inline should always be supported, even without feature policy");
});
// It shouldn't matter that there's no device connected, the SecurityError
// should reject first.
return promise_rejects(t, "SecurityError",
navigator.xr.isSessionSupported("immersive-vr"),
"Immersive isSessionSupported should reject");
});
});
xr_promise_test(
"Validate requestSession behavior without xr-spatial-tracking policy",
(t) => {
return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
.then(() => {
return new Promise((resolve, reject) => {
navigator.xr.test.simulateUserActivation(() => {
// Technically the first "requestSession" doesn't need either the device
// or the activation, but this makes the test code a little cleaner since
// the others do, as lacking user activation or a valid backing device
// should also cause the session to reject. In order to guarantee that
// we're seeing the rejection we want, we eliminate those as possibilities.
resolve(Promise.all([
navigator.xr.requestSession("inline").then(session => session.end()),
promise_rejects(t, "NotSupportedError",
navigator.xr.requestSession("inline", { requiredFeatures: ["local"] }),
"Inline with features should reject without feature policy"),
promise_rejects(t, "NotSupportedError",
navigator.xr.requestSession("immersive-vr"),
"Immersive-vr should reject without feature policy")
]));
});
});
});
});
xr_promise_test(
"Validate devicechange event behavior without xr-spatial-tracking policy",
(t) => {
navigator.xr.addEventListener("devicechange", () => {
t.step(() => { assert_unreached("devicechange should not fire"); });
})
// We need to yield a short time to ensure that any event registration has
// propagated, as this can take some time.
// Note that device connection is not guaranteed to fire per the spec, if it's
// the first connection, but disconnect definitely should.
t.step_timeout(() => {
navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
.then((testDeviceController) => {
return testDeviceController.disconnect();
});
}, 100);
// Wait an even longer time before finishing the test, so that if the event
// were to fire, it would've by now.
return new Promise((resolve) => {
t.step_timeout(() => { resolve(); }, 2000);
});
});
</script>
......@@ -17,11 +17,11 @@ test(t => {
test(() => {
if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
assert_in_array('xr', document.featurePolicy.features());
assert_in_array('xr-spatial-tracking', document.featurePolicy.features());
} else {
assert_equals(document.featurePolicy.features().indexOf("xr"), -1);
assert_equals(document.featurePolicy.features().indexOf("xr-spatial-tracking"), -1);
}
}, 'document.featurePolicy.features does not advertise xr without a token or flag.');
}, 'document.featurePolicy.features does not advertise xr-spatial-tracking without a token or flag.');
// Add the token, which was generated with the following command:
// tools/origin_trials/generate_token.py http://127.0.0.1:8000 WebXRDeviceM76 --expire-timestamp=2000000000
......@@ -34,8 +34,8 @@ test(t => {
}, "WebXR's entrypoint properties are available with origin trial token.");
test(() => {
assert_in_array('xr', document.featurePolicy.features());
}, 'document.featurePolicy.features advertises xr after token added.');
assert_in_array('xr-spatial-tracking', document.featurePolicy.features());
}, 'document.featurePolicy.features advertises xr-spatial-tracking after token added.');
// Ensure Gamepad Extensions are NOT enabled by the WebXR origin trial token.
test(t => {
......
......@@ -59,5 +59,5 @@ usb
vertical-scroll
vr
wake-lock
xr
xr-spatial-tracking
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment