compute pressure: Replace quantization with pressure states

As described in [1], compute pressure is using pressure states
instead of quantized value of cpuUtilization and bucketing.

This patch is implementing the following:
 - Removing the quantization of cpuUtilization, bucketing
   and instead is replacing cpu_utilization value with a pressure
   state.
 - A timestamp is retrieved and passed to the web API as defined
   in [2]
 - With the removal of quantization schemes, it is now possible to
   register any number of observers without stopping existing ones
   (which was the case when the quantization scheme of a new observer
   was different)
 - Compute pressure disconnect tests have been reduced. Previously
   quantization threshold changes were resetting the
   PressureServiceImpl object. In the new version, adding a new
   observer doesn't reset the PressureServiceImpl object anymore and
   therefore doesn't send new updates to the PressureObserverManager
   instance if the new update is similar to the previous reported one.
 - As mentioned, there is no reset of the PressureServiceImpl, and the
   filtering of similar updates is happening before the
   PressureObserverManager instance. Therefore it is necessary to
   save ´last_reported_update_´ to update newly registered observers
   with the latest reported update, as well as making sure that if the
   backend is ready before the binding, there is a trace of the first
   update before upcoming ones could be filtered if similar.
   ´last_reported_update_´ will be removed whenever the updates
   filtering will be moved to the PressureObserver class as discussed
   in [3].

[1] https://github.com/WICG/compute-pressure/commit/e3da844ddb2a9bf5d8c86ab561f62bf666ed6d27
[2] https://github.com/WICG/compute-pressure/commit/a10b940a9d50fa3cc526d2b888afe6773d706b20
[3] https://github.com/WICG/compute-pressure/issues/121

