Browse Source

chore: cherry-pick 8 changes from Release-1-M123 (#41746)

* chore: cherry-pick 8 changes from Release-1-M123

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Pedro Pontes 1 year ago
parent
commit
ad9a90ec53

+ 1 - 0
patches/angle/.patches

@@ -0,0 +1 @@
+m123_vulkan_fix_access_to_inactive_attributes.patch

+ 112 - 0
patches/angle/m123_vulkan_fix_access_to_inactive_attributes.patch

@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Geoff Lang <[email protected]>
+Date: Tue, 12 Mar 2024 16:06:37 -0400
+Subject: M123: Vulkan: Fix access to inactive attributes
+
+... within range of active ones.  Since a buffer is bound for inactive
+attributes, it must be considered accessed.
+
+Ultimately, the nullDescriptor feature could be used to avoid binding a
+buffer for inactive attributes.
+
+Bug: chromium:327807820
+Change-Id: I953b419d8ec51760e8848409024cad5083888fa2
+Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5386431
+Reviewed-by: Shahbaz Youssefi <[email protected]>
+
+diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
+index 63bfa0729b266ceca54e10153f561f74a1be0c27..a0cbaf8cefbae1453922e09aadcd13df6f478782 100644
+--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
++++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
+@@ -2610,8 +2610,7 @@ angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator *d
+         vertexArrayVk->getCurrentArrayBuffers();
+ 
+     // Mark all active vertex buffers as accessed.
+-    const gl::AttributesMask attribsMask = executable->getActiveAttribLocationsMask();
+-    for (size_t attribIndex : attribsMask)
++    for (uint32_t attribIndex = 0; attribIndex < maxAttrib; ++attribIndex)
+     {
+         vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
+         if (arrayBuffer)
+diff --git a/src/tests/gl_tests/VertexAttributeTest.cpp b/src/tests/gl_tests/VertexAttributeTest.cpp
+index b8a1c87728b3ba54a32cf0e4da6ca626c05d1d92..773bbf026821795c0db34239d27fd2bb1e5a751a 100644
+--- a/src/tests/gl_tests/VertexAttributeTest.cpp
++++ b/src/tests/gl_tests/VertexAttributeTest.cpp
+@@ -1256,6 +1256,19 @@ class VertexAttributeOORTest : public VertexAttributeTest
+     }
+ };
+ 
++class RobustVertexAttributeTest : public VertexAttributeTest
++{
++  public:
++    RobustVertexAttributeTest()
++    {
++        // mac GL and metal do not support robustness.
++        if (!IsMac() && !IsIOS())
++        {
++            setRobustAccess(true);
++        }
++    }
++};
++
+ // Verify that drawing with a large out-of-range offset generates INVALID_OPERATION.
+ // Requires WebGL compatibility with robust access behaviour disabled.
+ TEST_P(VertexAttributeOORTest, ANGLEDrawArraysBufferTooSmall)
+@@ -1316,6 +1329,48 @@ TEST_P(VertexAttributeOORTest, ANGLEDrawArraysOutOfBoundsCases)
+     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+ }
+ 
++// Test that enabling a buffer in an unused attribute doesn't crash.  There should be an active
++// attribute after that.
++TEST_P(RobustVertexAttributeTest, BoundButUnusedBuffer)
++{
++    constexpr char kVS[] = R"(attribute vec2 offset;
++void main()
++{
++    gl_Position = vec4(offset.xy, 0, 1);
++    gl_PointSize = 1.0;
++})";
++
++    constexpr char kFS[] = R"(precision mediump float;
++void main()
++{
++    gl_FragColor = vec4(1.0, 0, 0, 1.0);
++})";
++
++    const GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
++    const GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
++
++    GLuint program = glCreateProgram();
++    glBindAttribLocation(program, 1, "offset");
++    glAttachShader(program, vs);
++    glAttachShader(program, fs);
++    glLinkProgram(program);
++
++    GLBuffer buffer;
++    glBindBuffer(GL_ARRAY_BUFFER, buffer);
++    glBufferData(GL_ARRAY_BUFFER, 100, nullptr, GL_STATIC_DRAW);
++
++    // Enable an unused attribute that is within the range of active attributes (not beyond it)
++    glEnableVertexAttribArray(0);
++    glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
++
++    glUseProgram(program);
++    glDrawArrays(GL_TRIANGLES, 0, 6);
++
++    // Destroy the buffer.  Regression test for a tracking bug where the buffer was used by
++    // SwiftShader (even though location 1 is inactive), but not marked as used by ANGLE.
++    buffer.reset();
++}
++
+ // Verify that using a different start vertex doesn't mess up the draw.
+ TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
+ {
+@@ -4913,6 +4968,8 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
+     ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
+     ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
+ 
++ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(RobustVertexAttributeTest);
++
+ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES3);
+ ANGLE_INSTANTIATE_TEST_ES3_AND(
+     VertexAttributeTestES3,

+ 3 - 0
patches/chromium/.patches

@@ -133,3 +133,6 @@ fix_getcursorscreenpoint_wrongly_returns_0_0.patch
 fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
 remove_dxdiag_telemetry_code.patch
 cherry-pick-2607ddacd643.patch
+m122_webcodecs_disable_async_videoframe_readback_to_mitigate_a.patch
+fix_paintimage_deserialization_arbitrary-read_issue.patch
+reland_sensors_winrt_call_onreadingchangedcallback_via.patch

+ 36 - 0
patches/chromium/fix_paintimage_deserialization_arbitrary-read_issue.patch

@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peng Huang <[email protected]>
+Date: Wed, 20 Mar 2024 16:22:16 +0000
+Subject: Fix PaintImage deserialization arbitrary-read issue
+
+(cherry picked from commit 47e8386c97ac7a84a96866fbd35422b99a01de5a)
+
+Bug: 327183408
+Change-Id: I09927fbae60b666aaa370e3aba01607cdb977a25
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5370455
+Reviewed-by: Sunny Sachanandani <[email protected]>
+Commit-Queue: Peng Huang <[email protected]>
+Cr-Original-Commit-Position: refs/heads/main@{#1272930}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5382202
+Auto-Submit: Peng Huang <[email protected]>
+Commit-Queue: Sunny Sachanandani <[email protected]>
+Cr-Commit-Position: refs/branch-heads/6261@{#1106}
+Cr-Branched-From: 9755d9d81e4a8cb5b4f76b23b761457479dbb06b-refs/heads/main@{#1250580}
+
+diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
+index 22a044734c898997d13f34a04b10e356cc86717e..46c385054b1575cff7ad2ae38be237deea081914 100644
+--- a/cc/paint/paint_op_reader.cc
++++ b/cc/paint/paint_op_reader.cc
+@@ -1572,9 +1572,10 @@ inline void PaintOpReader::DidRead(size_t bytes_read) {
+   // All data are aligned with PaintOpWriter::kDefaultAlignment at least.
+   size_t aligned_bytes =
+       base::bits::AlignUp(bytes_read, PaintOpWriter::kDefaultAlignment);
+-  memory_ += aligned_bytes;
+   DCHECK_LE(aligned_bytes, remaining_bytes_);
+-  remaining_bytes_ -= aligned_bytes;
++  bytes_read = std::min(aligned_bytes, remaining_bytes_);
++  memory_ += bytes_read;
++  remaining_bytes_ -= bytes_read;
+ }
+ 
+ }  // namespace cc

+ 80 - 0
patches/chromium/m122_webcodecs_disable_async_videoframe_readback_to_mitigate_a.patch

@@ -0,0 +1,80 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eugene Zemtsov <[email protected]>
+Date: Mon, 25 Mar 2024 19:28:44 +0000
+Subject: webcodecs: Disable async VideoFrame readback to mitigate a race
+
+(cherry picked from commit fdc363eb7a1c1c194a02a4cb340534b1501b0f95)
+
+Bug: 330575496
+Change-Id: I187a113528da9d1c4316186e3dd24f91dbfd818b
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5386784
+Commit-Queue: Eugene Zemtsov <[email protected]>
+Reviewed-by: Dale Curtis <[email protected]>
+Cr-Original-Commit-Position: refs/heads/main@{#1277172}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5391828
+Reviewed-by: Eugene Zemtsov <[email protected]>
+Commit-Queue: Dale Curtis <[email protected]>
+Reviewed-by: Xiaohan Wang <[email protected]>
+Commit-Queue: Xiaohan Wang <[email protected]>
+Auto-Submit: Dale Curtis <[email protected]>
+Cr-Commit-Position: refs/branch-heads/6261@{#1124}
+Cr-Branched-From: 9755d9d81e4a8cb5b4f76b23b761457479dbb06b-refs/heads/main@{#1250580}
+
+diff --git a/content/test/data/gpu/webcodecs/copyTo.html b/content/test/data/gpu/webcodecs/copyTo.html
+index ec2455c9c18900ad911ce98f326139cbdeabd84f..9453c8d361a572b500e86b1249896bc4114ebe27 100644
+--- a/content/test/data/gpu/webcodecs/copyTo.html
++++ b/content/test/data/gpu/webcodecs/copyTo.html
+@@ -118,6 +118,16 @@ Take frames coming from various sources and read them using copyTo().
+     let frame = await source.getNextFrame();
+     let size = frame.allocationSize();
+ 
++    // Readback a whole frame to a regular buffer detach it
++    {
++      let buf = new ArrayBuffer(size);
++      TEST.assert(readWholeBuffer(buf) == 0, "Buffer should be zero");
++      let copy_promise = frame.copyTo(buf);
++      buf.transfer(1);
++      let layout = await copy_promise;
++      TEST.assert(layout, "layout is empty / ArrayBuffer");
++    }
++
+     // Readback a whole frame to a regular buffer and send it to a worker
+     {
+       let {worker, worker_promise } = makeWorker();
+@@ -158,4 +168,5 @@ Take frames coming from various sources and read them using copyTo().
+     TEST.log('Test completed');
+   }
+   addManualTestButton([{'source_type': 'offscreen'}]);
++  addManualTestButton([{'source_type': 'arraybuffer'}]);
+ </script>
+diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+index 279359ea2d536358ce946e6f7d8feec2dfcc160c..e37dd9568399283f8006dfd1578c0e5b57566830 100644
+--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
++++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+@@ -80,6 +80,11 @@ namespace blink {
+ 
+ namespace {
+ 
++// Controls if VideoFrame.copyTo() reads GPU frames asynchronously
++BASE_FEATURE(kVideoFrameAsyncCopyTo,
++             "VideoFrameAsyncCopyTo",
++             base::FEATURE_DISABLED_BY_DEFAULT);
++
+ media::VideoPixelFormat ToMediaPixelFormat(V8VideoPixelFormat::Enum fmt) {
+   switch (fmt) {
+     case V8VideoPixelFormat::Enum::kI420:
+@@ -1217,9 +1222,11 @@ ScriptPromise VideoFrame::copyTo(ScriptState* script_state,
+   } else {
+     DCHECK(local_frame->HasTextures());
+ 
+-    if (auto* resolver = CopyToAsync(script_state, local_frame, src_rect,
+-                                     destination, dest_layout)) {
+-      return resolver->Promise();
++    if (base::FeatureList::IsEnabled(kVideoFrameAsyncCopyTo)) {
++      if (auto* resolver = CopyToAsync(script_state, local_frame, src_rect,
++                                       destination, dest_layout)) {
++        return resolver->Promise();
++      }
+     }
+ 
+     if (!CopyTexturablePlanes(*local_frame, src_rect, dest_layout, buffer)) {

+ 1690 - 0
patches/chromium/reland_sensors_winrt_call_onreadingchangedcallback_via.patch

@@ -0,0 +1,1690 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Raphael Kubo Da Costa <[email protected]>
+Date: Thu, 21 Mar 2024 16:50:44 +0000
+Subject: Reland "sensors WinRT: Call OnReadingChangedCallback() via
+ PostTask()"
+
+This reverts commit 745ca2de005c052f58097ef9cb7aa2deff095cf4.
+
+Reason for revert: Reapproved by pgrace@ in the bug.
+
+Original change's description:
+> Revert "sensors WinRT: Call OnReadingChangedCallback() via PostTask()"
+>
+> This reverts commit 7e93b6a926ab65cc7ff1293bdcf0099c6e6e4e4e.
+>
+> Reason for revert: Requested in the bug by pgrace@
+>
+> Original change's description:
+> > sensors WinRT: Call OnReadingChangedCallback() via PostTask()
+> >
+> > While here, also add checks to make sure each method is running on the
+> > right sequence and make |minimum_report_interval_| guarded by |lock_|
+> > since it is accessed by the main task runner just like |client_|.
+> >
+> > There is a significant amount of changes in the unit tests for two
+> > reasons:
+> > 1. We now use multiple task runners and create Reader objects in a COM
+> >    STA task runner to better simulate what happens in production.
+> > 2. Doing so has uncovered bugs in the exist tests that had to be fixed.
+> >    Namely:
+> >    - One of the biggest offenders was the use of EXPECT_CALL() with
+> >      WillRepeatedly() for expecting calls to OnReadingUpdated(). Using
+> >      only WillRepeatedly() meant the control over the cardinality of the
+> >      expectations was not very strict, and sometimes callbacks were
+> >      simply not being run.
+> >      Now that TriggerFakeSensorReading() is asynchronous and we need to
+> >      use a base::RunLoop to ensure, we are also using WillOnce() a lot
+> >      more than WillRepeatedly() so that we set one expectation, call
+> >      TriggerFakeSensorReading() and consume it immediately.
+> >    - The *Thresholding tests were affected by the problem above, and
+> >      fixing them showed that several callbacks were not being invoked.
+> >      Many checks where values were increased by the exact threshold
+> >      amount were broken because the manipulated values are floats and
+> >      doubles, and the math operations on them in the
+> >      OnReadingChangedCallback() implementations caused the comparisons
+> >      with exact values to fail. In this case, it was simpler to just
+> >      remove those specific tests, as the "values bigger than the
+> >      threshold" case are already covered by other checks.
+> >    - Also as a consequence of the above, *Thresholding tests with
+> >      multi-axis values were also broken when they went from testing that
+> >      values did not pass the threshold checks to the first test that
+> >      verifies that an axis passes the threshold check. This caused all
+> >      previous |last_sent_*| variables to be stored in the Reader, and
+> >      other calls to threshold_helper(true) would fail. The fix here was
+> >      to reorder the calls so that each axis is tested entirely before
+> >      the next.
+> >
+> > (cherry picked from commit 2aafa000795519b5153125673f87c734f7b8ae9f)
+> >
+> > Bug: 326349405
+> > Change-Id: Ief67720e8c449af1ce4f450002103a20ca1830ee
+> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5340216
+> > Auto-Submit: Raphael Kubo Da Costa <[email protected]>
+> > Commit-Queue: Raphael Kubo Da Costa <[email protected]>
+> > Reviewed-by: Reilly Grant <[email protected]>
+> > Cr-Original-Commit-Position: refs/heads/main@{#1268797}
+> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5372846
+> > Reviewed-by: Colin Blundell <[email protected]>
+> > Cr-Commit-Position: refs/branch-heads/6261@{#1079}
+> > Cr-Branched-From: 9755d9d81e4a8cb5b4f76b23b761457479dbb06b-refs/heads/main@{#1250580}
+>
+> Bug: 326349405
+> Change-Id: I49d61cf7bdf2a00004aa565a5439ad813b1c379e
+> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5378404
+> Commit-Queue: Raphael Kubo Da Costa <[email protected]>
+> Bot-Commit: Rubber Stamper <[email protected]>
+> Cr-Commit-Position: refs/branch-heads/6261@{#1090}
+> Cr-Branched-From: 9755d9d81e4a8cb5b4f76b23b761457479dbb06b-refs/heads/main@{#1250580}
+
+Bug: 326349405
+Change-Id: I3bcba8840a3a10cd4660ec287fa24623bcf87657
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5383440
+Bot-Commit: Rubber Stamper <[email protected]>
+Commit-Queue: Raphael Kubo Da Costa <[email protected]>
+Cr-Commit-Position: refs/branch-heads/6261@{#1111}
+Cr-Branched-From: 9755d9d81e4a8cb5b4f76b23b761457479dbb06b-refs/heads/main@{#1250580}
+
+diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.cc b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
+index 6c778b7edf0cbaeae9a412b44bfcd75d0408cce9..673225e398a2318962aca7fb08ee2ea6c7a4a0a6 100644
+--- a/services/device/generic_sensor/platform_sensor_reader_winrt.cc
++++ b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
+@@ -8,6 +8,7 @@
+ 
+ #include "base/numerics/math_constants.h"
+ #include "base/time/time.h"
++#include "base/win/com_init_util.h"
+ #include "base/win/core_winrt_util.h"
+ #include "services/device/generic_sensor/generic_sensor_consts.h"
+ #include "services/device/public/mojom/sensor.mojom.h"
+@@ -99,7 +100,11 @@ PlatformSensorReaderWinrtBase<
+     ISensorWinrtStatics,
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+-    ISensorReadingChangedEventArgs>::PlatformSensorReaderWinrtBase() {
++    ISensorReadingChangedEventArgs>::PlatformSensorReaderWinrtBase()
++    : com_sta_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++  DETACH_FROM_SEQUENCE(main_sequence_checker_);
++
+   get_sensor_factory_callback_ =
+       base::BindRepeating([](ISensorWinrtStatics** sensor_factory) -> HRESULT {
+         return base::win::GetActivationFactory<ISensorWinrtStatics,
+@@ -119,6 +124,8 @@ void PlatformSensorReaderWinrtBase<
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+     ISensorReadingChangedEventArgs>::SetClient(Client* client) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
++
+   base::AutoLock autolock(lock_);
+   client_ = client;
+ }
+@@ -136,6 +143,8 @@ HRESULT PlatformSensorReaderWinrtBase<runtime_class_id,
+                                       ISensorReadingChangedEventArgs>::
+     ConvertSensorReadingTimeStamp(ComPtr<ISensorReading> sensor_reading,
+                                   base::TimeDelta* timestamp_delta) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   DateTime timestamp;
+   HRESULT hr = sensor_reading->get_Timestamp(&timestamp);
+   if (FAILED(hr))
+@@ -157,6 +166,8 @@ bool PlatformSensorReaderWinrtBase<
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+     ISensorReadingChangedEventArgs>::Initialize() {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<ISensorWinrtStatics> sensor_statics;
+ 
+   HRESULT hr = get_sensor_factory_callback_.Run(&sensor_statics);
+@@ -180,10 +191,14 @@ bool PlatformSensorReaderWinrtBase<
+     return false;
+   }
+ 
+-  minimum_report_interval_ = GetMinimumReportIntervalFromSensor();
++  {
++    base::AutoLock autolock(lock_);
++    minimum_report_interval_ = GetMinimumReportIntervalFromSensor();
+ 
+-  if (minimum_report_interval_.is_zero())
+-    DLOG(WARNING) << "Failed to get sensor minimum report interval";
++    if (minimum_report_interval_.is_zero()) {
++      DLOG(WARNING) << "Failed to get sensor minimum report interval";
++    }
++  }
+ 
+   return true;
+ }
+@@ -199,6 +214,8 @@ base::TimeDelta PlatformSensorReaderWinrtBase<
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+     ISensorReadingChangedEventArgs>::GetMinimumReportIntervalFromSensor() {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   UINT32 minimum_report_interval_ms = 0;
+   HRESULT hr = sensor_->get_MinimumReportInterval(&minimum_report_interval_ms);
+ 
+@@ -225,6 +242,9 @@ base::TimeDelta PlatformSensorReaderWinrtBase<
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+     ISensorReadingChangedEventArgs>::GetMinimalReportingInterval() const {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
++
++  base::AutoLock autolock(lock_);
+   return minimum_report_interval_;
+ }
+ 
+@@ -239,6 +259,8 @@ bool PlatformSensorReaderWinrtBase<runtime_class_id,
+                                    ISensorReadingChangedHandler,
+                                    ISensorReadingChangedEventArgs>::
+     StartSensor(const PlatformSensorConfiguration& configuration) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
++
+   base::AutoLock autolock(lock_);
+ 
+   if (!reading_callback_token_) {
+@@ -256,7 +278,39 @@ bool PlatformSensorReaderWinrtBase<runtime_class_id,
+     }
+ 
+     auto reading_changed_handler = Callback<ISensorReadingChangedHandler>(
+-        this, &PlatformSensorReaderWinrtBase::OnReadingChangedCallback);
++        [weak_ptr(weak_ptr_factory_.GetWeakPtr()),
++         com_sta_task_runner(com_sta_task_runner_)](
++            ISensorWinrtClass* sender, ISensorReadingChangedEventArgs* args) {
++          // We cannot invoke OnReadingChangedCallback() directly because this
++          // callback is run on a COM MTA thread spawned by Windows (on tests,
++          // we mimic the behavior by using base::ThreadPool, as the task
++          // scheduler threads live in the MTA).
++          //
++          // This callback is invoked on an MTA thread because the
++          // ISensorReadingChangedHandler declarations explicitly inherit from
++          // Microsoft::WRL::FtmBase, which makes them agile, free-threaded
++          // objects.
++          //
++          // We could CHECK() this behavior here, but ::CoGetApartmentType()
++          // depends on ole32.dll and base::win::GetComApartmentTypeForThread()
++          // returns NONE in the non-test code path even though
++          // ::GoGetApartmentType() returns MTA, so the best we can do is just
++          // double-check that this is not running on an STA.
++          DCHECK_NE(base::win::GetComApartmentTypeForThread(),
++                    base::win::ComApartmentType::STA);
++          com_sta_task_runner->PostTask(
++              FROM_HERE,
++              base::BindOnce(
++                  // TODO(crbug.com/326349405): base::IgnoreResult is being used
++                  // temporarily to reduce the amount of changes required for
++                  // this bug. OnReadingChangedCallback() must be changed to
++                  // have a void return type.
++                  base::IgnoreResult(
++                      &PlatformSensorReaderWinrtBase::OnReadingChangedCallback),
++                  weak_ptr, ComPtr<ISensorWinrtClass>(sender),
++                  ComPtr<ISensorReadingChangedEventArgs>(args)));
++          return S_OK;
++        });
+ 
+     EventRegistrationToken event_token;
+     hr = sensor_->add_ReadingChanged(reading_changed_handler.Get(),
+@@ -285,6 +339,9 @@ void PlatformSensorReaderWinrtBase<
+     ISensorWinrtClass,
+     ISensorReadingChangedHandler,
+     ISensorReadingChangedEventArgs>::StopSensor() {
++  // This function is called in the main task runner by PlatformSensorWin as
++  // well as in the com_sta_task_runner_ by the destructor.
++
+   base::AutoLock autolock(lock_);
+ 
+   if (reading_callback_token_) {
+@@ -316,6 +373,8 @@ PlatformSensorReaderWinrtLightSensor::PlatformSensorReaderWinrtLightSensor() =
+ HRESULT PlatformSensorReaderWinrtLightSensor::OnReadingChangedCallback(
+     ILightSensor* light_sensor,
+     ILightSensorReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<ILightSensorReading> light_sensor_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&light_sensor_reading);
+   if (FAILED(hr)) {
+@@ -379,6 +438,8 @@ PlatformSensorReaderWinrtAccelerometer::
+ HRESULT PlatformSensorReaderWinrtAccelerometer::OnReadingChangedCallback(
+     IAccelerometer* accelerometer,
+     IAccelerometerReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<IAccelerometerReading> accelerometer_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&accelerometer_reading);
+   if (FAILED(hr)) {
+@@ -464,6 +525,8 @@ PlatformSensorReaderWinrtGyrometer::PlatformSensorReaderWinrtGyrometer() =
+ HRESULT PlatformSensorReaderWinrtGyrometer::OnReadingChangedCallback(
+     IGyrometer* gyrometer,
+     IGyrometerReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<IGyrometerReading> gyrometer_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&gyrometer_reading);
+   if (FAILED(hr)) {
+@@ -548,6 +611,8 @@ PlatformSensorReaderWinrtMagnetometer::PlatformSensorReaderWinrtMagnetometer() =
+ HRESULT PlatformSensorReaderWinrtMagnetometer::OnReadingChangedCallback(
+     IMagnetometer* magnetometer,
+     IMagnetometerReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<IMagnetometerReading> magnetometer_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&magnetometer_reading);
+   if (FAILED(hr)) {
+@@ -631,6 +696,8 @@ HRESULT
+ PlatformSensorReaderWinrtAbsOrientationEulerAngles::OnReadingChangedCallback(
+     IInclinometer* inclinometer,
+     IInclinometerReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<IInclinometerReading> inclinometer_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&inclinometer_reading);
+   if (FAILED(hr)) {
+@@ -717,6 +784,8 @@ HRESULT
+ PlatformSensorReaderWinrtAbsOrientationQuaternion::OnReadingChangedCallback(
+     IOrientationSensor* orientation_sensor,
+     IOrientationSensorReadingChangedEventArgs* reading_changed_args) {
++  DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++
+   ComPtr<IOrientationSensorReading> orientation_sensor_reading;
+   HRESULT hr = reading_changed_args->get_Reading(&orientation_sensor_reading);
+   if (FAILED(hr)) {
+diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.h b/services/device/generic_sensor/platform_sensor_reader_winrt.h
+index 66c40adc59e897d85872eae864f957fecc62fca7..e4521a7816fad77a2f69416befa6f1358fb1a1c2 100644
+--- a/services/device/generic_sensor/platform_sensor_reader_winrt.h
++++ b/services/device/generic_sensor/platform_sensor_reader_winrt.h
+@@ -14,7 +14,10 @@
+ 
+ #include "base/functional/callback.h"
+ #include "base/memory/raw_ptr.h"
++#include "base/memory/weak_ptr.h"
++#include "base/sequence_checker.h"
+ #include "base/synchronization/lock.h"
++#include "base/task/single_thread_task_runner.h"
+ #include "base/thread_annotations.h"
+ #include "base/time/time.h"
+ #include "services/device/generic_sensor/platform_sensor_reader_win_base.h"
+@@ -77,7 +80,10 @@ class PlatformSensorReaderWinrtBase : public PlatformSensorReaderWinBase {
+ 
+  protected:
+   PlatformSensorReaderWinrtBase();
+-  virtual ~PlatformSensorReaderWinrtBase() { StopSensor(); }
++  virtual ~PlatformSensorReaderWinrtBase() {
++    DCHECK_CALLED_ON_VALID_SEQUENCE(com_sta_sequence_checker_);
++    StopSensor();
++  }
+ 
+   // Derived classes should implement this function to handle sensor specific
+   // parsing of the sensor reading.
+@@ -93,11 +99,15 @@ class PlatformSensorReaderWinrtBase : public PlatformSensorReaderWinBase {
+       Microsoft::WRL::ComPtr<ISensorReading> sensor_reading,
+       base::TimeDelta* timestamp_delta);
+ 
+-  // Following class member is protected by lock since SetClient,
+-  // StartSensor, and StopSensor can all be called from different
+-  // threads by PlatformSensorWin.
+-  base::Lock lock_;
+-  // Null if there is no client to notify, non-null otherwise.
++  SEQUENCE_CHECKER(com_sta_sequence_checker_);
++  SEQUENCE_CHECKER(main_sequence_checker_);
++
++  mutable base::Lock lock_;
++
++  // Null if there is no client to notify, non-null otherwise. Protected by
++  // |lock_| because SetClient() and StartSensor() are called from the main
++  // task runner rather than the thread where this object is created, and
++  // StopSensor() may be called from the main task runner too.
+   raw_ptr<Client, DanglingUntriaged> client_ GUARDED_BY(lock_);
+ 
+   // Always report the first sample received after starting the sensor.
+@@ -106,13 +116,21 @@ class PlatformSensorReaderWinrtBase : public PlatformSensorReaderWinBase {
+  private:
+   base::TimeDelta GetMinimumReportIntervalFromSensor();
+ 
++  // Task runner where this object was created.
++  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
++
+   GetSensorFactoryFunctor get_sensor_factory_callback_;
+ 
+   // absl::nullopt if the sensor has not been started, non-empty otherwise.
+   absl::optional<EventRegistrationToken> reading_callback_token_;
+ 
+-  base::TimeDelta minimum_report_interval_;
++  // Protected by |lock_| because GetMinimalReportingInterval() is called from
++  // the main task runner.
++  base::TimeDelta minimum_report_interval_ GUARDED_BY(lock_);
++
+   Microsoft::WRL::ComPtr<ISensorWinrtClass> sensor_;
++
++  base::WeakPtrFactory<PlatformSensorReaderWinrtBase> weak_ptr_factory_{this};
+ };
+ 
+ class PlatformSensorReaderWinrtLightSensor final
+diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
+index 2283de90c75dd91f5472ece24b1d674ed796120b..f6add828b496916ff2856d8ff36fcd2a7babb1a9 100644
+--- a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
++++ b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
+@@ -6,8 +6,13 @@
+ 
+ #include <objbase.h>
+ 
++#include "base/notreached.h"
+ #include "base/numerics/math_constants.h"
++#include "base/run_loop.h"
++#include "base/task/task_traits.h"
++#include "base/task/thread_pool.h"
+ #include "base/test/bind.h"
++#include "base/test/gmock_callback_support.h"
+ #include "base/test/task_environment.h"
+ #include "base/win/core_winrt_util.h"
+ #include "base/win/scoped_com_initializer.h"
+@@ -428,15 +433,26 @@ class FakeSensorWinrt
+     return remove_reading_changed_return_code_;
+   }
+ 
+-  // Makes any clients registered via add_ReadingChanged() to trigger with
+-  // the given sensor reading.
++  // Invokes the handler added via add_ReadingChanged() with the reading
++  // described by |reading|.
++  //
++  // The invocation is asynchronous to better simulate real behavior, where
++  // Windows delivers the reading notifications in a separate MTA thread.
+   void TriggerFakeSensorReading(
+       Microsoft::WRL::ComPtr<ISensorReading> reading) {
+-    EXPECT_TRUE(handler_);
+     Microsoft::WRL::ComPtr<ISensorReadingChangedEventArgs> reading_event_args =
+         Microsoft::WRL::Make<FakeSensorReadingChangedEventArgsWinrt<
+             ISensorReading, ISensorReadingChangedEventArgs>>(reading);
+-    EXPECT_HRESULT_SUCCEEDED(handler_->Invoke(this, reading_event_args.Get()));
++    base::ThreadPool::PostTask(
++        FROM_HERE, {base::MayBlock()},
++        base::BindLambdaForTesting(
++            // Copy |handler_| and |reading_event_args| to ensure they do not
++            // lose their values when TriggerFakeSensorReading() exits.
++            [this, handler = handler_, reading_event_args]() {
++              ASSERT_TRUE(handler);
++              EXPECT_HRESULT_SUCCEEDED(
++                  handler->Invoke(this, reading_event_args.Get()));
++            }));
+   }
+ 
+   // Returns true if any clients are registered for readings via
+@@ -547,7 +563,47 @@ class FakeSensorFactoryWinrt
+ };
+ 
+ class PlatformSensorReaderTestWinrt : public testing::Test {
+- private:
++ public:
++  void SetUp() override {
++    // Ensure each test starts with a fresh task runner.
++    com_sta_task_runner_ =
++        base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()});
++  }
++
++  // Synchronously creates a new PlatformSensorReaderWinrtBase-derived class on
++  // |com_sta_task_runner_| and returns it.
++  //
++  // This better simulates real behavior, as PlatformSensorProviderWinrt
++  // creates readers on a COM STA task runner.
++  template <typename SensorReader,
++            typename ISensorStatics,
++            typename... OtherFactoryTypes>
++  auto CreateAndInitializeSensor(
++      const Microsoft::WRL::ComPtr<
++          FakeSensorFactoryWinrt<ISensorStatics, OtherFactoryTypes...>>&
++          fake_sensor_factory) {
++    std::unique_ptr<SensorReader, base::OnTaskRunnerDeleter> reader(
++        nullptr, base::OnTaskRunnerDeleter(com_sta_task_runner_));
++
++    base::RunLoop run_loop;
++    com_sta_task_runner_->PostTaskAndReply(
++        FROM_HERE, base::BindLambdaForTesting([&]() {
++          reader.reset(new SensorReader);
++          reader->InitForTesting(base::BindLambdaForTesting(
++              [&](ISensorStatics** sensor_factory) -> HRESULT {
++                return fake_sensor_factory.CopyTo(sensor_factory);
++              }));
++          ASSERT_TRUE(reader->Initialize());
++        }),
++        run_loop.QuitClosure());
++    run_loop.Run();
++
++    return reader;
++  }
++
++ protected:
++  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
++
+   base::test::TaskEnvironment task_environment_;
+   base::win::ScopedCOMInitializer scoped_com_initializer_;
+ };
+@@ -602,11 +658,9 @@ TEST_F(PlatformSensorReaderTestWinrt, SensorMinimumReportInterval) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(),
+             kExpectedMinimumReportInterval);
+@@ -623,20 +677,42 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedSensorMinimumReportInterval) {
+       ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs,
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+-
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+   fake_sensor->SetGetMinimumReportIntervalReturnCode(E_FAIL);
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(), 0);
+ }
+ 
+-// Tests that PlatformSensorReaderWinrtBase converts the timestamp correctly
+-TEST_F(PlatformSensorReaderTestWinrt, SensorTimestampConversion) {
+-  static constexpr double expectedTimestampDeltaSecs = 19.0;
++TEST_F(PlatformSensorReaderTestWinrt, ReadingChangedCallbackAndPostTask) {
++  // Instead of using PlatformSensorReaderWinrtLightSensor, declare a custom
++  // implementation that does less and whose sole purpose is to assert that its
++  // OnReadingChangedCallback() implementation is never called.
++  struct CustomLightSensor
++      : public PlatformSensorReaderWinrtBase<
++            RuntimeClass_Windows_Devices_Sensors_LightSensor,
++            ABI::Windows::Devices::Sensors::ILightSensorStatics,
++            ABI::Windows::Devices::Sensors::ILightSensor,
++            Microsoft::WRL::Implements<
++                Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
++                ABI::Windows::Foundation::ITypedEventHandler<
++                    ABI::Windows::Devices::Sensors::LightSensor*,
++                    ABI::Windows::Devices::Sensors::
++                        LightSensorReadingChangedEventArgs*>,
++                Microsoft::WRL::FtmBase>,
++            ABI::Windows::Devices::Sensors::
++                ILightSensorReadingChangedEventArgs> {
++    ~CustomLightSensor() override = default;
++
++    HRESULT OnReadingChangedCallback(
++        ABI::Windows::Devices::Sensors::ILightSensor*,
++        ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs*)
++        override {
++      NOTREACHED_NORETURN() << "This function should not have been reached";
++    }
++  };
+ 
+   auto fake_sensor_factory = Microsoft::WRL::Make<FakeSensorFactoryWinrt<
+       ABI::Windows::Devices::Sensors::ILightSensorStatics,
+@@ -647,21 +723,57 @@ TEST_F(PlatformSensorReaderTestWinrt, SensorTimestampConversion) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
++  // Instead of using CreateAndInitializeSensor(), for simplicity and for
++  // better control over |light_sensor|'s lifetime we invert things and create
++  // the object in the main task runner and invoke StartSensor() from another
++  // one. The effect on the Reader is the same -- the calls are still made from
++  // different task runners.
++  auto light_sensor = std::make_unique<CustomLightSensor>();
++  light_sensor->InitForTesting(base::BindLambdaForTesting(
+       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  ASSERT_TRUE(light_sensor->Initialize());
++
++  base::RunLoop run_loop;
++  base::ThreadPool::PostTaskAndReply(
++      FROM_HERE, base::BindLambdaForTesting([&]() {
++        ASSERT_TRUE(light_sensor->StartSensor(
++            PlatformSensorConfiguration(kExpectedReportFrequencySet)));
++      }),
++      run_loop.QuitClosure());
++  run_loop.Run();
++
++  // The idea here is to rely on the fact that TriggerFakeSensorReading() is
++  // asynchronous: we call it while it has a valid handler, it schedules a
++  // task, we destroy the handler object synchronoustly and then it Invoke()s
++  // the callback, which should never reach
++  // CustomLightSensor::OnReadingChangedCallback().
++  Microsoft::WRL::ComPtr<ABI::Windows::Devices::Sensors::ILightSensorReading>
++      reading = Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(
++          ABI::Windows::Foundation::DateTime{}, 0.0f);
++  fake_sensor->TriggerFakeSensorReading(reading);
++  light_sensor.reset();
++  task_environment_.RunUntilIdle();
++}
+ 
+-  auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
++// Tests that PlatformSensorReaderWinrtBase converts the timestamp correctly
++TEST_F(PlatformSensorReaderTestWinrt, SensorTimestampConversion) {
++  static constexpr double expectedTimestampDeltaSecs = 19.0;
+ 
+-  double lastReportedTimestamp = 0.0;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke([&](const SensorReading& reading) {
+-        lastReportedTimestamp = reading.als.timestamp;
+-        EXPECT_EQ(reading.als.value, 0.0f);
+-      }));
++  auto fake_sensor_factory = Microsoft::WRL::Make<FakeSensorFactoryWinrt<
++      ABI::Windows::Devices::Sensors::ILightSensorStatics,
++      ABI::Windows::Devices::Sensors::ILightSensor,
++      ABI::Windows::Devices::Sensors::LightSensor,
++      ABI::Windows::Devices::Sensors::ILightSensorReading,
++      ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs,
++      ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
++  auto fake_sensor = fake_sensor_factory->fake_sensor_;
++
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
++  auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+@@ -672,18 +784,35 @@ TEST_F(PlatformSensorReaderTestWinrt, SensorTimestampConversion) {
+   Microsoft::WRL::ComPtr<ABI::Windows::Devices::Sensors::ILightSensorReading>
+       reading = Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(
+           ABI::Windows::Foundation::DateTime{}, 0.0f);
+-  fake_sensor->TriggerFakeSensorReading(reading);
+-  EXPECT_EQ(lastReportedTimestamp, 0);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(reading.als.timestamp, 0.0);
++          EXPECT_EQ(reading.als.value, 0.0f);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
++  // Verify the reported time stamp has ticked forward
++  // expectedTimestampDeltaSecs
+   auto second_timestamp =
+       base::Seconds(expectedTimestampDeltaSecs).ToWinrtDateTime();
+   reading =
+       Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(second_timestamp, 0.0f);
+-  fake_sensor->TriggerFakeSensorReading(reading);
+-
+-  // Verify the reported time stamp has ticked forward
+-  // expectedTimestampDeltaSecs
+-  EXPECT_EQ(lastReportedTimestamp, expectedTimestampDeltaSecs);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(reading.als.timestamp, expectedTimestampDeltaSecs);
++          EXPECT_EQ(reading.als.value, 0.0f);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ }
+ 
+ // Tests that PlatformSensorReaderWinrtBase starts and stops the
+@@ -698,11 +827,9 @@ TEST_F(PlatformSensorReaderTestWinrt, StartStopSensorCallbacks) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+@@ -732,17 +859,19 @@ TEST_F(PlatformSensorReaderTestWinrt, StartWithoutStopSensorCallbacks) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+   EXPECT_TRUE(fake_sensor->IsSensorStarted());
+ 
++  // *sensor is deleted in |com_sta_task_runner_|, so we need to wait for it to
++  // happen asynchronously.
+   sensor.reset();
++  task_environment_.RunUntilIdle();
++
+   EXPECT_FALSE(fake_sensor->IsSensorStarted());
+ }
+ 
+@@ -758,11 +887,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedSensorStart) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   fake_sensor->SetPutReportIntervalReturnCode(E_FAIL);
+ 
+@@ -787,11 +914,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedSensorStop) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+@@ -813,11 +938,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedLightSensorSampleParse) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+ 
+@@ -832,12 +955,17 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedLightSensorSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0.0f);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+   reading->SetGetTimestampReturnCode(S_OK);
+   reading->SetGetIlluminanceInLuxReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ // Tests that PlatformSensorReaderWinrtLightSensor notifies the client
+@@ -854,19 +982,11 @@ TEST_F(PlatformSensorReaderTestWinrt, SensorClientNotification) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(expected_lux, reading.als.value);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+@@ -874,8 +994,16 @@ TEST_F(PlatformSensorReaderTestWinrt, SensorClientNotification) {
+ 
+   auto reading = Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_lux);
+-  fake_sensor->TriggerFakeSensorReading(reading);
+-
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(expected_lux, reading.als.value);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+   sensor->StopSensor();
+ }
+ 
+@@ -896,30 +1024,31 @@ TEST_F(PlatformSensorReaderTestWinrt, CheckAccelerometerReadingConversion) {
+       Microsoft::WRL::Make<FakeAccelerometerSensorWinrt>());
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtAccelerometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(-expected_x * base::kMeanGravityDouble, reading.accel.x);
+-        EXPECT_EQ(-expected_y * base::kMeanGravityDouble, reading.accel.y);
+-        EXPECT_EQ(-expected_z * base::kMeanGravityDouble, reading.accel.z);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
+ 
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+-
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
++
+   auto reading = Microsoft::WRL::Make<FakeAccelerometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_x, expected_y, expected_z);
+-  fake_sensor->TriggerFakeSensorReading(reading);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(-expected_x * base::kMeanGravityDouble, reading.accel.x);
++          EXPECT_EQ(-expected_y * base::kMeanGravityDouble, reading.accel.y);
++          EXPECT_EQ(-expected_z * base::kMeanGravityDouble, reading.accel.z);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
+   sensor->StopSensor();
+ }
+@@ -937,13 +1066,10 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedAccelerometerSampleParse) {
+       Microsoft::WRL::Make<FakeAccelerometerSensorWinrt>());
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtAccelerometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+@@ -954,6 +1080,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedAccelerometerSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeAccelerometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0, 0, 0);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+@@ -968,6 +1097,8 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedAccelerometerSampleParse) {
+   reading->SetGetYReturnCode(S_OK);
+   reading->SetGetZReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ // Tests if PlatformSensorReaderWinrtGyrometer correctly converts sensor
+@@ -986,27 +1117,30 @@ TEST_F(PlatformSensorReaderTestWinrt, CheckGyrometerReadingConversion) {
+       ABI::Windows::Devices::Sensors::GyrometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtGyrometer>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(gfx::DegToRad(expected_x), reading.gyro.x);
+-        EXPECT_EQ(gfx::DegToRad(expected_y), reading.gyro.y);
+-        EXPECT_EQ(gfx::DegToRad(expected_z), reading.gyro.z);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   auto reading = Microsoft::WRL::Make<FakeGyrometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_x, expected_y, expected_z);
+-  fake_sensor->TriggerFakeSensorReading(reading);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(gfx::DegToRad(expected_x), reading.gyro.x);
++          EXPECT_EQ(gfx::DegToRad(expected_y), reading.gyro.y);
++          EXPECT_EQ(gfx::DegToRad(expected_z), reading.gyro.z);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
+   sensor->StopSensor();
+ }
+@@ -1023,11 +1157,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedGyrometerSampleParse) {
+       ABI::Windows::Devices::Sensors::GyrometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtGyrometer>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+@@ -1038,6 +1170,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedGyrometerSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeGyrometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0, 0, 0);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+@@ -1052,6 +1187,8 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedGyrometerSampleParse) {
+   reading->SetGetYReturnCode(S_OK);
+   reading->SetGetZReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ // Tests if PlatformSensorReaderWinrtMagnetometer correctly converts sensor
+@@ -1070,27 +1207,31 @@ TEST_F(PlatformSensorReaderTestWinrt, CheckMagnetometerReadingConversion) {
+       ABI::Windows::Devices::Sensors::MagnetometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtMagnetometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(expected_x, reading.magn.x);
+-        EXPECT_EQ(expected_y, reading.magn.y);
+-        EXPECT_EQ(expected_z, reading.magn.z);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   auto reading = Microsoft::WRL::Make<FakeMagnetometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_x, expected_y, expected_z);
+-  fake_sensor->TriggerFakeSensorReading(reading);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(expected_x, reading.magn.x);
++          EXPECT_EQ(expected_y, reading.magn.y);
++          EXPECT_EQ(expected_z, reading.magn.z);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
+   sensor->StopSensor();
+ }
+@@ -1107,11 +1248,10 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedMagnetometerSampleParse) {
+       ABI::Windows::Devices::Sensors::MagnetometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtMagnetometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+@@ -1122,6 +1262,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedMagnetometerSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeMagnetometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0, 0, 0);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+@@ -1136,6 +1279,8 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedMagnetometerSampleParse) {
+   reading->SetGetYReturnCode(S_OK);
+   reading->SetGetZReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ // Tests if PlatformSensorReaderWinrtAbsOrientationEulerAngles correctly
+@@ -1154,28 +1299,30 @@ TEST_F(PlatformSensorReaderTestWinrt, CheckInclinometerReadingConversion) {
+       ABI::Windows::Devices::Sensors::InclinometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationEulerAngles>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(expected_x, reading.orientation_euler.x);
+-        EXPECT_EQ(expected_y, reading.orientation_euler.y);
+-        EXPECT_EQ(expected_z, reading.orientation_euler.z);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   auto reading = Microsoft::WRL::Make<FakeInclinometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_x, expected_y, expected_z);
+-  fake_sensor->TriggerFakeSensorReading(reading);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(expected_x, reading.orientation_euler.x);
++          EXPECT_EQ(expected_y, reading.orientation_euler.y);
++          EXPECT_EQ(expected_z, reading.orientation_euler.z);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
+   sensor->StopSensor();
+ }
+@@ -1192,12 +1339,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedInclinometerSampleParse) {
+       ABI::Windows::Devices::Sensors::InclinometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationEulerAngles>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+@@ -1208,6 +1352,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedInclinometerSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeInclinometerReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0, 0, 0);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+@@ -1222,6 +1369,8 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedInclinometerSampleParse) {
+   reading->SetGetYReturnCode(S_OK);
+   reading->SetGetZReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ // Tests if PlatformSensorReaderWinrtAbsOrientationQuaternion correctly
+@@ -1242,32 +1391,32 @@ TEST_F(PlatformSensorReaderTestWinrt, CheckOrientationSensorReadingConversion) {
+           OrientationSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationQuaternion>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillOnce(testing::Invoke([&](const SensorReading& reading) {
+-        EXPECT_EQ(expected_w, reading.orientation_quat.w);
+-        EXPECT_EQ(expected_x, reading.orientation_quat.x);
+-        EXPECT_EQ(expected_y, reading.orientation_quat.y);
+-        EXPECT_EQ(expected_z, reading.orientation_quat.z);
+-      }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   auto reading = Microsoft::WRL::Make<FakeOrientationSensorReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, expected_w, expected_x, expected_y,
+       expected_z);
+-  fake_sensor->TriggerFakeSensorReading(reading);
++  {
++    base::RunLoop run_loop;
++    EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++        .WillOnce(testing::Invoke([&](const SensorReading& reading) {
++          EXPECT_EQ(expected_w, reading.orientation_quat.w);
++          EXPECT_EQ(expected_x, reading.orientation_quat.x);
++          EXPECT_EQ(expected_y, reading.orientation_quat.y);
++          EXPECT_EQ(expected_z, reading.orientation_quat.z);
++          run_loop.Quit();
++        }));
++    fake_sensor->TriggerFakeSensorReading(reading);
++    run_loop.Run();
++  }
+ 
+   sensor->StopSensor();
+ }
+@@ -1285,14 +1434,9 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedOrientationSampleParse) {
+           OrientationSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationQuaternion>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+   sensor->SetClient(mock_client.get());
+@@ -1303,12 +1447,17 @@ TEST_F(PlatformSensorReaderTestWinrt, FailedOrientationSampleParse) {
+   auto reading = Microsoft::WRL::Make<FakeOrientationSensorReadingWinrt>(
+       ABI::Windows::Foundation::DateTime{}, 0, 0, 0, 0);
+ 
++  // We cannot use a base::RunLoop in the checks below because we are expecting
++  // that MockClient::OnReadingUpdate() does _not_ get called.
++
+   reading->SetGetTimestampReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
+ 
+   reading->SetGetTimestampReturnCode(S_OK);
+   reading->SetGetQuaternionReturnCode(E_FAIL);
+   fake_sensor->TriggerFakeSensorReading(reading);
++
++  task_environment_.RunUntilIdle();
+ }
+ 
+ TEST_F(PlatformSensorReaderTestWinrt, LightSensorThresholding) {
+@@ -1321,29 +1470,30 @@ TEST_F(PlatformSensorReaderTestWinrt, LightSensorThresholding) {
+       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtLightSensor>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   float last_sent_lux = 1.0f;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto reading = Microsoft::WRL::Make<FakeLightSensorReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, last_sent_lux);
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+@@ -1359,10 +1509,6 @@ TEST_F(PlatformSensorReaderTestWinrt, LightSensorThresholding) {
+       PlatformSensorReaderWinrtLightSensor::kLuxPercentThreshold * 0.6f;
+   threshold_helper(true);
+ 
+-  // Expect callback, threshold has been met exactly
+-  last_sent_lux += PlatformSensorReaderWinrtLightSensor::kLuxPercentThreshold;
+-  threshold_helper(true);
+-
+   sensor->StopSensor();
+ }
+ 
+@@ -1377,22 +1523,14 @@ TEST_F(PlatformSensorReaderTestWinrt, AccelerometerThresholding) {
+       Microsoft::WRL::Make<FakeAccelerometerSensorWinrt>());
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtAccelerometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+@@ -1400,40 +1538,40 @@ TEST_F(PlatformSensorReaderTestWinrt, AccelerometerThresholding) {
+   double last_sent_y = 2.0f;
+   double last_sent_z = 3.0f;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto reading = Microsoft::WRL::Make<FakeAccelerometerReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, last_sent_x, last_sent_y,
+         last_sent_z);
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+   threshold_helper(true);
+ 
+-  // No callback, threshold has not been met
++  // For each axis, increase its value by an amount lower than the threshold so
++  // that no callback is invoked, then meet the threshold and do expect a
++  // callback.
+   last_sent_x += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.5f;
+   threshold_helper(false);
+-  last_sent_y += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.5f;
+-  threshold_helper(false);
+-  last_sent_z += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.5f;
+-  threshold_helper(false);
+-
+-  // Expect callback, threshold has been met since last reported sample
+   last_sent_x += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_y += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_y += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_z += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_z += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold * 0.6f;
+   threshold_helper(true);
+ 
+-  // Expect callback, threshold has been met exactly
+-  last_sent_x += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold;
+-  threshold_helper(true);
+-  last_sent_y += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold;
+-  threshold_helper(true);
+-  last_sent_z += PlatformSensorReaderWinrtAccelerometer::kAxisThreshold;
+-  threshold_helper(true);
+-
+   sensor->StopSensor();
+ }
+ 
+@@ -1447,20 +1585,13 @@ TEST_F(PlatformSensorReaderTestWinrt, GyrometerThresholding) {
+       ABI::Windows::Devices::Sensors::GyrometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<PlatformSensorReaderWinrtGyrometer>(
++      fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+@@ -1468,40 +1599,40 @@ TEST_F(PlatformSensorReaderTestWinrt, GyrometerThresholding) {
+   double last_sent_y = 4.0f;
+   double last_sent_z = 5.0f;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto reading = Microsoft::WRL::Make<FakeGyrometerReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, last_sent_x, last_sent_y,
+         last_sent_z);
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+   threshold_helper(true);
+ 
+-  // No callback, threshold has not been met
++  // For each axis, increase its value by an amount lower than the threshold so
++  // that no callback is invoked, then meet the threshold and do expect a
++  // callback.
+   last_sent_x += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.5f;
+   threshold_helper(false);
+-  last_sent_y += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.5f;
+-  threshold_helper(false);
+-  last_sent_z += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.5f;
+-  threshold_helper(false);
+-
+-  // Expect callback, threshold has been met since last reported sample
+   last_sent_x += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_y += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_y += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_z += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_z += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold * 0.6f;
+   threshold_helper(true);
+ 
+-  // Expect callback, threshold has been met exactly
+-  last_sent_x += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold;
+-  threshold_helper(true);
+-  last_sent_y += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold;
+-  threshold_helper(true);
+-  last_sent_z += PlatformSensorReaderWinrtGyrometer::kDegreeThreshold;
+-  threshold_helper(true);
+-
+   sensor->StopSensor();
+ }
+ 
+@@ -1515,20 +1646,14 @@ TEST_F(PlatformSensorReaderTestWinrt, MagnetometerThresholding) {
+       ABI::Windows::Devices::Sensors::MagnetometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor =
++      CreateAndInitializeSensor<PlatformSensorReaderWinrtMagnetometer>(
++          fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+@@ -1536,46 +1661,46 @@ TEST_F(PlatformSensorReaderTestWinrt, MagnetometerThresholding) {
+   double last_sent_y = 4.0f;
+   double last_sent_z = 5.0f;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto reading = Microsoft::WRL::Make<FakeMagnetometerReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, last_sent_x, last_sent_y,
+         last_sent_z);
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+   threshold_helper(true);
+ 
+-  // No callback, threshold has not been met
++  // For each axis, increase its value by an amount lower than the threshold so
++  // that no callback is invoked, then meet the threshold and do expect a
++  // callback.
+   last_sent_x +=
+       PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.5f;
+   threshold_helper(false);
+-  last_sent_y +=
+-      PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.5f;
+-  threshold_helper(false);
+-  last_sent_z +=
+-      PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.5f;
+-  threshold_helper(false);
+-
+-  // Expect callback, threshold has been met since last reported sample
+   last_sent_x +=
+       PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_y +=
++      PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_y +=
+       PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.6f;
+   threshold_helper(true);
++  last_sent_z +=
++      PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.5f;
++  threshold_helper(false);
+   last_sent_z +=
+       PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold * 0.6f;
+   threshold_helper(true);
+ 
+-  // Expect callback, threshold has been met exactly
+-  last_sent_x += PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold;
+-  threshold_helper(true);
+-  last_sent_y += PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold;
+-  threshold_helper(true);
+-  last_sent_z += PlatformSensorReaderWinrtMagnetometer::kMicroteslaThreshold;
+-  threshold_helper(true);
+-
+   sensor->StopSensor();
+ }
+ 
+@@ -1589,21 +1714,13 @@ TEST_F(PlatformSensorReaderTestWinrt, AbsOrientationEulerThresholding) {
+       ABI::Windows::Devices::Sensors::InclinometerReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
+-          -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationEulerAngles>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+@@ -1611,53 +1728,50 @@ TEST_F(PlatformSensorReaderTestWinrt, AbsOrientationEulerThresholding) {
+   double last_sent_y = 4.0f;
+   double last_sent_z = 5.0f;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto reading = Microsoft::WRL::Make<FakeInclinometerReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, last_sent_x, last_sent_y,
+         last_sent_z);
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+   threshold_helper(true);
+ 
+-  // No callback, threshold has not been met
++  // For each axis, increase its value by an amount lower than the threshold so
++  // that no callback is invoked, then meet the threshold and do expect a
++  // callback.
+   last_sent_x +=
+       PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+       0.5f;
+   threshold_helper(false);
+-  last_sent_y +=
+-      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+-      0.5f;
+-  threshold_helper(false);
+-  last_sent_z +=
+-      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+-      0.5f;
+-  threshold_helper(false);
+-
+-  // Expect callback, threshold has been met since last reported sample
+   last_sent_x +=
+       PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+       0.6f;
+   threshold_helper(true);
++  last_sent_y +=
++      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
++      0.5f;
++  threshold_helper(false);
+   last_sent_y +=
+       PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+       0.6f;
+   threshold_helper(true);
+   last_sent_z +=
+       PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
+-      0.6f;
+-  threshold_helper(true);
+-
+-  // Expect callback, threshold has been met exactly
+-  last_sent_x +=
+-      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold;
+-  threshold_helper(true);
+-  last_sent_y +=
+-      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold;
+-  threshold_helper(true);
++      0.5f;
++  threshold_helper(false);
+   last_sent_z +=
+-      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold;
++      PlatformSensorReaderWinrtAbsOrientationEulerAngles::kDegreeThreshold *
++      0.6f;
+   threshold_helper(true);
+ 
+   sensor->StopSensor();
+@@ -1674,34 +1788,32 @@ TEST_F(PlatformSensorReaderTestWinrt, AbsOrientationQuatThresholding) {
+           OrientationSensorReadingChangedEventArgs>>();
+   auto fake_sensor = fake_sensor_factory->fake_sensor_;
+ 
+-  auto sensor =
+-      std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
+-  sensor->InitForTesting(base::BindLambdaForTesting(
+-      [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
+-              sensor_factory) -> HRESULT {
+-        return fake_sensor_factory.CopyTo(sensor_factory);
+-      }));
+-  EXPECT_TRUE(sensor->Initialize());
++  auto sensor = CreateAndInitializeSensor<
++      PlatformSensorReaderWinrtAbsOrientationQuaternion>(fake_sensor_factory);
++  ASSERT_TRUE(sensor);
+ 
+   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
+-
+-  bool expected_callback = false;
+-  EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
+-      .WillRepeatedly(testing::Invoke(
+-          [&](const SensorReading&) { EXPECT_TRUE(expected_callback); }));
+-
+   sensor->SetClient(mock_client.get());
++
+   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
+   EXPECT_TRUE(sensor->StartSensor(sensor_config));
+ 
+   double last_sent_rad = 1.0;
+   auto threshold_helper = [&](bool expect_callback) {
+-    expected_callback = expect_callback;
+     auto quat = gfx::Quaternion(gfx::Vector3dF(1.0, 0, 0), last_sent_rad);
+     auto reading = Microsoft::WRL::Make<FakeOrientationSensorReadingWinrt>(
+         ABI::Windows::Foundation::DateTime{}, quat.w(), quat.x(), quat.y(),
+         quat.z());
+-    fake_sensor->TriggerFakeSensorReading(reading);
++    if (expect_callback) {
++      base::RunLoop run_loop;
++      EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
++          .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
++      fake_sensor->TriggerFakeSensorReading(reading);
++      run_loop.Run();
++    } else {
++      fake_sensor->TriggerFakeSensorReading(reading);
++      task_environment_.RunUntilIdle();
++    }
+   };
+ 
+   // Expect callback, first sample
+@@ -1719,11 +1831,6 @@ TEST_F(PlatformSensorReaderTestWinrt, AbsOrientationQuatThresholding) {
+       0.6f;
+   threshold_helper(true);
+ 
+-  // Expect callback, threshold has been met exactly
+-  last_sent_rad +=
+-      PlatformSensorReaderWinrtAbsOrientationQuaternion::kRadianThreshold;
+-  threshold_helper(true);
+-
+   sensor->StopSensor();
+ }
+ 
+diff --git a/services/device/generic_sensor/platform_sensor_win.cc b/services/device/generic_sensor/platform_sensor_win.cc
+index 3ee3c1fa86a80475dabe78ba440544767b2fce3a..e9a78687250f5214c99f03b62d31a7ff53211521 100644
+--- a/services/device/generic_sensor/platform_sensor_win.cc
++++ b/services/device/generic_sensor/platform_sensor_win.cc
+@@ -43,6 +43,8 @@ double PlatformSensorWin::GetMaximumSupportedFrequency() {
+ }
+ 
+ void PlatformSensorWin::OnReadingUpdated(const SensorReading& reading) {
++  // This function is normally called from |sensor_thread_runner_|, except on
++  // PlatformSensorAndProviderTestWin.
+   UpdateSharedBufferAndNotifyClients(reading);
+ }
+ 
+@@ -75,6 +77,7 @@ bool PlatformSensorWin::CheckSensorConfiguration(
+ }
+ 
+ PlatformSensorWin::~PlatformSensorWin() {
++  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
+   sensor_reader_->SetClient(nullptr);
+   sensor_thread_runner_->DeleteSoon(FROM_HERE, sensor_reader_.get());
+ }

+ 4 - 1
patches/config.json

@@ -11,5 +11,8 @@
   { "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" },
   { "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" },
   { "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
-  { "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }
+  { "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" },
+  { "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" },
+  { "patch_dir": "src/electron/patches/libvpx", "repo": "src/third_party/libvpx/source/libvpx" },
+  { "patch_dir": "src/electron/patches/dxc", "repo": "src/third_party/dawn/third_party/dxc" }
 ]

+ 1 - 0
patches/dxc/.patches

@@ -0,0 +1 @@
+fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch

+ 36 - 0
patches/dxc/fix_hlmatrixlowerpass_leaving_call_to_dangling_functionval.patch

@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Antonio Maiorano <[email protected]>
+Date: Wed, 20 Mar 2024 17:15:40 -0400
+Subject: Fix HLMatrixLowerPass leaving call to dangling FunctionVal
+
+When lowering an hl.cast, when the operand was an undef matrix, the pass would insert a call to a mat2vec stub, but since the undef value is not
+an alloca, it never gets handled, and the call to the temporary stub
+remains. Since the stub FunctionVal gets deleted, when the instruction
+is accessed in a future pass, it reads a dangling pointer.
+
+The fix is to handle undef similarly to how constant 0 is handled, and
+to return an undef vector from lowerHLCast.
+
+Bug: chromium:328958020
+Change-Id: Id31e3aa326d9cb9f03ea97139f14dc5292cd6f7b
+Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5383595
+Reviewed-by: Ben Clayton <[email protected]>
+Reviewed-by: David Neto <[email protected]>
+Reviewed-by: Kenneth Russell <[email protected]>
+
+diff --git a/lib/HLSL/HLMatrixLowerPass.cpp b/lib/HLSL/HLMatrixLowerPass.cpp
+index ca8a8a33fdb475542b3705f3f7a8b8af2554a21f..d5959eb9335465f67d8e7ef7d7ab4eb720274226 100644
+--- a/lib/HLSL/HLMatrixLowerPass.cpp
++++ b/lib/HLSL/HLMatrixLowerPass.cpp
+@@ -421,6 +421,11 @@ Value *HLMatrixLowerPass::getLoweredByValOperand(Value *Val,
+   if (isa<ConstantAggregateZero>(Val))
+     return ConstantAggregateZero::get(LoweredTy);
+ 
++  // Lower undef mat as undef vec
++  if (isa<UndefValue>(Val)) {
++      return UndefValue::get(LoweredTy);
++  }
++
+   // Return a mat-to-vec translation stub
+   FunctionType *TranslationStubTy =
+       FunctionType::get(LoweredTy, {Ty}, /* isVarArg */ false);

+ 2 - 0
patches/libvpx/.patches

@@ -0,0 +1,2 @@
+fix_to_buffer_alloc_for_vp9_bitstream_worker_data.patch
+vp9_fix_to_integer_overflow_test.patch

+ 190 - 0
patches/libvpx/fix_to_buffer_alloc_for_vp9_bitstream_worker_data.patch

@@ -0,0 +1,190 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Marco Paniconi <[email protected]>
+Date: Wed, 13 Mar 2024 10:58:17 -0700
+Subject: Fix to buffer alloc for vp9_bitstream_worker_data
+
+The code was using the bitstream_worker_data when it
+wasn't allocated for big enough size. This is because
+the existing condition was to only re-alloc the
+bitstream_worker_data when current dest_size was larger
+than the current frame_size. But under resolution change
+where frame_size is increased, beyond the current dest_size,
+we need to allow re-alloc to the new size.
+
+The existing condition to re-alloc when dest_size is
+larger than frame_size (which is not required) is kept
+for now.
+
+Also increase the dest_size to account for image format.
+
+Added tests, for both ROW_MT=0 and 1, that reproduce
+the failures in the bugs below.
+
+Note: this issue only affects the REALTIME encoding path.
+
+Bug: b/329088759, b/329674887, b/329179808
+
+Change-Id: Icd65dbc5317120304d803f648d4bd9405710db6f
+(cherry picked from commit c29e63728316486082dd6083c2062434b441b77d)
+
+diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
+index d838b4338550619d131567a0fc8b5b22a719ba96..e1702e4c4e83c16b4043cf6da50829344af6bb6a 100644
+--- a/test/encode_api_test.cc
++++ b/test/encode_api_test.cc
+@@ -676,7 +676,7 @@ vpx_image_t *CreateImage(const unsigned int width, const unsigned int height) {
+ // Emulates the WebCodecs VideoEncoder interface.
+ class VP9Encoder {
+  public:
+-  explicit VP9Encoder(int speed) : speed_(speed) {}
++  explicit VP9Encoder(int speed) : speed_(speed), row_mt_(0) {}
+   ~VP9Encoder();
+ 
+   void Configure(unsigned int threads, unsigned int width, unsigned int height,
+@@ -685,6 +685,7 @@ class VP9Encoder {
+ 
+  private:
+   const int speed_;
++  const unsigned int row_mt_;
+   bool initialized_ = false;
+   vpx_codec_enc_cfg_t cfg_;
+   vpx_codec_ctx_t enc_;
+@@ -719,6 +720,7 @@ void VP9Encoder::Configure(unsigned int threads, unsigned int width,
+     cfg_.rc_max_quantizer = 58;
+     ASSERT_EQ(vpx_codec_enc_init(&enc_, iface, &cfg_, 0), VPX_CODEC_OK);
+     ASSERT_EQ(vpx_codec_control(&enc_, VP8E_SET_CPUUSED, speed_), VPX_CODEC_OK);
++    ASSERT_EQ(vpx_codec_control(&enc_, VP9E_SET_ROW_MT, row_mt_), VPX_CODEC_OK);
+     initialized_ = true;
+     return;
+   }
+@@ -1078,6 +1080,92 @@ TEST(EncodeAPI, Buganizer317105128) {
+   encoder.Configure(16, 1920, 1, VPX_CBR, VPX_DL_REALTIME);
+ }
+ 
++TEST(EncodeAPI, Buganizer329088759RowMT0) {
++  VP9Encoder encoder(8, 0, VPX_BITS_8, VPX_IMG_FMT_I444);
++  encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/0, /*width=*/1686, /*height=*/1, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/0, /*width=*/1482, /*height=*/113, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/0, /*width=*/881, /*height=*/59, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
++                    VPX_DL_REALTIME);
++}
++
++TEST(EncodeAPI, Buganizer329088759RowMT1) {
++  VP9Encoder encoder(8, 1, VPX_BITS_8, VPX_IMG_FMT_I444);
++  encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Encode(/*key_frame=*/false);
++  // Needs to set threads to non-zero to repro the issue.
++  encoder.Configure(/*threads=*/2, /*width=*/1686, /*height=*/1, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/2, /*width=*/1482, /*height=*/113, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/2, /*width=*/881, /*height=*/59, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
++                    VPX_DL_REALTIME);
++}
++
++#if CONFIG_VP9_HIGHBITDEPTH
++TEST(EncodeAPI, Buganizer329674887RowMT0BitDepth12) {
++  VP9Encoder encoder(8, 0, VPX_BITS_12, VPX_IMG_FMT_I444);
++  encoder.Configure(/*threads=*/2, /*width=*/1030, /*height=*/583, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/0, /*width=*/1030, /*height=*/1, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/0, /*width=*/548, /*height=*/322, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/16, /*width=*/24, /*height=*/583, VPX_CBR,
++                    VPX_DL_GOOD_QUALITY);
++}
++
++TEST(EncodeAPI, Buganizer329179808RowMT0BitDepth10) {
++  VP9Encoder encoder(4, 0, VPX_BITS_10, VPX_IMG_FMT_I444);
++  encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++}
++
++TEST(EncodeAPI, Buganizer329179808RowMT1BitDepth10) {
++  VP9Encoder encoder(4, 1, VPX_BITS_10, VPX_IMG_FMT_I444);
++  encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/true);
++  encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++  encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
++                    VPX_DL_REALTIME);
++  encoder.Encode(/*key_frame=*/false);
++}
++#endif
++
+ #endif  // CONFIG_VP9_ENCODER
+ 
+ }  // namespace
+diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
+index ca56d14aa1e31e4791f8772316e449b771aae4fc..88a031e5fc1cf7b6cf0a441664dbbc62006c1790 100644
+--- a/vp9/encoder/vp9_bitstream.c
++++ b/vp9/encoder/vp9_bitstream.c
+@@ -962,6 +962,14 @@ void vp9_bitstream_encode_tiles_buffer_dealloc(VP9_COMP *const cpi) {
+   }
+ }
+ 
++static int encode_tiles_buffer_alloc_size(VP9_COMP *const cpi) {
++  VP9_COMMON *const cm = &cpi->common;
++  const int image_bps =
++      (8 + 2 * (8 >> (cm->subsampling_x + cm->subsampling_y))) *
++      (1 + (cm->bit_depth > 8));
++  return cpi->oxcf.width * cpi->oxcf.height * image_bps / 8;
++}
++
+ static void encode_tiles_buffer_alloc(VP9_COMP *const cpi) {
+   VP9_COMMON *const cm = &cpi->common;
+   int i;
+@@ -972,7 +980,7 @@ static void encode_tiles_buffer_alloc(VP9_COMP *const cpi) {
+   memset(cpi->vp9_bitstream_worker_data, 0, worker_data_size);
+   for (i = 1; i < cpi->num_workers; ++i) {
+     cpi->vp9_bitstream_worker_data[i].dest_size =
+-        cpi->oxcf.width * cpi->oxcf.height;
++        encode_tiles_buffer_alloc_size(cpi);
+     CHECK_MEM_ERROR(&cm->error, cpi->vp9_bitstream_worker_data[i].dest,
+                     vpx_malloc(cpi->vp9_bitstream_worker_data[i].dest_size));
+   }
+@@ -987,8 +995,8 @@ static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr) {
+   int tile_col = 0;
+ 
+   if (!cpi->vp9_bitstream_worker_data ||
+-      cpi->vp9_bitstream_worker_data[1].dest_size >
+-          (cpi->oxcf.width * cpi->oxcf.height)) {
++      cpi->vp9_bitstream_worker_data[1].dest_size !=
++          encode_tiles_buffer_alloc_size(cpi)) {
+     vp9_bitstream_encode_tiles_buffer_dealloc(cpi);
+     encode_tiles_buffer_alloc(cpi);
+   }

+ 28 - 0
patches/libvpx/vp9_fix_to_integer_overflow_test.patch

@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Marco Paniconi <[email protected]>
+Date: Sat, 16 Mar 2024 10:39:28 -0700
+Subject: vp9: fix to integer overflow test
+
+failure for the 16k test: issue introduced
+in: c29e637283
+
+Bug: b/329088759, b/329674887, b/329179808
+
+Change-Id: I88e8a36b7f13223997c3006c84aec9cfa48c0bcf
+(cherry picked from commit 19832b1702d5b0adf616a0e080abd5207c8445b5)
+
+diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
+index 88a031e5fc1cf7b6cf0a441664dbbc62006c1790..d3c029da4bacafdb19aa6bfb9865ccbf2db33393 100644
+--- a/vp9/encoder/vp9_bitstream.c
++++ b/vp9/encoder/vp9_bitstream.c
+@@ -967,7 +967,9 @@ static int encode_tiles_buffer_alloc_size(VP9_COMP *const cpi) {
+   const int image_bps =
+       (8 + 2 * (8 >> (cm->subsampling_x + cm->subsampling_y))) *
+       (1 + (cm->bit_depth > 8));
+-  return cpi->oxcf.width * cpi->oxcf.height * image_bps / 8;
++  const int64_t size =
++      (int64_t)cpi->oxcf.width * cpi->oxcf.height * image_bps / 8;
++  return (int)size;
+ }
+ 
+ static void encode_tiles_buffer_alloc(VP9_COMP *const cpi) {

+ 1 - 0
patches/v8/.patches

@@ -1,2 +1,3 @@
 chore_allow_customizing_microtask_policy_per_context.patch
 deps_add_v8_object_setinternalfieldfornodecore.patch
+merged_wasm_check_for_type-definition_count_limit.patch

+ 38 - 0
patches/v8/merged_wasm_check_for_type-definition_count_limit.patch

@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Manos Koukoutos <[email protected]>
+Date: Thu, 21 Mar 2024 11:38:08 +0100
+Subject: Merged: [wasm] Check for type-definition count limit
+
+(cherry picked from commit b852ad701db21d6db5b34e66f4ec1cdccd2ec4d4)
+
+Bug: chromium:330575498
+Change-Id: I395f0ed6d823b7d1e139da6551486e3627d65724
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5378419
+Commit-Queue: Jakob Kummerow <[email protected]>
+Reviewed-by: Jakob Kummerow <[email protected]>
+Auto-Submit: Manos Koukoutos <[email protected]>
+Cr-Original-Commit-Position: refs/heads/main@{#92941}
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5380190
+Reviewed-by: Francis McCabe <[email protected]>
+Commit-Queue: Adam Klein <[email protected]>
+Reviewed-by: Adam Klein <[email protected]>
+Cr-Commit-Position: refs/branch-heads/12.2@{#50}
+Cr-Branched-From: 6eb5a9616aa6f8c705217aeb7c7ab8c037a2f676-refs/heads/12.2.281@{#1}
+Cr-Branched-From: 44cf56d850167c6988522f8981730462abc04bcc-refs/heads/main@{#91934}
+
+diff --git a/src/wasm/module-decoder-impl.h b/src/wasm/module-decoder-impl.h
+index a4c1f5991f0498eab922faa42f69b30b21b423f0..b56dda7afb6a355a998fff57ac14b3fc26c09b7a 100644
+--- a/src/wasm/module-decoder-impl.h
++++ b/src/wasm/module-decoder-impl.h
+@@ -690,6 +690,11 @@ class ModuleDecoderImpl : public Decoder {
+         }
+       } else {
+         if (tracer_) tracer_->TypeOffset(pc_offset());
++        if (initial_size + 1 > kV8MaxWasmTypes) {
++          errorf(pc(), "Type definition count exceeds maximum %zu",
++                 kV8MaxWasmTypes);
++          return;
++        }
+         // Similarly to above, we need to resize types for a group of size 1.
+         module_->types.resize(initial_size + 1);
+         module_->isorecursive_canonical_type_ids.resize(initial_size + 1);