Bug: 1306803, 1308316
Change-Id: I60dc2a8b789bdc7808e2629d67541cc6755ecbd1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3865537
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Reviewed-by: Matthew Denton <mpdenton@chromium.org>
Commit-Queue: Arnaud Mandy <arnaud.mandy@intel.com>
Reviewed-by: Raphael Kubo Da Costa <raphael.kubo.da.costa@intel.com>
Reviewed-by: Fr <beaufort.francois@gmail.com>
Cr-Commit-Position: refs/heads/main@{#1050137}
diff --git a/compute-pressure/compute_pressure_arguments.tentative.https.window.js b/compute-pressure/compute_pressure_arguments.tentative.https.window.js
deleted file mode 100644
index 0c391a2..0000000
--- a/compute-pressure/compute_pressure_arguments.tentative.https.window.js
+++ /dev/null
@@ -1,44 +0,0 @@
-'use strict';
-
-for (const property of ['cpuUtilizationThresholds']) {
-  for (const out_of_range_value of [-1.0, 0.0, 1.0, 2.0]) {
-    test(t => {
-      const callback = () => {};
-
-      const options = {
-          cpuUtilizationThresholds: [0.5] };
-      options[property] = [out_of_range_value];
-
-      assert_throws_js(TypeError, () => {
-        new PressureObserver(callback, options);
-      });
-    }, `PressureObserver constructor throws when ${property} ` +
-       `is [${out_of_range_value}]`);
-  }
-
-  for (const valid_value of [0.05, 0.1, 0.2, 0.5, 0.9, 0.95]) {
-    test(t => {
-      const callback = () => {};
-
-      const options = {
-          cpuUtilizationThresholds: [0.5] };
-      options[property] = [valid_value];
-
-      const observer = new PressureObserver(callback, options);
-      assert_true(observer instanceof PressureObserver);
-    }, `PressureObserver constructor accepts ${property} value ` +
-       `[${valid_value}]`);
-  }
-}
-
-test(t => {
-  const callback = () => {};
-
-
-  assert_throws_js(TypeError, () => {
-    new PressureObserver(
-        callback,
-        { cpuUtilizationThresholds: [0.5, 0.5] });
-  });
-}, 'PressureObserver constructor throws when cpuUtilizationThresholds ' +
-   'has duplicates');
diff --git a/compute-pressure/compute_pressure_basic.tentative.https.window.js b/compute-pressure/compute_pressure_basic.tentative.https.window.js
index 7c939ba..59aba72 100644
--- a/compute-pressure/compute_pressure_basic.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_basic.tentative.https.window.js
@@ -1,39 +1,28 @@
 'use strict';
 
 promise_test(async t => {
-  // The quantization thresholds and the quantized values that they lead to can
-  // be represented exactly in floating-point, so === comparison works.
-
-  const update = await new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+  await new Promise((resolve, reject) => {
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
-
-  assert_equals(typeof update.cpuUtilization, 'number');
-  assert_greater_than_equal(update.cpuUtilization, 0.0, 'cpuUtilization range');
-  assert_less_than_equal(update.cpuUtilization, 1.0, 'cpuUtilization range');
-  assert_in_array(update.cpuUtilization, [0.25, 0.75],
-                  'cpuUtilization quantization');
 }, 'An active PressureObserver calls its callback at least once');
 
 promise_test(async t => {
   const observer1_updates = [];
   const update = await new Promise(async resolve => {
     const observer1 = new PressureObserver(
-        update => {observer1_updates.push(update)},
-        {cpuUtilizationThresholds: [0.5]});
+        update1 => {observer1_updates.push(update1)}, {sampleRate: 1.0});
     await observer1.observe('cpu');
 
-    const observer2 =
-        new PressureObserver(resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer2 = new PressureObserver(resolve, {sampleRate: 1.0});
     await observer2.observe('cpu');
   });
 
   assert_in_array(
-      update.cpuUtilization, [0.25, 0.75], 'cpuUtilization quantization')
+      update.state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
   assert_in_array(
-      observer1_updates[0].cpuUtilization, [0.25, 0.75],
-      'cpuUtilization quantization');
-}, 'Same quantization should also update second observer');
+      observer1_updates[0].state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
+}, 'Newly registered observer should get update');
diff --git a/compute-pressure/compute_pressure_basic_async.tentative.https.window.js b/compute-pressure/compute_pressure_basic_async.tentative.https.window.js
index 17c1222..a67f27c 100644
--- a/compute-pressure/compute_pressure_basic_async.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_basic_async.tentative.https.window.js
@@ -26,11 +26,13 @@
   const update = await new Promise(async resolve => {
     const observer = new PressureObserver(resolve);
     await observer.observe('cpu');
-
-    mockPressureService.setPressureState({cpuUtilization: 0.5});
+    mockPressureService.setPressureUpdate('critical');
     mockPressureService.sendUpdate();
   });
-  assert_equals(update.cpuUtilization, 0.5);
+  assert_equals(update.state, 'critical');
+  assert_equals(update.source, 'cpu');
+  assert_equals(typeof update.time, 'number');
+
 }, 'Basic functionality test');
 
 pressure_test((t, mockPressureService) => {
@@ -40,7 +42,7 @@
 
   observer.observe('cpu');
   observer.unobserve('cpu');
-  mockPressureService.setPressureState({cpuUtilization: 0.5});
+  mockPressureService.setPressureUpdate('critical');
   mockPressureService.sendUpdate();
 
   return new Promise(resolve => t.step_timeout(resolve, 1000));
@@ -59,41 +61,8 @@
 
   await Promise.all(observePromises);
 
-  mockPressureService.setPressureState({cpuUtilization: 0.5});
+  mockPressureService.setPressureUpdate('critical');
   mockPressureService.sendUpdate();
 
   return Promise.all(callbackPromises);
 }, 'Calling observe() multiple times works');
-
-pressure_test(async (t, mockPressureService) => {
-  const update = await new Promise(async resolve => {
-    const observer1 =
-        new PressureObserver(resolve, {cpuUtilizationThresholds: [0.5]});
-    await observer1.observe('cpu');
-
-    const observer2 =
-        new PressureObserver(() => {}, {cpuUtilizationThresholds: [0.5]});
-    await observer2.observe('cpu');
-
-    mockPressureService.setPressureState({cpuUtilization: 0.5});
-    mockPressureService.sendUpdate();
-  });
-
-  assert_equals(update.cpuUtilization, 0.5);
-}, 'Same quantization should not stop other observers');
-
-pressure_test(async (t, mockPressureService) => {
-  const observer1 = new PressureObserver(() => {
-    assert_unreached('The observer callback should not be called');
-  }, {cpuUtilizationThresholds: [0.5]});
-  await observer1.observe('cpu');
-
-  const observer2 =
-      new PressureObserver(() => {}, {cpuUtilizationThresholds: [0.3]});
-  await observer2.observe('cpu');
-
-  mockPressureService.setPressureState({cpuUtilization: 0.5});
-  mockPressureService.sendUpdate();
-
-  await new Promise(resolve => t.step_timeout(resolve, 1000));
-}, 'Different quantization should stop other observers');
diff --git a/compute-pressure/compute_pressure_detached_iframe.tentative.https.html b/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
index 7522b3f..e1639e8 100644
--- a/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
+++ b/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
@@ -23,7 +23,7 @@
 
   const observer = new frame_window.PressureObserver(
       () => {},
-      {cpuUtilizationThresholds: [0.5]});
+      {sampleRate: 1});
   const iframe_DOMException = frame_window.DOMException;
 
   iframe.remove();
@@ -40,7 +40,7 @@
 
   const observer = new frame_window.PressureObserver(
       () => {},
-      {cpuUtilizationThresholds: [0.5]});
+      {sampleRate: 1});
 
   await observer.observe('cpu');
 
@@ -57,7 +57,7 @@
 
   const observer = new frame_window.PressureObserver(
       () => {},
-      {cpuUtilizationThresholds: [0.5]});
+      {sampleRate: 1});
   const iframe_DOMException = frame_window.DOMException;
 
   // await is intentionally not used here. We want to remove the iframe while
@@ -70,12 +70,12 @@
   // call in the removed iframe's PressureObserver.
   const update = await new Promise((resolve, reject) => {
     const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+        resolve, {sampleRate: 1});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
-  assert_in_array(update.cpuUtilization, [0.25, 0.75],
-                  'cpuUtilization quantization');
+  assert_in_array(update.state, ['nominal', 'fair', 'serious', 'critical'],
+                  'cpu pressure state');
 }, 'Detaching frame while PressureObserver.observe() settles');
 
 </script>
diff --git a/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js b/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js
deleted file mode 100644
index 8fe2794..0000000
--- a/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js
+++ /dev/null
@@ -1,74 +0,0 @@
-'use strict';
-
-promise_test(async t => {
-  const observer1_updates = [];
-  const observer1 = new PressureObserver(
-      update => { observer1_updates.push(update); },
-      {cpuUtilizationThresholds: [0.5]});
-  t.add_cleanup(() => observer1.disconnect());
-  // Ensure that observer1's quantization scheme gets registered as the frame's
-  // scheme before observer2 starts.
-  await observer1.observe('cpu');
-
-  const observer2_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer2 = new PressureObserver(
-        update => {
-          observer2_updates.push(update);
-          resolve();
-        },
-        {cpuUtilizationThresholds: [0.25]});
-    t.add_cleanup(() => observer2.disconnect());
-    observer2.observe('cpu').catch(reject);
-  });
-
-  // observer2 uses a different quantization scheme than observer1. After
-  // observer2.observe() completes, observer1 should no longer be active.
-  //
-  // The check below assumes that observer2.observe() completes before the
-  // browser dispatches any update for observer1.  This assumption is highly
-  // likely to be true, because there should be a 1-second delay between
-  // observer1.observe() and the first update that observer1 would receive.
-  assert_equals(
-      observer1_updates.length, 0,
-      'observer2.observe() should have stopped observer1; the two observers ' +
-      'have different quantization schemes');
-
-  assert_equals(observer2_updates.length, 1);
-  assert_in_array(observer2_updates[0].cpuUtilization, [0.125, 0.625],
-                  'cpuUtilization quantization');
-
-  // Go through one more update cycle so any (incorrect) update for observer1
-  // makes it through the IPC queues.
-  observer1_updates.length = 0;
-  observer2_updates.length = 0;
-
-  const observer3_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer3 = new PressureObserver(
-        update => {
-          observer3_updates.push(update);
-          resolve();
-        },
-        {cpuUtilizationThresholds: [0.75]});
-    t.add_cleanup(() => observer3.disconnect());
-    observer3.observe('cpu').catch(reject);
-  });
-
-  assert_equals(
-      observer1_updates.length, 0,
-      'observer2.observe() should have stopped observer1; the two observers ' +
-      'have different quantization schemes');
-
-  // observer3 uses a different quantization scheme than observer2. So,
-  // observer3.observe() should stop observer2.
-  assert_equals(
-      observer2_updates.length, 0,
-      'observer3.observe() should have stopped observer2; the two observers ' +
-      'have different quantization schemes');
-
-  assert_equals(observer3_updates.length, 1);
-  assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875],
-                  'cpuUtilization quantization');
-}, 'PressureObserver with a new quantization schema stops all ' +
-   'other active observers in the same frame');
diff --git a/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js b/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js
deleted file mode 100644
index e1816a1..0000000
--- a/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js
+++ /dev/null
@@ -1,82 +0,0 @@
-'use strict';
-
-promise_test(async t => {
-  const observer1_updates = [];
-  const observer1 = new PressureObserver(
-      update => { observer1_updates.push(update); },
-      {cpuUtilizationThresholds: [0.5]});
-  t.add_cleanup(() => observer1.disconnect());
-  // Ensure that observer1's quantization scheme gets registered as the origin's
-  // scheme before observer2 starts.
-  await observer1.observe('cpu');
-
-  // iframe numbers are aligned with observer numbers.  The first observer is in
-  // the main frame, so there is no iframe1.
-  const iframe2 = document.createElement('iframe');
-  document.body.appendChild(iframe2);
-
-  const observer2_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer2 = new iframe2.contentWindow.PressureObserver(
-        update => {
-          observer2_updates.push(update);
-          resolve();
-        },
-        {cpuUtilizationThresholds: [0.25]});
-    t.add_cleanup(() => observer2.disconnect());
-    observer2.observe('cpu').catch(reject);
-  });
-
-  // observer2 uses a different quantization scheme than observer1. After
-  // observer2.observe() completes, observer1 should no longer be active.
-  //
-  // The check below assumes that observer2.observe() completes before the
-  // browser dispatches any update for observer1.  This assumption is highly
-  // likely to be true, because there should be a 1-second delay between
-  // observer1.observe() and the first update that observer1 would receive.
-  assert_equals(
-      observer1_updates.length, 0,
-      'observer2.observe() should have stopped observer1; the two observers ' +
-      'have different quantization schemes');
-
-  assert_equals(observer2_updates.length, 1);
-  assert_in_array(observer2_updates[0].cpuUtilization, [0.125, 0.625],
-                  'cpuUtilization quantization');
-
-  // Go through one more update cycle so any (incorrect) update for observer1
-  // makes it through the IPC queues.
-  observer1_updates.length = 0;
-  observer2_updates.length = 0;
-
-  const iframe3 = document.createElement('iframe');
-  document.body.appendChild(iframe3);
-
-  const observer3_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer3 = new iframe3.contentWindow.PressureObserver(
-        update => {
-          observer3_updates.push(update);
-          resolve();
-        },
-        {cpuUtilizationThresholds: [0.75]});
-    t.add_cleanup(() => observer3.disconnect());
-    observer3.observe('cpu').catch(reject);
-  });
-
-  assert_equals(
-      observer1_updates.length, 0,
-      'observer2.observe() should have stopped observer1; the two observers ' +
-      'have different quantization schemes');
-
-  // observer3 uses a different quantization scheme than observer2. So,
-  // observer3.observe() should stop observer2.
-  assert_equals(
-      observer2_updates.length, 0,
-      'observer3.observe() should have stopped observer2; the two observers ' +
-      'have different quantization schemes');
-
-  assert_equals(observer3_updates.length, 1);
-  assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875],
-                  'cpuUtilization quantization');
-}, 'PressureObserver with a new quantization schema stops all ' +
-   'other active observers');
diff --git a/compute-pressure/compute_pressure_disconnect.tentative.https.window.js b/compute-pressure/compute_pressure_disconnect.tentative.https.window.js
index b39af20..f6e5c31 100644
--- a/compute-pressure/compute_pressure_disconnect.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_disconnect.tentative.https.window.js
@@ -4,7 +4,7 @@
   const observer1_updates = [];
   const observer1 = new PressureObserver(update => {
     observer1_updates.push(update);
-  }, {cpuUtilizationThresholds: [0.5]});
+  }, {sampleRate: 1.0});
   t.add_cleanup(() => observer1.disconnect());
   // Ensure that observer1's schema gets registered before observer2 starts.
   await observer1.observe('cpu');
@@ -15,7 +15,7 @@
     const observer2 = new PressureObserver(update => {
       observer2_updates.push(update);
       resolve();
-    }, {cpuUtilizationThresholds: [0.5]});
+    }, {sampleRate: 1.0});
     t.add_cleanup(() => observer2.disconnect());
     observer2.observe('cpu').catch(reject);
   });
@@ -26,28 +26,6 @@
 
   assert_equals(observer2_updates.length, 1);
   assert_in_array(
-      observer2_updates[0].cpuUtilization, [0.25, 0.75],
-      'cpuUtilization quantization');
-
-  // Go through one more update cycle so any (incorrect) update for observer1
-  // makes it through the IPC queues.
-
-  const observer3_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer3 = new PressureObserver(update => {
-      observer3_updates.push(update);
-      resolve();
-    }, {cpuUtilizationThresholds: [0.75]});
-    t.add_cleanup(() => observer3.disconnect());
-    observer3.observe('cpu').catch(reject);
-  });
-
-  assert_equals(
-      observer1_updates.length, 0,
-      'disconnected observers should not receive callbacks');
-
-  assert_equals(observer3_updates.length, 1);
-  assert_in_array(
-      observer3_updates[0].cpuUtilization, [0.375, 0.875],
-      'cpuUtilization quantization');
+      observer2_updates[0].state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
 }, 'Stopped PressureObserver do not receive updates');
diff --git a/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js b/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js
index 10e3ad6..b2ae22f 100644
--- a/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js
@@ -4,7 +4,7 @@
   const observer1_updates = [];
   const observer1 = new PressureObserver(update => {
     observer1_updates.push(update);
-  }, {cpuUtilizationThresholds: [0.5]});
+  }, {sampleRate: 1});
   t.add_cleanup(() => observer1.disconnect());
   // Ensure that observer1's schema gets registered before observer2 starts.
   observer1.observe('cpu');
@@ -15,7 +15,7 @@
     const observer2 = new PressureObserver(update => {
       observer2_updates.push(update);
       resolve();
-    }, {cpuUtilizationThresholds: [0.5]});
+    }, {sampleRate: 1});
     t.add_cleanup(() => observer2.disconnect());
     observer2.observe('cpu').catch(reject);
   });
@@ -26,28 +26,6 @@
 
   assert_equals(observer2_updates.length, 1);
   assert_in_array(
-      observer2_updates[0].cpuUtilization, [0.25, 0.75],
-      'cpuUtilization quantization');
-
-  // Go through one more update cycle so any (incorrect) update for observer1
-  // makes it through the IPC queues.
-
-  const observer3_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer3 = new PressureObserver(update => {
-      observer3_updates.push(update);
-      resolve();
-    }, {cpuUtilizationThresholds: [0.75]});
-    t.add_cleanup(() => observer3.disconnect());
-    observer3.observe('cpu').catch(reject);
-  });
-
-  assert_equals(
-      observer1_updates.length, 0,
-      'stopped observers should not receive callbacks');
-
-  assert_equals(observer3_updates.length, 1);
-  assert_in_array(
-      observer3_updates[0].cpuUtilization, [0.375, 0.875],
-      'cpuUtilization quantization');
+      observer2_updates[0].state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
 }, 'Stopped PressureObserver do not receive updates');
diff --git a/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js b/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js
index 10e3ad6..cb5ab2d 100644
--- a/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js
@@ -4,7 +4,7 @@
   const observer1_updates = [];
   const observer1 = new PressureObserver(update => {
     observer1_updates.push(update);
-  }, {cpuUtilizationThresholds: [0.5]});
+  }, {sampleRate: 1.0});
   t.add_cleanup(() => observer1.disconnect());
   // Ensure that observer1's schema gets registered before observer2 starts.
   observer1.observe('cpu');
@@ -15,7 +15,7 @@
     const observer2 = new PressureObserver(update => {
       observer2_updates.push(update);
       resolve();
-    }, {cpuUtilizationThresholds: [0.5]});
+    }, {sampleRate: 1.0});
     t.add_cleanup(() => observer2.disconnect());
     observer2.observe('cpu').catch(reject);
   });
@@ -26,28 +26,6 @@
 
   assert_equals(observer2_updates.length, 1);
   assert_in_array(
-      observer2_updates[0].cpuUtilization, [0.25, 0.75],
-      'cpuUtilization quantization');
-
-  // Go through one more update cycle so any (incorrect) update for observer1
-  // makes it through the IPC queues.
-
-  const observer3_updates = [];
-  await new Promise((resolve, reject) => {
-    const observer3 = new PressureObserver(update => {
-      observer3_updates.push(update);
-      resolve();
-    }, {cpuUtilizationThresholds: [0.75]});
-    t.add_cleanup(() => observer3.disconnect());
-    observer3.observe('cpu').catch(reject);
-  });
-
-  assert_equals(
-      observer1_updates.length, 0,
-      'stopped observers should not receive callbacks');
-
-  assert_equals(observer3_updates.length, 1);
-  assert_in_array(
-      observer3_updates[0].cpuUtilization, [0.375, 0.875],
-      'cpuUtilization quantization');
+      observer2_updates[0].state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
 }, 'Stopped PressureObserver do not receive updates');
diff --git a/compute-pressure/compute_pressure_multiple.tentative.https.window.js b/compute-pressure/compute_pressure_multiple.tentative.https.window.js
index fef47e3..16ddb3c 100644
--- a/compute-pressure/compute_pressure_multiple.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_multiple.tentative.https.window.js
@@ -2,22 +2,19 @@
 
 promise_test(async t => {
   const update1_promise = new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
 
   const update2_promise = new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
 
   const update3_promise = new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
@@ -26,8 +23,8 @@
       await Promise.all([update1_promise, update2_promise, update3_promise]);
 
   for (const update of [update1, update2, update3]) {
-    assert_in_array(update.cpuUtilization, [0.25, 0.75],
-                    'cpuUtilization quantization');
+    assert_in_array(
+        update.state, ['nominal', 'fair', 'serious', 'critical'],
+        'cpu pressure state');
   }
-}, 'Three PressureObserver instances with the same quantization ' +
-   'schema receive updates');
+}, 'Three PressureObserver instances receive updates');
diff --git a/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js b/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js
index dff994c..7377337 100644
--- a/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js
@@ -2,20 +2,19 @@
 
 promise_test(async t => {
   const update1_promise = new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
 
-  // iframe numbers are aligned with observer numbers. The first observer is in
-  // the main frame, so there is no iframe1.
+  // iframe numbers are aligned with observer numbers. The first observer is
+  // in the main frame, so there is no iframe1.
   const iframe2 = document.createElement('iframe');
   document.body.appendChild(iframe2);
 
   const update2_promise = new Promise((resolve, reject) => {
-    const observer = new iframe2.contentWindow.PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer =
+        new iframe2.contentWindow.PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
@@ -24,8 +23,8 @@
   document.body.appendChild(iframe3);
 
   const update3_promise = new Promise((resolve, reject) => {
-    const observer = new iframe3.contentWindow.PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer =
+        new iframe3.contentWindow.PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
   });
@@ -34,8 +33,8 @@
       await Promise.all([update1_promise, update2_promise, update3_promise]);
 
   for (const update of [update1, update2, update3]) {
-    assert_in_array(update.cpuUtilization, [0.25, 0.75],
-                    'cpuUtilization quantization');
+    assert_in_array(
+        update.state, ['nominal', 'fair', 'serious', 'critical'],
+        'cpu pressure state');
   }
-}, 'Three PressureObserver instances in different iframes, but with ' +
-   'the same quantization schema, receive updates');
+}, 'Three PressureObserver instances, in different iframes, receive updates');
diff --git a/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js b/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js
index 925f73a..86d26e1 100644
--- a/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js
@@ -1,22 +1,16 @@
 'use strict';
 
 promise_test(async t => {
-  // The quantization thresholds and the quantized values that they lead to can
-  // be represented exactly in floating-point, so === comparison works.
-
   const update = await new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve, {cpuUtilizationThresholds: [0.5]});
+    const observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
     observer.observe('cpu').catch(reject);
     observer.observe('cpu').catch(reject);
     observer.observe('cpu').catch(reject);
   });
 
-  assert_equals(typeof update.cpuUtilization, 'number');
-  assert_greater_than_equal(update.cpuUtilization, 0.0, 'cpuUtilization range');
-  assert_less_than_equal(update.cpuUtilization, 1.0, 'cpuUtilization range');
-  assert_in_array(update.cpuUtilization, [0.25, 0.75],
-                  'cpuUtilization quantization');
+  assert_equals(typeof update.state, 'string');
+  assert_in_array(
+      update.state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu pressure state');
 }, 'PressureObserver.observe() is idempotent');
-
diff --git a/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js b/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js
index 7d6e94c..69fe125 100644
--- a/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js
@@ -2,16 +2,14 @@
 
 promise_test(async t => {
   const observer = new PressureObserver(
-      t.unreached_func('oops should not end up here'),
-      {cpuUtilizationThresholds: [0.1, 0.5]});
+      t.unreached_func('oops should not end up here'), {sampleRate: 1.0});
   t.add_cleanup(() => observer.disconnect());
   await promise_rejects_js(t, TypeError, observer.observe('random'));
 }, 'PressureObserver.observe() requires a valid source');
 
 test(function(t) {
   const observer = new PressureObserver(
-      t.unreached_func('oops should not end up here'),
-      {cpuUtilizationThresholds: [0.1, 0.5]});
+      t.unreached_func('oops should not end up here'), {sampleRate: 1.0});
   t.add_cleanup(() => observer.disconnect());
   assert_throws_js(TypeError, () => {
     observer.unobserve('random');
diff --git a/compute-pressure/compute_pressure_take_records.tentative.https.window.js b/compute-pressure/compute_pressure_take_records.tentative.https.window.js
index c6da8f6..ce5e835 100644
--- a/compute-pressure/compute_pressure_take_records.tentative.https.window.js
+++ b/compute-pressure/compute_pressure_take_records.tentative.https.window.js
@@ -1,9 +1,12 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
 'use strict';
 
 test(t => {
   const observer = new PressureObserver(
       t.unreached_func('This callback should not have been called.'),
-      {cpuUtilizationThresholds: [0.25]});
+      {sampleRate: 1.0});
 
   const records = observer.takeRecords();
   assert_equals(records.length, 0, 'No record before observe');
@@ -11,16 +14,15 @@
 
 promise_test(async t => {
   let observer;
-  const record = await new Promise((resolve, reject) => {
-    observer = new PressureObserver(
-        resolve,
-        {cpuUtilizationThresholds: [0.25]});
+  const update = await new Promise(async resolve => {
+    observer = new PressureObserver(resolve, {sampleRate: 1.0});
     t.add_cleanup(() => observer.disconnect());
-    observer.observe('cpu').catch(reject);
-  });
 
+    await observer.observe('cpu');
+  });
   assert_in_array(
-      record.cpuUtilization, [0.125, 0.625], 'cpuUtilization quantization');
+      update.state, ['nominal', 'fair', 'serious', 'critical'],
+      'cpu presure state');
 
   const records = observer.takeRecords();
   assert_equals(records.length, 0, 'No record available');
diff --git a/compute-pressure/compute_pressure_values.tentative.https.window.js b/compute-pressure/compute_pressure_values.tentative.https.window.js
deleted file mode 100644
index b51a3e3..0000000
--- a/compute-pressure/compute_pressure_values.tentative.https.window.js
+++ /dev/null
@@ -1,17 +0,0 @@
-'use strict';
-
-promise_test(async t => {
-  // The quantization thresholds and the quantized values that they lead to can
-  // be represented exactly in floating-point, so === comparison works.
-
-  const update = await new Promise((resolve, reject) => {
-    const observer = new PressureObserver(
-        resolve,
-        {cpuUtilizationThresholds: [0.25]});
-    t.add_cleanup(() => observer.disconnect());
-    observer.observe('cpu').catch(reject);
-  });
-
-  assert_in_array(
-      update.cpuUtilization, [0.125, 0.625], 'cpuUtilization quantization');
-}, 'PressureObserver quantizes utilization and speed separately');
diff --git a/resources/chromium/mock-pressure-service.js b/resources/chromium/mock-pressure-service.js
index e8a21ac..47fc3c3 100644
--- a/resources/chromium/mock-pressure-service.js
+++ b/resources/chromium/mock-pressure-service.js
@@ -1,4 +1,5 @@
-import {PressureService, PressureServiceReceiver, PressureStatus, SetQuantizationStatus} from '/gen/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.m.js'
+import {PressureState} from '/gen/services/device/public/mojom/pressure_update.mojom.m.js'
+import {PressureService, PressureServiceReceiver, PressureStatus} from '/gen/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.m.js'
 
 class MockPressureService {
   constructor() {
@@ -9,6 +10,10 @@
       this.receiver_.$.bindHandle(e.handle);
     };
     this.reset();
+    this.mojomStateType_ = new Map([
+      ['nominal', PressureState.kNominal], ['fair', PressureState.kFair],
+      ['serious', PressureState.kSerious], ['critical', PressureState.kCritical]
+    ]);
   }
 
   start() {
@@ -26,8 +31,7 @@
 
   reset() {
     this.observer_ = null;
-    this.pressureState_ = null;
-    this.quantization_ = null;
+    this.pressureUpdate_ = null;
     this.pressureStatus_ = PressureStatus.kOk;
   }
 
@@ -40,42 +44,20 @@
     return {status: this.pressureStatus_};
   }
 
-  isSameQuantization(quantization) {
-    if (this.quantization_ === null)
-      return false;
-
-    if (quantization.cpuUtilizationThresholds.length !=
-        this.quantization_.cpuUtilizationThresholds.length) {
-      return false;
-    }
-
-    for (let i = 0; i < quantization.cpuUtilizationThresholds.length; i++) {
-      if (quantization.cpuUtilizationThresholds[i] !=
-          this.quantization_.cpuUtilizationThresholds[i]) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  async setQuantization(quantization) {
-    if (this.isSameQuantization(quantization)) {
-      return {status: SetQuantizationStatus.kUnchanged};
-    } else {
-      this.quantization_ = quantization;
-      return {status: SetQuantizationStatus.kChanged};
-    }
-  }
-
   sendUpdate() {
-    if (this.pressureState_ === null || this.observer_ === null)
+    if (this.pressureUpdate_ === null || this.observer_ === null)
       return;
-    this.observer_.onUpdate(this.pressureState_);
+    this.observer_.onUpdate(this.pressureUpdate_);
   }
 
-  setPressureState(value) {
-    this.pressureState_ = value;
+  setPressureUpdate(state) {
+    if (!this.mojomStateType_.has(state))
+      throw new Error(`PressureState '${state}' is invalid`);
+
+    this.pressureUpdate_ = {
+      state: this.mojomStateType_.get(state),
+      timestamp: window.performance.timeOrigin
+    };
   }
 
   setExpectedFailure(expectedException) {